初识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 330
out 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);

OpenGL着色器语言相关推荐

  1. OpenGL着色器语言GLSL语法总结

    GLSL语法与C语言类似. 1.变量类型 基础类型:bool,int,uint,float,double与C语言的类型类似. 向量类型:vecN,bvecN,ivecN,uvecN,dvecN,N表示 ...

  2. OpenGL着色器GLSL

    OpenGL着色器 OpenGL着色器简介 GLSL 数据类型 向量 输入与输出 顶点着色器 片段着色器 Uniform 更多属性 我们自己的着色器类 从文件读取 OpenGL着色器简介 着色器(Sh ...

  3. OpenGL ES着色器语言之变量和数据类型

    所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符.变量在声明的时候首先要标明类型,后边可以跟多个变量,之间用逗号隔开.很多情 ...

  4. OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)...

    OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ...

  5. OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章)

    OpenGL ES着色器语言之变量和数据类型(二)(官方文档第四章) 4.5精度和精度修饰符 4.5.1范围和精度 用于存储和展示浮点数.整数变量的范围和精度依赖于数值的源(varying,unifo ...

  6. OpenGL ES着色器语言(GLSL ES)规范 ——下篇

    文章目录 前言 分支和循环 if.if-else for continue.break.discard 着色器内置变量 函数 函数定义 规范声明 webgl内置函数 存储限定字 const attri ...

  7. OpenGL着色器基础

    前言: 本文翻译自LearnOpengl经典教程,OpenGL着色器基础介绍的比较通俗易懂,特总结分享一下! 为什么要使用着色器? 我们知道,OpenGL一般使用经典的固定渲染管线来渲染对象,但是随着 ...

  8. OpenGL(三)——OpenGL着色器基础

    上一篇我们介绍了OpenGL基础相关的知识:OpenGL图形绘制和OpenGL入门,今天介绍一下OpenGL另一重要的成员----OpenGL着色器. 什么是OpenGL着色器? Open GL ES ...

  9. 可编程渲染管线与着色器语言

    Programming pipeline & shading language 大家好,今天想给大家介绍一下可编程渲染管线和着色器语言的相关基础知识,使想上手SHADER编程的童鞋们可以快速揭 ...

  10. opengl 着色器

    Opengl 着色器 文章目录 Opengl 着色器 前言 一.GLSL 二.使用步骤 效果 前言 着色器(Shader)是运行在GPU上的小程序.这些小程序为图形渲染管线的某个特定部分而运行.从基本 ...

最新文章

  1. C语言之prinf的用法
  2. 三种方式实现观察者模式 及 Spring中的事件编程模型
  3. linux find d,Linux find命令傻瓜入门
  4. linux课程教学设计,《LINUX操作系统》课程整体教学设计.doc
  5. Ubuntu 安装简单samba
  6. 面试总结之html+css
  7. 2017.10.8 球形空间产生器sphere 思考记录
  8. WCF从理论到实践(10):异常处理 (转)
  9. 数据分析看关晓彤的招黑之路
  10. 0.0 研磨设计模式
  11. VB 2010 (53)Command对象
  12. Android 开源项目和文章集合(更新:2022.03.21)
  13. 千万流量大型分布式系统架构设计实战(干货)
  14. 简要分析上海链家9月二手房
  15. java 刽子手图像代码,刽子手游戏代码
  16. 云迁移实践:VMware虚拟机迁移到华为云
  17. 腾讯QQ会员中心g_tk32算法【C#版】
  18. 5G核心网技术基础自学系列 | (增强型)专用核心网
  19. APP渗透—Android 7.0 抓包(教程)
  20. js版身份证省市性别查询

热门文章

  1. 【转】用万兆网卡测试超五类网线传输速度,颠覆你的认知
  2. 一个完整的项目管理流程包括什么?
  3. 二维码生成器:问卷星怎么生成二维码?
  4. seafile专业版集成微软的office online实现在线协同编辑
  5. java a的2次方_java-获取比a大,最接近a的2的次方的数(最小二次幂,位运算)
  6. Node.js安装详细步骤教程(Windows版)
  7. python实现整数反转_python算法 整数反转
  8. dsp的ad标志位是什么_DSP简简单单学习之AD采样
  9. Ajax回调函数中return不生效问题
  10. 计算机系军训横幅,军训横幅标语有创意精选100句