OpenGL着色器语言

来源:互联网 发布:数据专员这工作好吗 编辑:程序博客网 时间:2024/05/21 17:08

初识OpenGL着色器语言


未完待续:


1、着色器架构

OpenGL着色器语言(GLSL)由OpenGL实现链接和编译,完全在图形硬件中运行。

基本着色器架构

至少需要两个着色器

  • 顶点着色器
  • 片段着色器。
  • 还有一种可选的着色器称为几何着色器。

我们可以在3中方式中选择一种向顶点着色器传递数据:

  1. 参数,是对每个顶点而言的。
  2. 统一值,是针对整个顶点数据批次的常量。
  3. 加载和使用纹理数据。

可以为片段着色器设置统一值和纹理数据。

注意:将顶点属性发送到片段着色器毫无意义,因为片段着色器只是用来在土元进行光栅化后对片段进行填充(最基本的是像素)。

着色器程序的从入口点main函数开始。


2、变量和数据类型

数据类型:

  • 整数(有符号和无符号)
  • 浮点数(单精度)
  • 布尔值

    没有指针,且没意任何类型的字符串和字符。但函数可以还回这些类型的一种,也可以声明为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);  //构造一个单位矩阵

3、存储限定符

——限定符用于将变量标记为输入变量(in或uniform)、输出变量(out)或常量。

  • 输入变量:接受来自OpenGL客户端(通过C/C++提交的属性)或者以前的着色器阶段(例如从顶点着色器传递到片段着色器)。
  • 输出变量:指在任何着色器阶段进行写入的变量,我们希望在后续的着色器阶段能看到这些变量。如,从顶点着色器传递到片段着色器。
限定符 描述 const 一个编译时的常量 in 一个从以前的阶段传递过来的变量 in centroid 一个从以前的阶段传递过来的变量,使用质心插值 out 传递到下一个处理阶段或者在一个函数中指定一个还回值 out centroid 传递到下一个处理阶段,使用质心插值 uniform 一个从客户端传递过来的变量,在顶点之间不做改变 inout 一个读/写变量,只能用于局部函数参数 < none> 只是普通的本地变量,外部不可见,外部不可访问

补充:
1. inout只能在一个函数中声明一个参数时使用。这是将一个值传递 到一个函数并且允许这个函数修改并还回同一变量值得唯一方法。
2. 在但采样缓存区中,插值操作总是从像素中心开始的,限定符controid只对一个多重采样缓存区起作用。
3. 默认情况下,参数将在两个着色器阶段之间以一种透视正确的方法进行插补。noperspective关键字来指定一个非透视插值,flat关键词不进行插值,smooth是以一种透视正确的方法进行插补。


4、真正的着色器

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 330out vec4 vFragColor;    //将要进行光栅化的片段颜色in vec4 vFrayingColor;  //从顶点阶段得到的颜色void main(void){    vFragColor = vVaryingColor;  //对片段进行颜色插值}
  • 属性声明:是由C/C++客户端OpenGL代码逐个顶点进行指定的,每个顶点程序中最多可以有16个属性。另外,标记为in的变量是只读的。
  • 顶点动作:主函数main中的内容,gl_Position是一个预定义的内建4个分量向量,它包含顶点着色器要求的一个输出。输入gl_Position的值是集合图形阶段用来装配图元的。
  • 片段三角形:在渲染一个图元时,一旦3个顶点有顶点程序进行处理,那么他们将组成一个三角形,这个三角形将由硬件进行光栅化。如果片段程序只有一个输出,那么它在内部将被分配为“输出0”。这个片段着色器的一个输出,并将传递到有glDrawBuffers设置的缓存区目标。

5、编译、绑定和链接

顶点着色器的后缀名.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"<<szVertexProg            <<" 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"<<szFragmentProg            <<" 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 "<<hReturn            <<" 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");

    用来绑定一个带有顶点位置和表面法线属性的着色器。
  • GLTools类GLBatch和GLTriangleBatch使用一系列一直的属性位置,

    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 };

    使用这些属性位置标识符,我们就可以开始和GLShaderManager类中支持的存储着色器一起使用自己的着色器了。
  • 设置源代码:
    首要任务是创建两个着色器对象,分别对应顶点着色器和片段着色器。
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);

  • 编译着色器
  • 进行连接和绑定
  • 连接着色器

6、使用着色器

glUseProgram(myShaderProgram);将着色器设置成活动的,这样在顶点和片段着色器会处理所以提交的几何图形。在提交顶点属性之前,要对Uniform值和纹理进行设置。


着色器统一值

1、寻址统一值

在着色器编译和链接后,我们必须在着色器中寻找统一值位置。

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);

0 0
原创粉丝点击