【Threejs进阶教程-着色器篇】1. Shader入门(ShadertoyShader和ThreejsShader入门)

ThreejsShader入门

  • 关于本Shader教程
  • 认识Shader
    • Shader和Threejs的关系
    • WebGLShader
    • ThreejsShader
    • ShadertoyShader
    • 其他Shader
  • 再次劝退数学不好的人
  • 从ShaderToy开始
    • Shader的代码是强类型
    • glsl的类型,变量,内置函数,关键字
    • 关于uv
    • 基于UV的颜色处理
  • 最基本的ThreeJS Shader
    • ShaderMaterial介绍
    • 代码拆解
      • uniforms(参数集)(本篇不讲)
      • vertexShader(顶点着色器)(现阶段不讲)
      • fragmentShader(片元着色器)代码讲解
    • 现阶段的效果进阶
  • ThreejsShader和ShadertoyShader的巧妙使用
  • 本系列教程更新速度可能较慢,还请耐心等待

关于本Shader教程

  1. 本教程着重讲解Shadertoy的shader和Threejs的Shader,与原生WebGLShader略有不同,如果需要学习原生WebGL的shader,请参考《WebGL编程指南》
  2. 本人的shader水平也比较基础,文章中所写代码,不一定是最佳的代码,思路也不一定是最好的思路,所以一切本人的Shader教程下,所有的代码及思路以及学习建议均仅供参考,且目前本教程可能不适用于WebGPU,如果有大佬路过看到本人文章,觉得有可以指点之处,可以在下面留言,我们一起进步
  3. 数学水平不行的人,尤其是高中数学都及格不了的,不建议入坑Shader
  4. 本教程会在讲解片元着色器时,使用Shadertoy来编写demo,所以教程中会出现一部分Shadertoy的代码
  5. 本段内容将会出现在本人所有的【进阶教程-着色器篇】的文章中

认识Shader

能百度到的我这里就不废话了,自行百度 WebGL,OpenGL,OpenGL ES,GLSL,这些可以帮助你了解shader的历史和发展以及版本关系

Shader和Threejs的关系

shader是Threejs的底层,在前后关系上,Shader要更底层,Threejs的渲染器部分,主要基于Shader来开发

WebGLShader

最原始版本的Shader,在学习《WebGL编程指南》时会经常接触

ThreejsShader

ThreejsShader,特指 THREE.ShaderMaterial和THREE.RawShaderMaterial,这个是Threejs最核心的内容之一,基本上所有的特效物体,特效粒子,都可以使用Shader来制作,在threejs的ShaderMaterial中,内置了很多方便的常用的变量,提供给你访问,如果你不想使用Threejs内置的变量,那么用THREE.RawShaderMaterial即可

ShadertoyShader

基于Shadertoy网站的Shader,由Shadertoy网站提供了大量的内置变量,以编写片元着色器为主
(但是shadertoy上的大佬,早就不满足于只写片元着色器了,在里面加入了各种各样牛逼的写法,什么光线追踪,3d化的各种效果,还有人在里面做游戏的,也有人就纯靠代码写出来超级逼真的场景,比如说iq大佬,而且全部开源,是个非常适合学Shader的地方)

本系列教程,以ShadertoyShader和ThreejsShader为主,可能部分写法不太适用于其他的shader

其他Shader

cesium,babylon,pixi均内置了自己的shader系统,但是所有的shader,基本语法都是一样的,只有内置变量的区别,所以学会了原生Shader基本上可以通吃整个webgl圈子的shader

所以如果你想要学习原生的Shader,建议从《WebGL开发指南》开始学起

再次劝退数学不好的人

Shader难度很高,对数学能力要求很高,如果你已经做好了心理准备,那么我们接下来,就准备开始吧

从ShaderToy开始

ShaderToy的入门案例

但是,这里本人要改一下,改的更简单一点,方便入门
在这里插入图片描述

	void mainImage( out vec4 fragColor, in vec2 fragCoord ){vec2 uv = fragCoord/iResolution.xy;fragColor = vec4(uv.x,0.0,0.0,1.0);}

把这一段代码,替换到Shadertoy中,然后点击编辑窗左下角的播放键,即可得到左边的渐变红色效果

我们来对上述代码做一个分析

Shader的代码是强类型

很多人直接就反应了,这个代码根本看不懂,因为根本就不是 JS语言
首先,我们看到第一行,代码是==void mainImage( out vec4 fragColor, in vec2 fragCoord ) ==
有没有发现,这个代码很像是我们学习的C语言的HelloWorld

