属性是每个顶点位置、表面法线和纹理坐标都需要的,而统一值则用于为整个图元批次向保持不变的着色器传递数据。对于顶点着色器来说,最普遍的统一值就是变换矩阵。任何着色器变量都可以指定为一个统一值,而统一值可以在3个着色器阶段中的任意一个阶段。
创建统一值的方法很简单,只需要在变量声明开始的时候放置一个uniform关键字。
统一值不能标记为in或out,他们也不能在着色器阶段之间进行插值,并且他们总是只读的。
(1)寻找统一值
在一个着色器进行编译和连接之后,我们必须在着色器中统一值位置。
glGetUniformLocation(GLuint shaderID, const GLchar* varName);
注意,这个函数返回一个有符号的整数,代表在shaderID指定的着色器中由varName命名的变量位置。
注意,着色器变量名称是区分大小写的。如果返回值为-1,那么输入的名字就不能被定位。
即使着色器编译正确, 但是如果不是在着色器当中直接使用过,那么一个统一值名称仍然能够在这个着色器当中消失。我们不必担心统一变量会被优化掉,但是如果声明了一个统一值而不去使用,那么编译器会丢掉它。
(2)设置标量和向量的统一值
一个单独的标量和向量数据类型可以再glUniform函数当中使用下面的变量进行设置:
void glUniform4f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2,GLfloat v3)
其他数量以及不同的数据类型类似上面的函数,第一位为location。
GLint locTime;
locTime=glGetUniformLocation(myShader, "fTime");
glUseProgram(myShader);
glUniform1f(locTime, 42.5f);
注意上面的执行顺序,其他数据类型大同小异:首先声明变量,使用变量得到对应统一值的location,然后选定着色器激活程序,最后赋值。
(3)设置统一数组
注意这种赋值和上面的赋值是完全不同的两回事。
glUnform函数还接受一个指针,假定指向一个数值数组。
void glUniform4fv(GLint location, GLuint count, GLfloat* v);
void glUniform4iv(GLint location, GLuint couunt, GLint* v);
在这里,count值代表每个含有x分量的数组中有多少个元素,其中x是位于函数名字末尾的数字。
关于函数的赋值的目标数,请注意函数末尾的几个字母。
注意:可以一次性赋值一个向量,那么count就为1啦。
(4)设置统一矩阵
设置矩阵统一值,着色器矩阵数据类型只有浮点类型,这样变量就少了很多。
glUniformMatrix2fv(GLint location, GLuint count, GLboolean transpose, const GLfloat *m);
glUniformMatrix3fv(GLint location, GLuint count, GLboolean transpose, const GLfloat *m);
glUniformMatrix4fv(GLint location, GLuint count, GLboolean transpose, const GLfloat *m);
变量count代表指针参数m中存储的矩阵数量(可以使用矩阵数组!)。如果矩阵已经按照列优先排列进行存储,布尔值标记transpose将会被设置为GL_TRUE。将这个值设置为GL_FALSE会导致这个矩阵复制到着色器当中的时发生变换。
如果使用一个行优先矩阵布局(Direct3D),那么这一点就要考虑进去。
(5)平面着色器
// Flat Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130
// 注意这个透视投影矩阵
uniform mat4 mvpMatrix;
// 传入的顶点信息
in vec4 vVertex;
void main(void)
{
//这是对几何图形进行变换的操作
gl_Position = mvpMatrix * vVertex;
}
这个是顶点渲染器,作为vp文件存放在程序的主目录中。
// Flat Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130
// 设置几何图形为实体。
uniform vec4 vColorValue;
// 输出片段颜色
out vec4 vFragColor;
void main(void)
{
vFragColor = vColorValue;
}
存储在fp文件,在主程序工程文件目录下,等待读取。
#pragma comment(lib,"GLTools.lib")
#include <GLTools.h> // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <GL/glut.h>
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLuint flatShader; // The Flat shader
GLint locMVP; // 重点:声明访问到shader程序当中的统一值
GLint locColor; // 重点:声明访问到shader程序当中的统一值
// 渲染环境初始化
void SetupRC(void)
{
// Background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
viewFrame.MoveForward(4.0f);
// Make the torus
gltMakeTorus(torusBatch, .80f, 0.25f, 52, 26);
//加载shader程序
flatShader = gltLoadShaderPairWithAttributes("FlatShader.vp", "FlatShader.fp", 1, GLT_ATTRIBUTE_VERTEX, "vVertex");
//在SetUpRC当中加载对应shader当中的统一值属性。
locMVP = glGetUniformLocation(flatShader, "mvpMatrix");
locColor = glGetUniformLocation(flatShader, "vColorValue");
}
// Cleanup
void ShutdownRC(void)
{
}
// Called to draw scene
void RenderScene(void)
{
static CStopWatch rotTimer;
// Clear the window and the depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
modelViewMatrix.PushMatrix(viewFrame);
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
GLfloat vColor[] = { 0.1f, 0.1f, 1.f, 1.0f };
//注意,在SetupRC当中装载并且得到对应shader当中的统一值
//在Render当中对shader程序进行加载,并且对统一值进行赋值。
glUseProgram(flatShader);
glUniform4fv(locColor, 1, vColor);
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
torusBatch.Draw();
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}
void ChangeSize(int w, int h)
{
// Prevent a divide by zero
if (h == 0)
h = 1;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);
//得到透视投影矩阵
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Simple Transformed Geometry");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
对平面着色器进行使用。