未完待续:
OpenGL着色器语言(GLSL)由OpenGL实现链接和编译,完全在图形硬件中运行。
至少需要两个着色器
我们可以在3中方式中选择一种向顶点着色器传递数据:
可以为片段着色器设置统一值和纹理数据。
注意:将顶点属性发送到片段着色器毫无意义,因为片段着色器只是用来在土元进行光栅化后对片段进行填充(最基本的是像素)。
着色器程序的从入口点main函数开始。
数据类型:
布尔值
没有指针,且没意任何类型的字符串和字符。但函数可以还回这些类型的一种,也可以声明为void。
向量类型:
向量数据类型 | 描述 |
---|---|
vec2,vec3,vec4 | 2分量,3分量,4分量浮点向量 |
ivec2,ivec3,ivec4 | 2分量,3分量,4分量整数向量 |
uvec2,uvec3,uvec4 | 2分量,3分量,4分量无符号整数向量 |
bvec2,bvec3,bvec4 | 2分量,3分量,4分量布尔向量 |
我们可以使用一个“构造函数初始化一个向量。
例如:
vec4 vVertexPos = vec4(39.0f, 10.0f, 0.0f, 1.0f);
有关向量的操作:
vVertexPos = vOldPos + vOffset; //两个向量相加
vVertexPos = vNewPos; //赋值
vVertexPos = vec4(1.0f, 1.0f, 0.1f, 0.0f);
vVertexPos *= 5.0f; //进行缩放
可以对独立元素进行寻址:
1.典型情况下:
vVertexPos.x = 3.0f;
vVertexPos.xy = vec2(3.0f, 5.0f);
vVertexPos.xyz = vNewPos.xyz;
2.进行颜色操作时使用rgba:
vOutputColor.r = 1.0f;
3.进行纹理操作时用stpq。
4.向量类型还支持调换操作:
如:
vNewColor.bgra = vOtherVertex.x + 5.0f;
向量类型不只是着色器的本地数据类型,也是硬件的数据类型,速度很快。
矩阵类型:
所以的矩阵只支持浮点数。
矩阵类型 | 描述 |
---|---|
mat2,mat2x2 | 两行两列 |
mat3,mat3x3 | 三行三列 |
mat4,mat4x4 | 四行四列 |
mat2x3 | 两行三列 |
mat2x4 | 两行四列 |
mat3x2 | 三行两列 |
mat3x4 | 三行四列 |
mat4x2 | 四行两列 |
mat4x3 | 四行三列 |
一个矩阵就是一个向量组成的数组—-列向量
矩阵的相关操作:
mModelView[3] = vec4(0.0f, 0.0f, 0.0f, 1.0f); /*设置矩阵的最后一列*/
vec4 vTranslation = mModelView[3]; /*恢复一个矩阵的最后一列*/
vec4 vTranslation = mModelView[3].xyz; /**/
vec4 vVertex;
mat4 mvpMatrix;
vOutPos = mvpMatrix * vVertex; //矩阵乘以向量
mat4 vTransform = mat4(1.0f); //构造一个单位矩阵
——限定符用于将变量标记为输入变量(in或uniform)、输出变量(out)或常量。
限定符 | 描述 |
---|---|
const | 一个编译时的常量 |
in | 一个从以前的阶段传递过来的变量 |
in centroid | 一个从以前的阶段传递过来的变量,使用质心插值 |
out | 传递到下一个处理阶段或者在一个函数中指定一个还回值 |
out centroid | 传递到下一个处理阶段,使用质心插值 |
uniform | 一个从客户端传递过来的变量,在顶点之间不做改变 |
inout | 一个读/写变量,只能用于局部函数参数 |
< none> | 只是普通的本地变量,外部不可见,外部不可访问 |
补充:
1. inout只能在一个函数中声明一个参数时使用。这是将一个值传递 到一个函数并且允许这个函数修改并还回同一变量值得唯一方法。
2. 在但采样缓存区中,插值操作总是从像素中心开始的,限定符controid只对一个多重采样缓存区起作用。
3. 默认情况下,参数将在两个着色器阶段之间以一种透视正确的方法进行插补。noperspective关键字来指定一个非透视插值,flat关键词不进行插值,smooth是以一种透视正确的方法进行插补。
GLShanderManager类有个单位存储着色器。—–这种着色器不会对集合图像进行转换,而是使用单一的颜色来绘制图元。
ShadedIdentity顶点程序:
#version 330 //指定着色器要求的OpneGL着色语言的最低版本为3.3
//属性声明
in vec4 vVertex; //顶点位置属性
in vec4 vColor; //顶点颜色属性
out vec4 vVaryingColor; /*传递到片段着色器的颜色值,这个变量将成为要传递到片段着色器的顶点的颜色值,逐个着变量必须为片段着色器声明一个in变量*/
void main(void)
{
vVaryingColor = vColor; // 简单复制颜色值
gl_Postion = vVertex; //简单传递顶点位置
}
ShadedIdentity着色器片段程序:
#version 330
out vec4 vFragColor; //将要进行光栅化的片段颜色
in vec4 vFrayingColor; //从顶点阶段得到的颜色
void main(void)
{
vFragColor = vVaryingColor; //对片段进行颜色插值
}
顶点着色器的后缀名.vp。
片段着色器的后缀名.fp。
gltLoadShaderPairWithAttributes函数
/////////////////////////////////////////////////
//加载一对着色器,进行编译并链接到一起
//为每个着色器指定完整的源文本
//在着色器名之后,指定参数数量,然后指定索引和每个参数的参数名
GLuint gltLoadShaderPairWithAttributes(const char *szVertexProg, const char *szFragmentProg, ......)
{
//临时着色器对象
GLuint hVertexShader;
GLuint hFragmentShader;
GLuint hReturn = 0;
GLint testVal;
//创建着色器对象
hVertexShader = glCreateShader(GL_VERTEX_SHADER);
hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
//加载他们,如果失败则进行清除并还回null
//顶点程序
if(gltLoadShaderFile(szVertexProg, hVertexShader) == false)
{
glDeleteShader(hVertexShader);
glDeleteShader(hFragmentShader);
cout << "The shader at "<< szVertexProg
<< "could not be found.\n";
return (GLuint)NULL;
}
//片段程序
if(gltLoadShaderFile(szFragmentProg, hVFragmentShader) == false)
{
glDeleteShader(hVertexShader);
glDeleteShader(hFragmentShader);
cout << "The shader at "<< szFragmentProg
<< "could not be found.\n";
return (GLuint)NULL;
}
//对两者进行编译
glCompileShader(hVertexShader);
glCompileShader(hFragmentShader);
//在顶点着色器检查错误
glGetShaderiv(hVertexShader, GL_COMPILE_SHADER,
&testVal);
if(testVal == GL_FLASE)
{
char infoLog[1024];
glGetShaderInfoLog(hVertexShader, 1024, NULL,
infoLog);
cout<<"The shader at"<" failed to compile with the following error:\n"<< infoLog << "\n";
glDeleteShader(hVertexShader);
glDeleteShader(hFragmentShader);
return (GLuint)NULL;
}
//在片段着色器检查错误
glGetShaderiv(hFragmentShader, GL_COMPILE_SHADER,
&testVal);
if(testVal == GL_FLASE)
{
char infoLog[1024];
glGetShaderInfoLog(hFragmentShader, 1024, NULL,
infoLog);
cout<<"The shader at"<" failed to compile with the following error:\n"<< infoLog << "\n";
glDeleteShader(hVertexShader);
glDeleteShader(hFragmentShader);
return (GLuint)NULL;
}
//创建最终的程序对象,并链接着色器
hReturn = glCreateProgram();
glAttrachShader(hReturn,hVertexShader);
glAttrachShader(hReturn,hFragmentShader);
//现在需要将参数名绑定到他们指定的参数位置列表上
va_list attributeList;
va_start(attributeList, szFragmentShader);
//重复迭代这个参数列表;
char *szNextArg;
int iArgCount = va_arg(attributeList, int); //参数数量
for(int i = 0; i < iArgCount; i++)
{
int index = va_arg(attributeList, int);
szNextArg = va_arg(attributeList, char*);
glBindAttribLocation(hReturn, index, szNextArg);
}
va_end(attributeList);
//尝试连接
glLinkProgram(hReturn);
//这些不在需要了
glDeleteShader(hVertexShader);
glDeleteShader(hFragmentShader);
//确认连接也有效
glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal);
if(testVal == GL_FLASE)
{
char infoLog[1024];
glGetProgramInfoLog(hReturn, 1024, NULL, infoLog);
cout<<"The program "<" failed to link with the following error:\n"<< infoLog<< "\n";
glDeleteProgram(hReturn);
return (GLuint)NULL;
}
return hReturn;
}
加载一个着色器所以必须元素:
hShader = gltLoadShaderPairWithAttributes("vertexProg.vp", fragmentProg.fp, 2, 0, "vVertexPos", 1, "vNormal");
typedef enum GLT_SHADER_ATTRIBUTE{GLUT_ATTRIBUTE_VERTEX = 0,
GLUT_ATTRIBUTE_COLOR, GLUT_ATTRIBUTE_NORNAL,
GLUT_ATTRIBUTE_TEXTURE0, GLUT_ATTRIBUTE_TEXTURE1,
GLUT_ATTRIBUTE_TEXTURE2, GLUT_ATTRIBUTE_TEXTURE3,
GLUT_ATTRIBUTE_LAST };
hVertexShader = glCreateShader(GL_VERTEX_SHADER);
hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
然后,可以使用者两个着色器ID来加载着色器源代码。
GLchar *fsStringPtr[1];
fsStringPtr[0] = (GLchar *)szShaderSrc;
glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL);
glUseProgram(myShaderProgram);
将着色器设置成活动的,这样在顶点和片段着色器会处理所以提交的几何图形。在提交顶点属性之前,要对Uniform值和纹理进行设置。
在着色器编译和链接后,我们必须在着色器中寻找统一值位置。
GLint glGetUniformLocation(GLuint shaderID, const GLchar * varName);
代表在shaderID指定的着色器中由valName命名的变量的位置。
void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
.
.
.
void glUniform4i(GLint Location, GLint v0, GLint v1, GLint v2, GLint v3);
例如:
uniform float fTime;
uniform int iIndex;
uniform vec4 vColorValue;
uniform bool bSomeFlag;
//为了在着色器中寻找并这些值,代码如下:
GLint locTime, locIndex, locColor, locFlag;
locTime = glGetUniformLocation(myShader, "fTime");
locIndex = glGetUniformLocation(myShader, "iIndex");
locColor = glGetUniformLocation(myShader, "vColorValue");
locFlag = glGetUniformLocation(myShader, "bSomeFlag");
......
......
glUseProgram(myShader);
glUniform1f( locTime, 45.2f);
glUniform1i(locIndex, 42);
glUniform4f(locColor, 1.0f, 0.0f, 0.0f , 1.0f);