glsl是强类型语言,所以我们无论什么时候,都要遵循强类型语言的规则

现阶段,我们只需要死记硬背,第一行是Shadertoy必须要写的内容即可

然后我们开始分析第二行代码,vec2 uv = fragCoord/iResolution.xy;
这里声明了一个变量,vec2 uv

glsl的类型,变量,内置函数,关键字

这里本人就懒得手敲了,《WebGL编程指南》187页~215页,非常多,这里本人仅截图出来第一张,后面的请自行去群里下载电子书,或者买一本实体书来阅读
什么群?基本上所有的Threejs/WebGL的qq群文件里都有相关电子书,非常好找,随便加一个就行了

内置函数在 427~436页,内置函数表在后续的开发中会经常查阅,所以建议学习Shader的人自行购买一本实体书
还有,内置变量啊,内置函数啊,现阶段就看一遍就行了,知道哪些是关键字,避开就行了
在这里插入图片描述

实在懒得看书的就看我这里的解释吧。。。
这里仅介绍本篇教程中用到的变量和对象

vec2,其实是一个缩写,完整单词是Vector2,二维向量,这里的uv实际上就是一个二维向量,一个二维向量由 x,y两个数据构成

然后后面的 fragCoord/iResolution.xy,这里,现阶段不做讲解,只需要记住,shadertory第二行必须是这个就行了,后面在threejs的开发中,这一行也不会发生大的改变,如果你需要更详细的了解和学习Shadertoy,再去考虑研究 fragCoord和iResolution的作用,最终的计算结果,就是uv

注意:shadertoy,以及后续所有的Shader代码每一行结尾必须加分号!!!!!!!!

关于uv

uv这个概念,在前面介绍纹理篇已经简单介绍过了,所以还不懂uv概念的,回去补补课了

在Shadertoy中,已经通过内置的计算,把uv给你端上来了,但是shadertoy的uv和我们传统意义上的uv的直观感受不太一样,一般我们在讲解uv的时候,长宽是一样长的,但是shadertoy中不同

在这里插入图片描述

基于UV的颜色处理

接下来进入最重要的一行了 fragColor = vec4(uv.x,0.0,0.0,1.0);

首先,在Shadertoyu中,fragColor 代表最终输出,也就是说,无论你怎么编写这里的代码,都必须要有一个最终输出,这个最终输出需要你传入一个 vec4类型的变量,就是最终颜色,对应颜色的rgba

vec4在用作最终变量的时候,4个值分别对应 红色百分比,绿色百分比,蓝色百分比,透明度

我们从代码中可以得到,我们把uv的x值,作为红色的百分比值,传入到了最终输出中,然后绿色和蓝色保持为0,透明度为1,所以整个效果都呈现红色,只有强弱的区别

但是,这个效果并不是纯红色,因为uv的值是在变的,画面最左侧的uv的u值(代码中是uv.x),是0,左右侧的u值为1,所以最终呈现出了这样的一个渐变红色的效果

我们把uv.x放到第二个参数上,看看效果
在这里插入图片描述
我们把uv.y 作为参数传进去,看看效果
在这里插入图片描述

这样我们就完成了Shader的入门级案例,基于uv的颜色渐变

最基本的ThreeJS Shader

Shader最最基本的案例,我们已经完成了,那么现在我们进入下一阶段,将这个效果应用于Threejs
首先,我们依然要准备一个demo

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>body{width:100vw;height: 100vh;overflow: hidden;margin: 0;padding: 0;border: 0;}</style>
</head>
<body><script type="importmap">{"imports": {"three": "../three/build/three.module.js","three/addons/": "../three/examples/jsm/"}}</script><script type="x-shader/x-vertex" id="vertexShader">varying vec2 vUv;void main(){vUv = vec2(uv.x,uv.y);vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_Position = projectionMatrix * mvPosition;}</script>
<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;void main(){gl_FragColor = vec4(vUv.x,0.0,0.0,1.0);}
</script><script type="module">import * as THREE from "../three/build/three.module.js";import {OrbitControls} from "../three/examples/jsm/controls/OrbitControls.js";window.addEventListener('load',e=>{init();addMesh();render();})let scene,renderer,camera;let orbit;function init(){scene = new THREE.Scene();renderer = new THREE.WebGLRenderer({alpha:true,antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);document.body.appendChild(renderer.domElement);camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,0.1,2000);camera.add(new THREE.PointLight());camera.position.set(0,0,15);scene.add(camera);orbit = new OrbitControls(camera,renderer.domElement);orbit.enableDamping = true;scene.add(new THREE.GridHelper(10,10));}let uniforms = {}function addMesh() {let geometry = new THREE.PlaneGeometry(10,10);let material = new THREE.ShaderMaterial({uniforms,vertexShader:document.getElementById('vertexShader').textContent,fragmentShader:document.getElementById('fragmentShader').textContent,})let mesh = new THREE.Mesh(geometry,material);scene.add(mesh);}function render() {renderer.render(scene,camera);orbit.update();requestAnimationFrame(render);}</script>
</body>
</html>

