一、着色器
着色器(Shaders )是一种使用GLSL(OpenGL Shading Language)编写并在GPU上运行的程序。它们被用于定位几何体的每个顶点,并为该几何体的每个可见像素着色。使用“像素Pixel”来描述其实并不准确,因为渲染的每个点不一定与屏幕上的每个像素相匹配,因此我们更倾向于使用术语“片元fragment”。
之后我们会向着色器发送大量数据,如顶点坐标、网格变换、摄像机及其视野范围的信息、颜色、纹理、灯光、雾等参数。然后,GPU会按照着色器的指示处理所有的这些数据,接着几何体便出现在渲染中。
Shaders 也是一系列的指令,但是这些指令会对屏幕上的每个像素同时下达。也就是说,你的代码必须根据像素在屏幕上的不同位置执行不同的操作。就像活字印刷,你的程序就像一个 function(函数),输入位置信息,输出颜色信息,当它编译完之后会以相当快的速度运行
二、顶点着色器和片元着色器
WebGL
的着色器代码分为顶点着色器代码和片元着色器代码两部分,顶点着色器代码会在GPU
的顶点着色器单元执行,片元着色器代码会在GPU
的片元着色器单元执行,在WebGL
渲染管线流程中,或者说GPU
的渲染流程中,顶点着色器代码先执行处理顶点,得到一系列片元,然后再执行片元着色器代码处理片元。
————————————————
1、顶点着色器
顶点着色器(Vertex Shader
)的作用是定位几何体的顶点。其思想是发送顶点位置、网格变换(如定位position
、旋转rotation
和缩放scale
)、摄影机信息(如定位position
、旋转rotation
和视野fov
)。然后,GPU
将按照顶点着色器中的指示处理所有这些信息,以便将顶点投影到2D空间,该空间将成为我们的渲染render
,也就是我们的画布canvas
。
顶点着色器首先运行; 它接收attributes
, 计算/操纵每个单独顶点的位置,并将其他数据(varyings
)传递给片元着色器。
————————————————
2、片元着色器
片元着色器的作用是为几何体的每个可见片元(像素)进行着色。
我们会创建片元着色器,可以通过使用uniform
将数据(像是颜色)和着色器发送至GPU
,之后GPU
就会按照指令对每个片元进行着色。
片元(或像素)着色器后运行; 它设置渲染到屏幕的每个单独的“片元”(像素)的颜色。
三、着色器材质
着色器材质(ShaderMaterial
)是一个用GLSL
编写的小程序 ,在GPU
上运行。它能够提供 materials
之外的效果,也可以将许多对象组合成单个Geometry
或BufferGeometry
以提高性能。
shader
中有三种类型的变量: uniforms
, attributes
, varying
关键字(变量类型) | 数据传递 | 声明变量 |
---|---|---|
uniforms | javascript 顶点、片元着色器 | 声明非顶点数据变量 |
attributes | javascript 片元着色器 | 声明顶点数据变量 |
varying | 顶点着色器->片元着色器 | 声明需要插值计算的顶点变量 |
- Uniforms是所有顶点都具有相同的值的变量。 比如灯光,雾,和阴影贴图就是被储存在uniforms中的数据。
uniforms可以通过顶点着色器和片元着色器来访问。 - Attributes 与每个顶点关联的变量。例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes 只
可以在顶点着色器中访问。 - Varyings 是从顶点着色器传递到片元着色器的变量。对于每一个片元,每一个varying的值将是相邻顶点值的平滑插值。
————————————————
炫彩蛋示例
var geometry= new THREE.SphereGeometry(10, 30, 20);
// 创建着色器材质
var material= new THREE.ShaderMaterial({//顶点着色器vertexShader: `varying vec3 vNormal;void main() {//将attributes的normal通过varying赋值给了向量vNormalvNormal = normal;//projectionMatrix:投影变换矩阵 modelViewMatrix:相机坐标系的变换矩阵 y值乘以1.4得到形如鸡蛋的几何体gl_Position = projectionMatrix * modelViewMatrix * vec4( position.x, position.y * 1.4, position.z, 1.0 );}`,// 片元着色器fragmentShader: `//片元着色器同样需要定义varying vec3 vNormal;varying vec3 vNormal;void main() {//vNormal是一个已经归一化的三维向量float pr = (vNormal.x + 1.0) / 2.0; //pr红色通道值范围为0~1float pg = (vNormal.y + 1.0) / 2.0; //pg绿色通道值范围为0~1float pb = (vNormal.z + 1.0) / 2.0; //pb蓝色通道值范围为0~1gl_FragColor=vec4(pr, pg, pb, 1.0); //最后设置顶点颜色,点与点之间会自动插值}`
})
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh)