另外,“uniforming a matrix”是什么意思?
以下内容直接从http://www.lighthouse3d.com/tutorials/glsl-tutorial/data-types-and-variables/复制而来。实际网站有更详细的信息,值得一看。
变量修饰符
修饰符可以赋予变量特殊含义。以下修饰符可用:
- const – 声明为编译时常量。
- attribute – 全局变量,可能会在每个顶点中发生变化,由OpenGL应用程序传递到顶点着色器中。此修饰符只能在顶点着色器中使用。对于着色器而言,这是一个只读变量。请参见Attribute部分。
- uniform – 全局变量,可能会在每个基元中发生变化[...],由OpenGL应用程序传递到着色器中。此修饰符可在顶点着色器和片段着色器中使用。对于着色器而言,这是一个只读变量。请参见Uniform部分。
- varying – 用于在顶点着色器和片段着色器之间插值数据。在顶点着色器中可写,在片段着色器中只读。请参见Varying部分。
对于类比,const和uniform就像C/C++中的全局变量,一个是常量,另一个可以被设置。Attribute变量伴随着顶点而变化,例如颜色或纹理坐标。Varying变量可以被顶点着色器修改,但不能被片段着色器修改,因此它们实际上是通过管道传递信息。
uniform
是 每个图元(primitive) 的参数(在整个绘制调用期间保持不变);attribute
是 每个顶点 的参数(通常是位置、法向量、颜色、UV 等);varying
是 每个片段(或像素) 的参数:它们从一个像素变化到另一个像素。了解 varying
的工作原理对于编写自己的着色器非常重要。
假设您在 顶点着色器 中为三角形的每个顶点定义了一个变化参数 v
。当将此变化参数发送到 片段着色器 时,它的值会根据要绘制的像素的位置自动插值。
在以下图像中,红色像素接收到了变化参数 v
的插值值。这就是为什么我们称它们为“varying”的原因。
为简单起见,上面给出的示例使用了 双线性插值,假设所有绘制的像素与相机的距离相同。为了实现准确的 3D 渲染,图形设备使用 透视校正插值,它考虑了像素的深度。
// "program" contains a shader pipeline:
// vertex shader -> other shaders -> fragment shader
//
const program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
顶点着色器处理顶点,几何着色器处理几何体,镶嵌着色器处理细分,像素着色器处理片元,计算着色器处理其他批处理任务,这些都是渲染三维模型所需的。
OpenGL(WebGL)着色器使用GLSL编写(一种在GPU上编译的基于文本的着色器语言)。
// Note: As of 2017, WebGL only supports Vertex and Fragment shaders
<!-- Vertex Shader -->
<script id="shader-vs" type="x-shader/x-vertex">
// <-- Receive from WebGL application
uniform vec3 vertexVariableA;
// attribute is supported in Vertex Shader only
attribute vec3 vertexVariableB;
// --> Pass to Fragment Shader
varying vec3 variableC;
</script>
<!-- Fragment Shader -->
<script id="shader-fs" type="x-shader/x-fragment">
// <-- Receive from WebGL application
uniform vec3 fragmentVariableA;
// <-- Receive from Vertex Shader
varying vec3 variableC;
</script>
着色器可以将数据传递给管道中的下一个着色器(out
,inout
),它们还可以接受来自WebGL应用程序或先前着色器的数据(in
)。
顶点着色器和片段着色器(任何着色器都可以)可以使用uniform
变量从WebGL应用程序接收数据。
// Pass data from WebGL application to shader
const uniformHandle = gl.glGetUniformLocation(program, "vertexVariableA");
gl.glUniformMatrix4fv(uniformHandle, 1, false, [0.1, 0.2, 0.3], 0);
顶点着色器还可以使用attribute
变量接收来自WebGL应用程序的数据,根据需要启用或禁用该变量。
// Pass data from WebGL application to Vertex Shader
const attributeHandle = gl.glGetAttribLocation(mProgram, "vertexVariableB");
gl.glEnableVertexAttribArray(attributeHandle);
gl.glVertexAttribPointer(attributeHandle, 3, gl.FLOAT, false, 0, 0);
顶点着色器可以使用 varying
变量将数据传递到片段着色器。请参见上面的GLSL代码(varying vec3 variableC;
)。
Uniforms是将数据从CPU应用程序传递到GPU着色器的另一种方式,但与顶点属性相比,uniforms略有不同。首先,uniforms是全局的。全局意味着uniform变量对于每个着色器程序对象是唯一的,并且可以从着色器程序的任何阶段访问。其次,无论您将uniform值设置为什么,uniforms都会保持其值,直到重置或更新它们为止。
我喜欢https://learnopengl.com/Getting-started/Shaders中的描述,因为单词“per-primitive”并不直观。