demo效果如下
在这里插入图片描述
中间的那条线,是在代码中创建的网格辅助线

ShaderMaterial介绍

ShaderMaterial官方文档
RawShaderMaterial官方文档

大多数情况下都用Shadermaterial,内置的东西已经足够用了,RawShaderMaterial只是用了更原生的方式,来编写Shader

现阶段给你文档也不一定看得懂,只需要记得,下面提到的,现阶段死记硬背的东西,就死记硬背下来,按照这个格式写就行了

代码拆解

创建ShaderMaterial,至少要有三个要点

uniforms(参数集)(本篇不讲)

uniforms是一个对象,而且,threejs对uniforms有严格要求,比如说下面的写法:

let uniforms = {
opacity:{ value: 1.0 },
aPosition:{value: new THREE.Vector3()}
}

uniforms的参数,必须是 [key] : { value : [value] },后续会详细讲解uniforms的用法用途

vertexShader(顶点着色器)(现阶段不讲)

threejs这里需要的是一个字符串,这个字符串,就是glsl的代码
现阶段,默认顶点着色器代码固定 ,且只需要知道,创建ShaderMaterial必须要有一个顶点着色器即可,通过document.getElementById(‘vertexShader’).textContent
来获取上面id为 vertexShader的dom,并通过.textContent,来获取到内部编写的文本代码

<script type="x-shader/x-vertex" id="vertexShader">varying vec2 vUv;void main(){vUv = vec2(uv.x,uv.y);vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_Position = projectionMatrix * mvPosition;}</script>

fragmentShader(片元着色器)代码讲解

现阶段主要编写的代码,通过
document.getElementById(‘fragmentShader’).textContent
来获取上面id为 fragmentShader的dom,并通过.textContent,来获取到内部编写的文本代码

<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;void main(){gl_FragColor = vec4(vUv.x,0.0,0.0,1.0);}
</script>

这里我们先介绍片元着色器的代码,等后续进入到顶点着色器的篇章中,再详细介绍顶点着色器

首先,varying vec2 vUv; ,现阶段视为片元着色器的固定代码,只需要关注下面的即可

我们对比一下和ShaderToy的代码结构

在这里插入图片描述

首先,这里我们依然是需要一个main,但是在Threejs的Shader中,写法变更为 main(),而且不需要传入参数(为什么不需要传入参数,这个后续讲解ShadertoyShader时会讲)
然后同样的,threejs中,也需要一个最终输出,只不过,这个最终输出写为 gl_FragColor,参数与Shadertoy一致

我们的代码,采用在Shadertoy的代码的第一版,依然是用vUv.x去控制红色

在Threejs中,uv是内置变量,所以我们为了避免冲突,在这里写成vUv,实际作用与在Shadertoy里面的uv是一致的

现阶段的效果进阶

我们现在改一下代码,改动一点点即可

<script type="x-shader/x-fragment" id="fragmentShader">varying vec2 vUv;void main(){gl_FragColor = vec4(1.0 - vUv.y,0.0,0.0,1.0 - vUv.y);}
</script>

然后改动一下下面的ShaderMaterial

        let material = new THREE.ShaderMaterial({uniforms,vertexShader:document.getElementById('vertexShader').textContent,fragmentShader:document.getElementById('fragmentShader').textContent,transparent:true,side:THREE.DoubleSide});

这样,我们就得出了一个这样的效果

