OpenGL programing guide 9th eidtion学习笔记-第二章
Chaper 2 shader
1 语法
1.1 数据类型
类似于C语言,Shader 有各种数据类型,包括基本数据类型(和C 类似, 除了uint)和结构体
uint: unsigned 32-bit integer
特殊的数据类型(不透明类型):sampler types, image types, and atomic counter types (detailed explanation in chapter4)
double 型变量用常量初始化时常量必须用LF结尾 eg: double pi = 3.141592653589732LF
;
GLSL 比 C 类型安全,不支持一些隐式转换 eg: int n = false;
是错误的赋值方式。
支持以下几种类型隐式转换
复合数据类型:向量和矩阵类型
matN(mat2, mat3, mat4, dmat2…) 属于对角矩阵
m = mat3(4.0) = (4.0 0 0
0 4.0 0
0 0 4.0)
矩阵初始化时先列后行的原则,和C语言中的二维数组相反
mat3 M = mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
vec3 column1 = vec3(1.0, 2.0, 3.0); vec3 column2 = vec3(4.0, 5.0, 6.0); vec3 column3 = vec3(7.0, 8.0, 9.0); mat3 M = mat3(column1, column2, column3)
vec2 column1 = vec2(1.0, 2.0); vec2 column2 = vec2(4.0, 5.0); vec2 column3 = vec2(7.0, 8.0); mat3 M = mat3(column1, 3.0, column2, 6.0, column3, 9.0)
以上3种方式初始化的到的矩阵都是
1.0 4.0 7.0
2.0 5.0 8.0
3.0 6.0 9.0
数组
初始化
float coeff[3]; // an array of 3 floats
float[3] coeff; // same thing
int indices[]; //unsized array ,redeclare later with a size
length(
方法可获得数组(数组长度)、矩阵(列数)、向量的长度(元素个数)
存储限定符
uniform 限定符 可修饰任意类型及任意类型的聚合类型
uniform 变量是用户传递给着色器的数据,在所有的着色阶段是不变的,必须定义为全局变量,并且存储在程序对象(program object)中
在着色器中无法改变uniform变量的值,但是可以在定义时进行初始化操作,要修改值只能通过应用程序的API修改,通过预先指定的位置可以查询
layout(Location = 2) *uniform* float scale;
Location应当是唯一的,两个不同的uniform变量不能指定相同的Location。但是在着色器的不同阶段有两个同类型同名的变量,Location必须指定相同的。
数组和结构体的变量位置指定与查询,被分配一组位置,按顺序增长
layout(Location = 4) uniform float array[5];
占据4-8总共5个位置
Location 有最大数量限制GL_MAX_UNIFORM_LOCATIONS(至少1024),所有变量的位置(0,GL_MAX_UNIFORM_LOCATIONS -1)
buffer 限定符 类似***uniform*** ,但是可以在着色器中修改值
1.2 流程控制(Control Flow)
和 C类似,if else, for ,while, do…while() ,switch
fragment shader 阶段discard关键字,表示丢弃当前片元fragment,终止shader执行
1.3 函数
参数访问限制符(accessModifer)eg. float HornerEvalPolynomial(float coeff[10], float x);
in 限定符时可选的,没有指定访问限定符的参数默认是in
计算一致性(Computation Invariance)
关键字 invariant, precise,这两个关键字修饰的变量只针对在图形设备上的计算
调试阶段可以用 #pragma STDGL invariant(all) 表示所有的变量都用invariant修饰,但是会降低着色器性能(使用该关键字会禁用优化)
precise 关键字除了可以修饰变量,还可以修饰函数返回值,在细分曲面着色(tessellation shader)阶段用的最多
eg:
precise gl_Position; precise out vec3 Location; precise vec3 subdivide(vec3 P1, vec3 P2) { ... }
1.4 预处理指令
1.4.1 宏定义和预处理条件
简单宏定义 #define NUM_ELEMENTS 1
带参数的宏定义 #define LPos(n) gl_LightSource[(n)].postion
取消宏定义 #undef LPos
#ifdef NUM_ELEMENTS
...code
#endif
或者
#if defined(NUM_ELEMENTS) && NUM_ELEMENTS >3
code...
#elif NUM_ELEMENTS < 7
code...
#endif
1.4.2 编译器控制
优化控制 #pragma optimize(on/off)
on 打开优化,off关闭优化, 默认全局优化,也可单独在某个函数头和声明对某个函数进行优化
调试开关 #pragma debug(on/off)
1.4.3 扩展
#extension extension_name:<directive>
or
#extension all:<directive>
1.5 Interface Block
有的时候,在各个shader阶段、shader程序和应用程序之间共享的变量,必须声明在Block中
eg:
匿名块
uniform b { // 'uniform' or 'in' or 'out' or 'buffer' vec4 v1; // list of variables bool v2; // ... }; // no name; access members as 'v1' and 'v2
有名块
uniform b { // 'uniform' or 'in' or 'out' or 'buffer' vec4 v1; // list of variables bool v2; // ... } name; // named; access members as 'name.v1' and 'name.v2
uniform block layout control
eg:设置一个unform block shared and row_major matrices
layout(shared, row_major) uniform b{...}
设置往后的所有Uniform block的layout, 用下面的格式声明
layout(packed, c= column_major) uniform;
#version 440
layout (std140) uniform b {
float size; // starts at byte 0, by default
ayout(offset=32) vec4 color; // starts at byte 32
layout(align=1024) vec4 a[12]; // starts at the next multiple of 1024
vec4 b[12]; //assigned next offset after a[12]
} buf;
Buffer block
和uniform block 类似,不同的是buffer block 可以在shader中改变值,而且只能使用std430的layout限定符
In/Out Block,Location, Component
输入输出变量也可以以block的形式组织,这样能比较直观地判断各个shader阶段之间的输入输出是否匹配
不论是再block之内还是block之外,同一location最多可以容纳vec4, 所以想要在已经定义的同一location再添加更小的对象,可以用component来声明
#version 440 in Lighting { layout(location=1) vec3 normal; layout(location=2) vec2 bumpCoord; };
#version 440 in Lighting { layout(location=1, component=0) vec2 offset; layout(location=1, component=2) vec2 bumpCoord; };
1.7 SubRoutine
step1 :定义subroutine 原型
subroutine returnType subroutineType(type param, …);
step2:实现每个函数
subroutine (subroutineType) returnType functionName(…);
step3:指定subroutine 类型的函数指针uniform变量名
subroutine uniform subroutineType variableName;
Example:
subroutine vec4 LightFunc(vec3); // Step 1
subroutine (LightFunc) vec4 ambient(vec3 n) // Step 2
{ return Materials.ambient; }
subroutine (LightFunc) vec4 diffuse(vec3 n) // Step 2 (again) { return Materials.diffuse * max(dot(normalize(n), LightVec.xyz), 0.0); }
subroutine uniform LightFunc materialShader; // Step 3
指定选择哪个subroutine function的步骤
step1: 获取subroutine uniform 函数指针变量的位置Location
调用函数 GLint glGetSubroutineUniformLocation(GLuint program, GLenum shadertype, const char* name);
step2: 获取指定subroutine function 的index
GLuint glGetSubroutineIndex(GLuint program, GLenum shadertype, const char* name);
step3: 设定指定位置的subroutine uniform的调用index
GLuint glUniformSubroutinesuiv(GLenum shadertype, GLsizei count, const GLuint * indices);
example:
GLint materialShaderLoc; GLuint ambientIndex; GLuint diffuseIndex; glUseProgram(program);
materialShaderLoc = glGetSubroutineUniformLocation(program, GL_VERTEX_SHADER, "materialShader");
if (materialShaderLoc < 0) { // Error: materialShader is not an active subroutine // uniform in the shader. }
ambientIndex = glGetSubroutineIndex(program,GL_VERTEX_SHADER,“ambient”);
diffuseIndex = glGetSubroutineIndex(program, GL_VERTEX_SHADER, “diffuse”);if (ambientIndex == GL_INVALID_INDEX ||diffuseIndex == GL_INVALID_INDEX)
{ // Error: the specified subroutines are not active in // the currently bound program for the GL_VERTEX_SHADER // stage. }
else { GLsizei n; glGetIntegerv(GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, &n); GLuint *indices = new GLuint[n]; indices[materialShaderLoc] = ambientIndex; glUniformSubroutinesuiv(GL_VERTEX_SHADER, n, indices); delete [] indices; }