Vertex Shader
As mentioned before, a vertex shader is responsible for transforming the vertices. In here it will be shown how to transform the vertices following the equations for the fixed functionality.
The fixed functionality states that a vertex is to be transformed by the modelview and projection matrices using the following equation: //固定管线的顶点着色部分把一个顶点变换到剪裁坐标系中,顶点需要乘以两个矩阵,一个是投影矩阵,一个是模型视图矩阵,如下图
vTrans = projection * modelview * incomingVertexIn order to write such a statement in GLSL it is necessary to access the OpenGL state to retrieve both matrices. As mentioned before, part of the OpenGL state is accessible in GLSL, namely the above mentioned matrices. The matrices are provided through predefined uniform variables declared as:
//为了代替固定管线,首先需要得到模型视图矩阵和投影矩阵,可以用下面两个内置的变量直接得到,gl_ModelVieweMatrix和
//gl_ProjectionMatrix;
uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix;One more thing is needed: to access the incoming vertex. These vertices are suplied, one by one, to the vertex shader through a predefined attribute variable:
//通过预先定义的属性变量gl_Vertex,顶点着色器要对每个传入进来的顶点进行处理,也就是乘以上面两个矩阵,这样就把每一个传入进来的顶点变找到了剪裁坐标系,剪裁坐标系范围在x,y,z三个轴方向上为(-1, 1), (-1, 1), (-1, 1);
attribute vec4 gl_Vertex;In order to output the transformed vertex, the shader must write to the also predefined variable gl_Position, declared as a vec4.
Given the above, it is now possible to write a vertex shader that will do nothing more than transform vertices. Note that all other functionality will be lost, meaning, for instance, that lighting computations will not be performed. //这个最简单的顶点着色器只是完成了顶点到剪裁坐标系的转换,而没有计算纹理坐标,光照等其它功能,如果安装了顶点着色器,那么顶点着色器的功能就代替了固定管线的顶点着色功能,如果灯光等没有在顶点着色器中设置,则没有设置的功能将失效
The vertex shader has to have a main function. The following code does the trick:
void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; }
In the above code, the projection matrix is multiplied by the modelview matrix for every vertex, which is a clear waste of time since these matrices do not change per vertex. The matrices are uniform variables.
GLSL provides some derived matrices, namely the gl_ModelViewProjectionMatrix that is the result of multiplying the above matrices. So the vertex shader could be written as:
void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
//此式和上式gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex作用相同,只不过速度快一些 }
The end result is of course the same. Does this guarantee the same transformation as in the fixed functionality? Well in theory yes, but in practice the process of transforming the vertices may not follow the same order as in here. This is normally a highly optimized task in a graphic card, and a special function is provided to take advantage of that optimization. Another reason for this function is due to the limit in the precision of the float data type. When calculus is done in different orders, different results may be obtained due to this limited precision. Hence the GLSL provides a function that guarantees that not only the best performance is obtained but also that the result is always the same as when using the fixed functionality. This magical function is:
vec4 ftransform(void);This function returns the transformed incoming vertex, following the same steps as the fixed functionality does. The shader could then be rewritten as:
void main() { gl_Position = ftransform();//此式和上两式相同,但在精度更高,在任何时候都合固定管线的功能
// 一致,此式为推荐写法. }
Fragment Shader
The fragment shader also has a predefined variable to write the color of the fragment: gl_FragColor. As in the case of vertex shaders, fragment shaders must also have a main function. The following code is for a fragment shader that draws all fragments in a bluish color:
void main() { gl_FragColor = vec4(0.4,0.4,0.8,1.0);//把片元设置为同一种艳色 } //----------------补充说明
此例子为glsl的入门例子,在顶点着色器中仅仅把传入的顶点转找到剪裁坐标系,然后把变换后的顶定通过内置变量gl_Position传给后面的
固定管线,在片元着色器中,把每个片元的艳色设置为(0.4, 0.4, 0.8, 1.0).