在这里插入图片描述
在这里插入图片描述
然后,我们在代码中,创建4个一样的平面,然后做一下旋转,拼成一个围墙

    function addMesh() {let geometry = new THREE.PlaneGeometry(10,10);let material = new THREE.ShaderMaterial({uniforms,vertexShader:document.getElementById('vertexShader').textContent,fragmentShader:document.getElementById('fragmentShader').textContent,transparent:true,side:THREE.DoubleSide})let mesh = new THREE.Mesh(geometry,material);let mesh1 = mesh.clone();mesh1.position.set(5,5,0);mesh1.rotation.y = Math.PI/2;scene.add(mesh1);let mesh2 = mesh.clone();mesh2.position.set(-5,5,0);mesh2.rotation.y = Math.PI/2;scene.add(mesh2);let mesh3 = mesh.clone();mesh3.position.set(0,5,-5);scene.add(mesh3);let mesh4 = mesh.clone();mesh4.position.set(0,5,5);scene.add(mesh4);}

在这里插入图片描述
这个就是最基础的光栅栏效果,各位可以自行修改在片元着色器中的颜色,来修改颜色

但是,这个光栅栏不是最终版本,请阅读后续教程来继续优化效果

ThreejsShader和ShadertoyShader的巧妙使用

上面我们展示了,如何编写最基本的shader,不难看出,我们在编辑片元着色器的时候,是可以借助Shadertoy来编辑的,很多shadertoy的2d效果,也可以被搬到Threejs中现用,但是仅限于你要看懂,且以uv为基准的那些,所以,如果你想要编辑一些2D的,以及动态贴图效果,都可以借助Shadertoy来研究和学习

本系列教程更新速度可能较慢,还请耐心等待

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/39809.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全网最详细的软件测试面试题总结+基础知识(完整版)

一、什么是软件&#xff1f; 软件是计算机系统中的程序和相关文件或文档的总称。 二、什么是软件测试&#xff1f; 说法一&#xff1a;使用人工或自动的手段来运行或测量软件系统的过程&#xff0c;以检验软件系统是否满足规定的要求&#xff0c;并找出与预期结果之间的差异…

【深海王国】小学生都能玩的语音模块?ASRPRO打造你的第一个智能语音助手(4)

Hi~ (o^^o)♪, 各位深海王国的同志们&#xff0c;早上下午晚上凌晨好呀~ 辛勤工作的你今天也辛苦啦(/≧ω) 今天大都督继续为大家带来系列——小学生都能玩的语音模块&#xff0c;帮你一周内快速学会语音模块的使用方式&#xff0c;打造一个可用于智能家居、物联网领域的语音助…

qtreewidget 美化,htmlcss和qss 不是一个概念!已解决

这种样式的美化&#xff0c; 能气死个人&#xff0c;css 一个单词搞定&#xff0c;非要 在qss中。多少个单词不知道了。 m_tree_widget->setStyleSheet("QTreeView{background:transparent; selection-background-color:transparent;}""QTreeView::branch{b…

linux 安装腾讯会议和解决ubuntu打开腾讯会议提示:不兼容 wayland 协议

一. 下载腾讯会议安装包 腾讯会议下载链接 二. 命令行安装 cd [安装包路径] sudo dpkg -i TencentMeeting_0300000000_3.19.1.400_x86_64_default.publish.deb 三. 打开腾讯会议提示无法支持wayland 协议 解决方法: 打开终端 sudo vi /etc/gdm3/custom.conf打开 #Wayland…

哪个牌子的充电宝牌子便宜好用?2024年性价比高充电宝排行榜!

在 2024 年&#xff0c;充电宝市场依旧琳琅满目&#xff0c;让人眼花缭乱。大家都在寻找那个既便宜又好用的充电宝&#xff0c;可面对众多品牌和产品&#xff0c;常常感到无从下手。别担心&#xff01;经过深入的市场调研和实际使用体验&#xff0c;我们为您精心整理出了 2024 …

轻度图像处理工具,匹敌photoshop

一、简介 1、一款功能强大的在线图片编辑工具,用户可以将其安装为渐进式网页应用(PWA)。它提供了与 Photoshop 相似的核心功能,能够满足大多数图像编辑需求,非常适合那些不愿或无法安装 Photoshop 的用户。即使使用免费版本,用户也能享受所有功能,是轻度图像处理的理想选…

实用麦克风话筒音频放大器电路设计和电路图

设计目标 输入电压最大值输出电压最大值电源Vcc电源Vee频率响应偏差20Hz频率响应偏差20kHz100dB SPL(2Pa)1.228Vrms5V0V–0.5dB–0.1dB 设计说明 此电路使用跨阻抗放大器配置中的运算放大器将驻极体炭精盒麦克风的输出电流转换为输出电压。此电路的共模电压是固定的&#xf…

动物检测yolo格式数据集(水牛 、大象 、犀牛 、斑马四类)

