WebGL (着色器)Shaders
WebGL (着色器)Shaders
着色器是在GPU上运行的程序,着色器是用OpenGL ES着色语言(称为es sl)编写的。ES SL有自己的变量、数据类型、限定符、内置输入和输出.
数据类型
下表列出了OpenGL提供的基本数据类型。
No | 类型 | 简介 |
---|---|---|
1 | void | 表示空值 |
2 | bool | 接受true或false |
3 | int | 整数类型 |
4 | float | 浮点数 |
5 | vec2, vec3, vec4 | n-component浮点向量 |
6 | bvec2, bvec3, bvec4 | 布尔向量 |
7 | ivec2, ivec3, ivec4 | 符号整数向量 |
8 | mat2, mat3, mat4 | 2x2, 3x3, 4x4浮点矩阵 |
9 | sampler2D | 访问二维纹理 |
10 | samplerCube | 访问立方体映射纹理 |
限定符
OpenGL ES SL中有三个主要限定符:
No | 限定符 | 说明 |
---|---|---|
1 | attribute | 这个限定符作为顶点着色器和每个顶点数据的OpenGL ES之间的链接. 这个属性的值改变了顶点着色的每一个执行 |
2 | uniform | 这个限定符链接着色程序和WebGL应用程序 。与属性限定符不同,制服的值不会改变。制服仅供阅读;可以使用任何基本数据类型来声明变量 |
3 | varying | 这个限定符形成了顶点Shader和片段Shader之间的链接,用于插值数据 。它可以与float、vec2、vec3、vec4、mat2、mat3、mat4或arrays数据类型一起使用 |
顶点Shader
顶点着色是一个程序代码,它在每个顶点上调用,它将几何图形(例如:三角形)从一个位置转换为另一个位置,它处理每个顶点(每个顶点数据)的数据,如顶点坐标、法线、颜色和纹理坐标.
在顶点着色器的ES代码中,程序员必须定义属性来处理数据,这些属性指向用JavaScript编写的顶点缓冲对象,可以使用顶点着色器和顶点转换执行以下任务:
顶点变换
正常变换与归一化
纹理坐标生成
纹理坐标变换
照明设备
颜色材料应用
预定义变量
OpenGL ES可为顶点着色器提供以下预定义的变量:
No | 变量 | 说明 |
---|---|---|
1 | highp vec4 gl_Position | 保持顶点的位置 |
2 | mediump float gl_PointSize | 保持变换的点大小,此变量的单位为像素 |
示例代码
下面的示例代码处理三角形的顶点:
attribute vec2 coordinates; void main(void) { gl_Position = vec4(coordinates, 0.0, 1.0); };
如果仔细观察上述代码,我们已经用名称坐标声明了一个属性变量(此变量将与使用方法getattriblocation()的顶点缓冲对象关联),属性坐标作为参数传递给这个方法和着色程序对象.
在给定顶点着色程序的第二步中,定义了gl_position 变量。
gl_position
gl_position是预定义的变量,它只在顶点着色程序中可用。它包含顶点位置。在上述代码中,坐标属性以向量的形式传递。由于顶点着色是一个顶点操作,每个顶点都计算出gl_position值.
稍后,原始装配、剪裁、剔除以及在顶点处理结束后对基元操作的其他固定功能操作使用gl_position值。
我们可以编写顶点着色程序为所有的操作顶点着色,我们将在本教程中单独讨论。
片段Shader
网格由多个三角形组成,每个三角形的表面称为片段,片段Shader是在每个像素上运行的代码。这是为了计算和填充每个像素的颜色,可以使用片段Shader执行以下任务:
插值的运算
纹理存取
纹理应用
雾
彩色和
预定义变量
OpenGL ES可为片段Shader提供以下预定义的变量:
No | 变量 | 说明 |
---|---|---|
1 | mediump vec4 gl_FragCoord | 在帧缓冲区中保存片段位置 |
2 | bool gl_FrontFacing | 保存属于面向前端基元的片段 |
3 | mediump vec2 gl_PointCoord | 在点内保持碎片位置(仅限光栅化) |
4 | mediump vec4 gl_FragColor | 保持着色器的输出片段的颜色值 |
5 | mediump vec4 gl_FragData[n] | 保存颜色附件n的碎片颜色 |
示例代码
下面片段Shader的示例代码演示如何将颜色应用到三角形中的每个像素:
void main(void) { gl_FragColor = vec4(0, 0.8, 0, 1); }
在上述代码中,颜色值存储在变量gl.FragColor,片段Shader通过固定函数变量将输出传递到管道中;FragColor是其中之一,此变量保存模型的像素的颜色值。
存储和编译着色程序。
由于着色器是独立的程序,我们可以将它们作为单独的脚本编写,并在应用程序中使用。或者可以直接以字符串格式存储它们,如下所示。
var vertCode = 'attribute vec2 coordinates;' + 'void main(void) {' + ' gl_Position = vec4(coordinates, 0.0, 1.0);' + '}';
编译Shader
汇编涉及以下三个步骤:
创建着色对象
将源代码附加到创建的着色对象中。
编译程序
创建顶点着色器
为了创建一个空的着色器, WebGL提供了一个名为createShader()的方法。它创建和返回着色对象。其语法如下:
Object createShader (enum type)
正如在语法中所观察到的,此方法接受预定义的枚举作为参数。我们有两个选择,
gl.VERTEX_SHADER用于创建顶点Shader
gl.FRAGMENT_SHADER用于创建片段Shader
将源附加到着色器上。
可以使用方法shaderSource()将源代码附加到创建的着色对象中。其语法如下:
void shaderSource(Object shader, string source)
此方法接受两个参数−
Shader-你必须通过创建的着色对象作为一个参数。
Source-你必须通过着色器尔程序代码的字符串形式。
编译程序
要编译程序,必须使用方法compileshader()。其语法如下:
compileShader(Object shader)
这个方法接受着色程序对象作为参数。创建着色程序对象后,将源代码附加到它,并将该对象传递给这个方法。
下面的代码片段展示了如何创建和编译一个顶点着色器以及一个片段着色器来创建一个三角形。
// Vertex Shader var vertCode = 'attribute vec3 coordinates;' + 'void main(void) {' + ' gl_Position = vec4(coordinates, 1.0);' + '}'; var vertShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertShader, vertCode); gl.compileShader(vertShader); // Fragment Shader var fragCode = 'void main(void) {' + ' gl_FragColor = vec4(0, 0.8, 0, 1);' + '}'; var fragShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragShader, fragCode); gl.compileShader(fragShader);
组合程序
在创建和编译两个着色程序之后,您需要创建一个包含着色器(顶点和片段)的组合程序。需要采取以下步骤:
创建程序对象
附上着色器
将着色器链接
使用程序
创建程序对象
使用方法createprogram()创建程序对象,它将返回一个空的程序对象。以下是它的语法:
createProgram();
附上着色器
使用方法attachshader()将着色器附加到创建的程序对象。其语法如下
attachShader(Object program, Object shader);
此方法接受两个参数−
Program−传递创建的空程序对象作为一个参数。
Shader-通过一个已编译的着色器程序(顶点着色,片段着色)
注意-您需要使用此方法同时附加两个着色器。
链接着色器
通过传递您连接着色器的程序对象,使用方法linkprogram()链接着色器。其语法如下:
linkProgram(shaderProgram);
使用程序
WebGL提供了一种名为useprogram()的方法,您需要将链接程序传递给它。其语法如下:
useProgram(shaderProgram);
下面的代码片段显示如何创建、链接和使用组合着色程序:
var shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertShader); gl.attachShader(shaderProgram, fragShader); gl.linkProgram(shaderProgram); gl.useProgram(shaderProgram);