Skip to content

基础要点

  1. shader 语言 有一个 main 函数,会在最后返回颜色值。这点和 C 语言很像。

  2. 最终的像素颜色取决于预设的全局变量 gl_FragColor。

  3. 这个类 C 语言有内建的变量(像gl_FragColor),函数和数据类型。在本例中我们刚刚介绍了vec4(四分量浮点向量)。之后我们会见到更多的类型,像 vec3 (三分量浮点向量)和 vec2 (二分量浮点向量),还有非常著名的:float(单精度浮点型), int(整型) 和 bool(布尔型)。

  4. 如果我们仔细观察 vec4 类型,可以推测这四个变元分别响应红,绿,蓝和透明度通道。同时我们也可以看到这些变量是规范化的,意思是它们的值是从0到1的。之后我们会学习如何规范化变量,使得在变量间map(映射)数值更加容易。

  5. 另一个可以从本例看出来的很重要的类 C 语言特征是,预处理程序的宏指令。宏指令是预编译的一部分。有了宏才可以 #define (定义)全局变量和进行一些基础的条件运算(通过使用 #ifdef 和 #endif)。所有的宏都以 # 开头。预编译会在编译前一刻发生,把所有的命令复制到 #defines 里,检查#ifdef 条件句是否已被定义, #ifndef 条件句是否没有被定义。在我们刚刚的“hello world!”的例子中,如果定义了GL_ES这个变量,才会插入运行第2行的代码,这个通常用在移动端或浏览器的编译中。

  6. float类型在 shaders 中非常重要,所以精度非常重要。更低的精度会有更快的渲染速度,但是会以质量为代价。你可以选择每一个浮点值的精度。在第一行(precision mediump float;)我们就是设定了所有的浮点值都是中等精度。但我们也可以选择把这个值设为“低”(precision lowp float;)或者“高”(precision highp float;)。

  7. 最后可能也是最重要的细节是,GLSL 语言规范并不保证变量会被自动转换类别。这句话是什么意思呢?显卡的硬件制造商各有不同的显卡加速方式,但是却被要求有最精简的语言规范。因而,自动强制类型转换并没有包括在其中。在我们的“hello world!”例子中,vec4 精确到单精度浮点,所以应被赋予 float 格式。但是如果你想要代码前后一致,不要之后花费大量时间 debug 的话,最好养成在 float 型数值里加一个 . 的好习惯。

glsl
#ifdef GL_ES
precision mediump float;  // highp mediump lowp
#endif

uniform float u_time;

void main() {
	gl_FragColor = vec4(1.0,0.0,1.0,1.0);
}
#ifdef GL_ES
precision mediump float;  // highp mediump lowp
#endif

uniform float u_time;

void main() {
	gl_FragColor = vec4(1.0,0.0,1.0,1.0);
}

:::tips 注意 精度设置 lowp、mediump、highp(可能会导致一些bug,由于精度不足导致)

precision mediump float; 在three.js中 精度设置有可能会报错,必须保证 顶点着色器片元着色器在同一频率。 :::