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; 是错误的赋值方式。

支持以下几种类型隐式转换
OpenGL programing guide 9th eidtion学习笔记-第二章

复合数据类型:向量和矩阵类型
OpenGL programing guide 9th eidtion学习笔记-第二章

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( 方法可获得数组(数组长度)、矩阵(列数)、向量的长度(元素个数)

存储限定符
OpenGL programing guide 9th eidtion学习笔记-第二章

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)
OpenGL programing guide 9th eidtion学习笔记-第二章
eg. float HornerEvalPolynomial(float coeff[10], float x);

in 限定符时可选的,没有指定访问限定符的参数默认是in

计算一致性(Computation Invariance)

关键字 invariantprecise,这两个关键字修饰的变量只针对在图形设备上的计算

调试阶段可以用 #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 预处理指令

OpenGL programing guide 9th eidtion学习笔记-第二章

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>
OpenGL programing guide 9th eidtion学习笔记-第二章

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
OpenGL programing guide 9th eidtion学习笔记-第二章
OpenGL programing guide 9th eidtion学习笔记-第二章
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; }

1.8 SPRI-V