目录
一、说明
二、着色器的变量
2.1 着色器变量
2.2 着色器内置变量
三、最常见内置变量使用范例
3.1 常见着色器变量
3.2 示例1: gl_PointSize
3.3 示例2:gl_Position
3.4 gl_FragColor
3.5 渲染点片元坐标gl_PointCoord
3.6 gl_PointCoord应用案例
四、GPU的内置函数
4. 1 内置函数列表
4.2 角度与三角函数
4.3 指数函数
4.4 通用函数
4.5 几何函数
4.6 矩阵函数
4.7 矢量函数
4.8 纹理查询函数
一、说明
着色器的内置变量和内置函数很有必要说一说,因为,初入门的时候不知道着色器有多深的水准,必须将它所蕴涵的东西统统摆到桌面上,才能有所准备,有所认知,有所实用。本篇就是将着色器默认的变量函数统统摆出,混个脸熟。
二、着色器的变量
2.1 着色器变量
着色器有两种变量:
- 普通变量,着色器语言和C语言类似,需要先声明后使用。
- 内置变量,所谓内置变量就是不用声明可以直接赋值,主要是为了实现特定的功能。
2.2 着色器内置变量
1) 顶点着色器内置变量
名称 | 类型 | 描述 |
---|---|---|
gl_Color | vec4 | 输入属性-表示顶点的主颜色 |
gl_SecondaryColor | vec4 | 输入属性-表示顶点的辅助颜色 |
gl_Normal | vec3 | 输入属性-表示顶点的法线值 |
gl_Vertex | vec4 | 输入属性-表示物体空间的顶点位置 |
gl_MultiTexCoordn | vec4 | 输入属性-表示顶点的第n个纹理的坐标 |
gl_FogCoord | float | 输入属性-表示顶点的雾坐标 |
gl_Position | vec4 | 输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。 |
gl_ClipVertex | vec4 | 输出坐标,用于用户裁剪平面的裁剪 |
gl_PointSize | float | 点的大小 |
gl_FrontColor | vec4 | 正面的主颜色的varying输出 |
gl_BackColor | vec4 | 背面主颜色的varying输出 |
gl_FrontSecondaryColor | vec4 | 正面的辅助颜色的varying输出 |
gl_BackSecondaryColor | vec4 | 背面的辅助颜色的varying输出 |
gl_TexCoord[] | vec4 | 纹理坐标的数组varying输出 |
gl_FogFragCoord | float | 雾坐标的varying输出 |
2)片段着色器内置变量
名称 | 类型 | 描述 |
---|---|---|
gl_Color | vec4 | 包含主颜色的插值只读输入 |
gl_SecondaryColor | vec4 | 包含辅助颜色的插值只读输入 |
gl_TexCoord[] | vec4 | 包含纹理坐标数组的插值只读输入 |
gl_FogFragCoord | float | 包含雾坐标的插值只读输入 |
gl_FragCoord | vec4 | 只读输入,窗口的x,y,z和1/w |
gl_FrontFacing | bool | 只读输入,如果是窗口正面图元的一部分,则这个值为true |
gl_PointCoord | vec2 | 点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。 |
gl_FragData[] | vec4 | 使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。 |
gl_FragColor | vec4 | 输出的颜色用于随后的像素操作 |
gl_FragDepth | float | 输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替 |
三、最常见内置变量使用范例
3.1 常见着色器变量
内置变量名称 | 含义 | 变量数值类型 |
---|---|---|
gl_PointSize | 点渲染模式,方形点区域渲染像素大小 | float |
gl_Position | 顶点位置坐标 | vec4 |
gl_FragColor | 片元颜色值 | vec4 |
gl_FragCoord | 片元坐标,单位像素 | vec2 |
gl_PointCoord | 点渲染模式对应点像素坐标 | vec2 |
当WebGL执行绘制函数gl.drawArrays()绘制模式是点模式gl.POINTS的时候,顶点着色器语言main函数中才会用到内置变量gl_PointSize,使用内置变量gl_PointSize主要是用来设置顶点渲染出来的方形点像素大小。
3.2 示例1: gl_PointSize
void main() {
//给内置变量gl_PointSize赋值像素大小,注意值是浮点数
gl_PointSize=20.0;
}
//绘制函数绘制模式:点gl.POINTS
gl.drawArrays(gl.POINTS,0,点数量);
3.3 示例2:gl_Position
gl_Position内置变量主要和顶点相关,出现的位置是顶点着色器语言的main函数中。gl_Position内置变量表示最终传入片元着色器片元化要使用的顶点位置坐标。
如果只有一个顶点,直接在给顶点着色器中设置内置变量gl_Position赋值就可以,内置变量gl_Position的值是四维向量vec4(x,y,z,1.0),前三个参数表示顶点的xyz坐标值,第四个参数是浮点数1.0。
void main() {
//顶点位置,位于坐标原点
gl_Position = vec4(0.0,0.0,0.0,1.0);
}
如果你想完全理解内置变量gl_Position,必须建立逐顶点的概念,如果javascript语言中出现一个变量赋值,你可以理解为仅仅执行一次,但是对于着色器中不能直接这么理解,如果有多个顶点,你可以理解为每个顶点都要执行一遍顶点着色器主函数main中的程序。
多个顶点的时候,内置变量gl_Position对应的值是attribute关键字声明的顶点位置坐标变量apos,顶点位置坐标变量apos变量对应了javascript代码中多个顶点位置数据。
<!-- 顶点着色器源码 -->
<script id="vertexShader" type="x-shader/x-vertex">
//attribute声明vec4类型变量apos
attribute vec4 apos;
void main() {
//顶点坐标apos赋值给内置变量gl_Position
//逐顶点处理数据
gl_Position = apos;
}
</script>
逐顶点处理的案例:WebGL的每一个顶点位置坐标都会通过平移矩阵m4进行矩阵变换,相当于批量操作所有的顶点数据,进行了平移,只是平移的计算通过矩阵乘法运算完成的而已。所谓的逐顶点,在这里体现的就是每一个顶点都会执行main函数中的矩阵变换。你可以参照生活的流水线去理解,比如多个同样的设备从我这里经过,我会分别对他们进行同样的操作,比如安装一个零件。
<!-- 顶点着色器源码 -->
<script id="vertexShader" type="x-shader/x-vertex">
//attribute声明vec4类型变量apos
attribute vec4 apos;
void main() {
//创建平移矩阵(沿x轴平移-0.4)
//1 0 0 -0.4
//0 1 0 0
//0 0 1 0
//0 0 0 1
mat4 m4 = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, -0.4,0,0,1);
//平移矩阵m4左乘顶点坐标(vec4类型数据可以理解为线性代数中的nx1矩阵,即列向量)
// 逐顶点进行矩阵变换
gl_Position = m4*apos;
}
</script>
## gl_Position的顶点数据传递
attribute声明的顶点变量数据如何通过javascript的WebGL API批量传递所有顶点数据。
<script>
//顶点着色器源码
var vertexShaderSource = document.getElementById( 'vertexShader' ).innerText;
//片元着色器源码
var fragShaderSource = document.getElementById( 'fragmentShader' ).innerText;
//初始化着色器
var program = initShader(gl,vertexShaderSource,fragShaderSource);
//获取顶点着色器的位置变量apos,即aposLocation指向apos变量。
var aposLocation = gl.getAttribLocation(program,'apos');
//类型数组构造函数Float32Array创建顶点数组
var data=new Float32Array([0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]);
//创建缓冲区对象
var buffer=gl.createBuffer();
//绑定缓冲区对象,激活buffer
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
//顶点数组data数据传入缓冲区
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
//缓冲区中的数据按照一定的规律传递给位置变量apos
gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0);
//允许数据传递
gl.enableVertexAttribArray(aposLocation);
...
</script>
3.4 示例3:gl_FragColor
gl_FragColor内置变量主要用来设置片元像素的颜色,出现的位置是片元着色器语言的main函数中。
内置变量gl_Position的值是四维向量vec4(r,g,b,a),前三个参数表示片元像素颜色值RGB,第四个参数是片元像素透明度A,1.0表示不透明,0.0表示完全透明。
// 片元颜色设置为红色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
理解内置变量gl_Position需要建立逐顶点的概念,对于内置变量gl_FragColor而言,需要建立逐片元的概念。顶点经过片元着色器片元化以后,得到一个个片元,或者说像素点,然后通过内置变量gl_FragColor给每一个片元设置颜色值,所有片元可以使用同一个颜色值,也可能不是同一个颜色值,可以通过特定算法计算或者纹理像素采样。
根据位置设置渐变色
void main() {
// 片元沿着x方向渐变
gl_FragColor = vec4(gl_FragCoord.x/500.0*1.0,1.0,0.0,1.0);
}
纹理采样
// 接收插值后的纹理坐标
varying vec2 v_TexCoord;
// 纹理图片像素数据
uniform sampler2D u_Sampler;
void main() {
// 采集纹素,逐片元赋值像素值
gl_FragColor = texture2D(u_Sampler,v_TexCoord);
}
片元坐标gl_FragCoord
内置变量gl_FragCoord表示WebGL在canvas画布上渲染的所有片元或者说像素的坐标,坐标原点是canvas画布的左上角,x轴水平向右,y竖直向下,gl_FragCoord坐标的单位是像素,gl_FragCoord的值是vec2(x,y),通过gl_FragCoord.x、gl_FragCoord.y方式可以分别访问片元坐标的纵横坐标。
下面代码是把canvas画布上不同区域片元设置为不同颜色。
<!-- 片元着色器源码 -->
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
// 根据片元的x坐标,来设置片元的像素值
if(gl_FragCoord.x < 300.0){
// canvas画布上[0,300)之间片元像素值设置
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}else if (gl_FragCoord.x <= 400.0) {
// canvas画布上(300,400]之间片元像素值设置
gl_FragColor = vec4(0.0,1.0,0.0,1.0);
}else {
// canvas画布上(400,500]之间片元像素值设置
gl_FragColor = vec4(0.0,0.0,1.0,1.0);
}
// 所有片元设置为红色
// gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>
片元的颜色随着坐标变化(设置一个渐变色效果)
<!-- 片元着色器源码 -->
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
// 片元沿着x方向渐变
gl_FragColor = vec4(gl_FragCoord.x/500.0*1.0,1.0,0.0,1.0);
}
</script>
3.5 渲染点片元坐标gl_PointCoord
如果你想了解内置变量gl_PointCoord表示的坐标含义,就需要了解 GL绘制函数gl.drawArrays()的绘制模式参数gl.POINTS。
绘制函数gl.drawArrays()绘制模式参数设置为点渲染模式gl.POINTS,WebGL会把顶点渲染为一个方形区域,在顶点着色器代码中可以通过内置变量gl_PointSize设置顶点渲染的方向区域像素大小。
一个顶点渲染为一个方形区域,每个方形区域可以以方向区域的左上角建立一个直角坐标系,然后使用内置变量gl_PointCoord描述每个方形区域中像素或者说片元的坐标,比如方形区域的左上角坐标是(0.0,0.0),每个方形区域几何中心坐标是(0.5,0.5),右下角坐标是(1.0,1.0)。
注意内置变量gl_PointCoord和gl_FragCoord表示的像素坐标含义不同,查看下图表示。
// 点绘制模式渲染10个顶点
gl.drawArrays(gl.POINTS,0,10);
顶点着色器中通过内置变量gl_PointSize设置点渲染的方形区域像素尺寸。
void main() {
//点渲染的方形区域像素大小
gl_PointSize = 20.0;
...
}
3.6 gl_PointCoord应用案例
gl.POINTS绘制模式点默认渲染效果是方形区域,通过下面片元着色器代码设置可以把默认渲染效果更改为圆形区域。
<!-- 片元着色器源码 -->
<script id="fragmentShader" type="x-shader/x-fragment">
precision lowp float;// 所有float类型数据的精度是lowp
void main() {
// 计算方形区域每个片元距离方形几何中心的距离
// gl.POINTS模式点渲染的方形区域,方形中心是0.5,0.5,左上角是坐标原点,右下角是1.0,1.0,
float r = distance(gl_PointCoord, vec2(0.5, 0.5));
//根据距离设置片元
if(r < 0.5){
// 方形区域片元距离几何中心半径小于0.5,像素颜色设置红色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}else {
// 方形区域距离几何中心半径不小于0.5的片元剪裁舍弃掉:
discard;
}
}
</script>
通过gl_PointCoord返回的是片元纵横坐标vec2(x,y),自然通过xy分量gl_PointCoord.x、gl_PointCoord.y方式可以分别访问片元坐标的横坐标、纵坐标,
四、GPU的内置函数
4. 1 内置函数列表
4.2 角度与三角函数
4.3 指数函数
4.4 通用函数