OpenGL中的着色语言


Glimpse

GLSL是专门用来OpenGL shader的语言,shader是可以直接在GPU上运行的小程序,一般以字符串的方式在代码中使用。shader分为vertex shader(顶点着色器)与fragment shader(片段着色器)两种,顶点shader在每个顶点执行一次,片段shader在每个像素执行一次,两者配合决定模型的渲染结果。

变量类型

GLSL中用来传递值的变量类型有三种:attributeuniformvarying

  • attribute
    attribute变量只存在于顶点shader,用于顶点shader接收CPU传来的数据,多为顶点相关的数据。attribute给了CPU一个向shader传递值的接口,CPU通过变量名获取attribute变量在GPU的地址,使用glVertexAttribPointer命令向其赋值。通常CPU将模型的顶点数据传给shader,shader会依次对每个顶点通过一系列矩阵操作,确定其最终位置,赋值给顶点shader内建的输出变量gl_position供渲染管线下一步使用。
//get attribute slot position
_vertexPosition = glGetAttribLocation(_programHandle, "vertexPosition");
//feed attribute slot
glVertexAttribPointer(_vertexPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, 0);
  • uniform
    uniform常量在shader中不可变,不同于attribute变量,其在顶点shader和片段shader中都可以使用,如果两个shader中都声明了同一个uniform变量,那么他们值是相同的。CPU通过变量名获取uniform变量在GPU的地址,使用glUniform1i命令向其赋值。通常CPU通过uniform常量向GPU传递纹理等数据块。
//get uniform slot position
GLint yuvType = glGetUniformLocation(_programHandle, "yuvType");
//feed uniform slot
glUniform1i(1, yuvType);
  • varying
    顶点shader用varying变量向片段shader传递值。使用时,在顶点shader与片段shader中定义同一个varying变量,顶点shader在顶点执行完之后,会自动将值传递给片段shader。varying变量CPU是不可见的,一般是顶点shader中计算并赋值。通常varying变量用来传递顶点的颜色值、纹理坐标。渐变量有一个重要的特点是可以自动插值。从CPU传给GPU的只是模型每个顶点的属性,对于顶点之间的线或面上的像素属性(主要是其颜色和纹理坐标),渐变量可以根据该像素在顶点间的位置自动插值出来。 这个特点也是为符合其用途的需要。

GLSL有一些特定的数据类型,如vec表示向量、mat表示矩阵、sample2D/sample3D表示纹理。
除此之外GLSL还拥有自己的内建变量,即以gl_开头的变量。可以看这里查阅

语法

GLSL的是基于C的一种语言,语法与其相同,每个shader都由main函数作为程序入口。不同的是shader都有自己的内建变量,使用它们可以与渲染管线通信。例如顶点shader的任务就是计算顶点的最终位置并赋值给gl_Position,片段shader计算每个像素的颜色并赋值给gl_FragColor

以下是一对简单的shader,顶点shader接受CPU传来的vertexPosition与pixelColor,再将pixelColor传递给片段shader,GPU根据它们的计算结果渲染结果。

vertex shader:

//attribute 关键字用来描述传入shader的变量
attribute vec4 vertexPosition; // 需要从外部获取的4分量vector
attribute vec4 pixelColor; 
//varying 关键字用来描述从vertex shader传递给fragment shader的变量
//精度修饰符分为三种:highp, mediump, lowp
varying mediump vec4 finalPixelColor; //mediumP修饰代表中等精度,提高效率。
 
void main(void) { 
    finalPixelColor = pixelColor; // 将pixelColor的值通过finalPixelColor传递给fragment shader
    gl_Position = vertexPosition; // gl_Position是vertex shader的内建变量,gl_Position中的顶点值最终输出到渲染管线中
}

fragment shader:

varying mediump vec4 finalPixelColor; 
 
void main(void) { 
    gl_FragColor = finalPixelColor; // gl_FragColor是fragment shader的内建变量,gl_FragColor中的像素值最终输出到渲染管线中
}

最后

我这里只是基本介绍了下Shader的知识,实际上Shader是支撑各种炫酷特效的幕后功臣,相关的技术也非常深,感兴趣的小伙伴可以去ShaderToy里看一下大神写的Shader是什么样的。

你可能感兴趣的:(OpenGL中的着色语言)