动物检测数据集 1、下载地址&#xff1a; https://download.csdn.net/download/qq_15060477/89512588?spm1001.2101.3001.9500 2、数据集介绍 本数据集含有四种动物可以检测&#xff0c;分别是水牛 、大象 、犀牛 、斑马四类&#xff0c;数据集格式为yolo格式&#xff0c;…

大模型对汽车行业意味着什么?_汽车企业大模型

引 言 大模型是一种利用海量数据进行训练的深度神经网络模型&#xff0c;其特点是拥有庞大的参数规模和复杂的计算结构。通过在大规模数据集上进行训练&#xff0c;大模型能够学习到丰富的模式和特征&#xff0c;从而具备强大的泛化能力&#xff0c;可以对未知数据做出准确的预…

Vue87-Vuex中的mapState、mapGetters

一、借助mapState生成计算属性&#xff0c;从state中读取数据 当vuex中的state有很多数据的时候&#xff1a; 组件中调用state中的数据 此写法不是很方便&#xff0c;借助计算属性。 计算属性的写法也不是很方便&#xff1a; 优化&#xff1a; 1-1、对象写法 注意&#xff1a…

JVM原理(十二):JVM虚拟机类加载过程

一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载为止&#xff0c;它的整个生命周期将会经过 加载、验证、准备、解析、初始化、使用、卸载七个阶段。其中 验证、准备、解析三个部分统称为 连接 1. 加载 加载是整个类加载的一个过程。在加载阶段&#xff0c;Java虚拟机…

使用python编程的视频文件列表应用程序

简介&#xff1a; 在本篇博客中&#xff0c;我们将介绍一个基于 wxPython 的视频文件列表应用程序。该应用程序允许用户选择一个文件夹&#xff0c;并显示该文件夹中的视频文件列表。用户可以选择文件并查看其详细信息&#xff0c;导出文件列表为文本文件&#xff0c;以及播放…

Spring系统学习-什么是AOP?为啥使用AOP?

问题思考 我们为啥要使用AOP? 来看一个案例&#xff1a; 声明计算器接口Calculator&#xff0c;包含加减乘除的抽象方法 public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }public class Calculat…

JS(JavaScript)数据校验 表单校验-案例

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

【Rust入门】生成随机数

文章目录 前言随机数库rand添加rand库到我们的工程生成一个随机数示例代码 总结 前言 在编程中&#xff0c;生成随机数是一种常见的需求&#xff0c;无论是用于数据分析、游戏开发还是模拟实验。Rust提供了强大的库来帮助我们生成随机数。在这篇文章中&#xff0c;我们将通过一…

顺序表--续(C语言详细版)

2.9 在指定位置之前插入数据 // 在指定位置之前插入数据 void SLInsert(SL* ps, int pos, SLDataType x); 步骤&#xff1a; ① 程序开始前&#xff0c;我们要断言一下&#xff0c;确保指针是有效的&#xff0c;不是NULL&#xff1b; ② 我们还要断言一下&#xff0c;指定的…

ctfshow sql注入 web234--web241

web234 $sql "update ctfshow_user set pass {$password} where username {$username};";这里被过滤了&#xff0c;所以我们用\转义使得变为普通字符 $sql "update ctfshow_user set pass \ where username {$username};";那么这里的话 pass\ where…

libtorch+torchvision windows编译

libtorch建议直接采用官方的预编译版本,对应好torchvision版本做编译。 1. libtorch预编译版本下载 libtorch官方下载地址 Pybind11编译 git clone https://github.com/pybind/pybind11.git cd pybind11 mkdir build (base) PS E:\project\pybind11-2.13.1> cd .\build…

小程序-<web-view>嵌套H5页面支付功能

背景&#xff1a;小程序未发布前&#xff0c;公司使用vue框架搭建了管理系统&#xff0c;为了减少开发成本&#xff0c;微信提供了web-view来帮助已有系统能在小程序上发布&#xff0c;详见web-view | 微信开放文档。因公司一直未打通嵌套H5小程序的支付功能&#xff0c;导致用…

AIGC对设计行业的影响与启发:AIGC设计能替代真正的设计师吗?

随着科技的飞速发展&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术在设计行业的应用日益广泛&#xff0c;引发了广泛的讨论和关注。AIGC以其高效、多样化的生成能力&#xff0c;为设计行业带来了前所未有的变革。然而&#xff0c;关于AIGC是否能替代真正的设计…