2.着色器与GLSL

[TOC]

GLSL

支持了很多c++和java的特性,有一些相似性

#version 330 core

void main()
{
    //TODO
}

注释

//
/**/

变量

支持for循环

for(int i =0; i < 10;i++){

}

基本数据类型

  • float
  • double
  • int
  • uint
  • bool

声明必须初始化

double pi = 3.1415926LF;

类型转换

float f = 10.0;
int ten = (int)f;
  • uint -> int
  • float -> int\uint
  • double -> float\int\uint

聚合类型

基本类型 2D向量 3D向量 4D向量 矩阵类型
float vec2 vec3 vec4 mat2、mat3、mat4、mat2x2 、mat2x3、mat2x4、mat3x2、mat3x3、mat3x4、mat4x2、mat4x3、mat4x4
double dvec2 dvec3 dvec4 dmat2、dmat3、dmat4、dmat2x2 、dmat2x3、dmat2x4、dmat3x2、dmat3x3、dmat3x4、dmat4x2、dmat4x3、dmat4x4
int ivec2 ivec3 ivec4 -
uint uvec2 uvec3 uvec4 -
bool bvec2 bvec3 bvec4 -
vec3 v = vec3(1.0, 1.0, 1.0);

ivec3 step = ivec3(v);

vec4 color;
vec3 RGB = vec3(color);//只有前三个分量

vec3 white = vec3(1.0); //white = (1.0, 1.0,1.0)
vec4 translucent = vec4(white, 0.5);


             
mat3(1.0); //对角矩阵

//给定的数据先填充列,再填充行**
/**
 (1.0, 4.0, 7.0,
  2.0, 5.0, 8.0,
  3.0, 6.0, 9.0
 )
**/

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 = vec3(1.0, 2.0);
vec2 column2 = vec3(4.0, 5.0);
vec2 column3 = vec3(7.0, 8.0);
mat3 M = mat3(column1, 3.0,
                column2, 6.0
                column3, 9.0);

分量访问符 描述
(x,y,z,w) 位置相关
(r,g,b,a) 颜色相关
(s,t,p,q) 纹理坐标相关

float v_y = velocity.y;
float v_y = velocity[1];


vec3 luminance = color.rrr;


color = color.abgr; //反转每个分量

结构体

struct Particle {
    float v,
    vec3 position
}

Particle p = Particle(10.0, pos);

数组

float[3] v = float[3]{1.0,1.0,10.0};

v.length();

mat3x4 m;
int c = m.length();
int r = m[0].length();                                                               

限制符

存储限定符

const

  • 将变量定义为只读

attribute

  • attribute变量是应用程序传输给顶点着色器的逐顶点数据,即每个顶点都需要一份数据,通常用于表示顶点坐标、顶点颜色、纹理坐标等数据。attribute变量在shader中是只读的,不能在顶点着色器中进行修改。此外,attribute变量必须由执行着色器的应用程序传输数据进行赋值。
  • 可使用的最大attribute数量是有上限的,可以使用内置函数glGetIntegerv来查询GL_MAX_VERTEX_ATTRIBS。OpenGL ES 2.0至少支持8个attribute变量。

uniform

  • 设置变量为用户应用程序传递给着色器的数据,对于图元是只读的。
  • 着色器可以使用的uniform个数是有限的,可以使用内置函数glGetIntegerv来查询GL_MAX_VERTEX_UNIFORM_VECTORS和GL_MAX_FRAGMENT_UNIFORM_VECTORS。OpenGL ES 2.0至少支持128个顶点uniform以及16个片元uniform。

varying

  • varying用于声明顶点着色器和片元着色器之间共享的变量。在顶点和片元着色器中,必须有相同的varying变量声明。首先,顶点着色器为每个顶点的varying变量赋值,然后光栅化阶段会对varying变量进行插值计算(光栅化后的每个片元都会得到一个对应的varying变量值),最后把插值结果交给片元着色器进行着色。varying只能用于修饰浮点标量、浮点向量、浮点矩阵以及包含这些类型的数组。
  • varying数量也存在限制,可以使用glGetIntegerv来查询GL_MAX_VARYING_VECTORS。OpenGL ES 2.0至少支持8个varying变量。

buffer

  • 设置应用程序共享的一块可读写的内存,这款内存也作为着色器中的存储缓存

shared

  • 设置变量是本地工作组中共享的

参数限定符

in

  • 着色器阶段的输入变量

out

  • 着色器阶段的输出变量

精度限定符

  • highp 最高精度
  • lowp 最低精度
  • mediump 中间精度,介于两者之间

语句

算数操作符

和java、c++类似

++、+=、a ? b :c 、

流控制

if () {

} else {

}

switch (init_value) {
    case b:
        break;
}

循环

for, do while、while

  • break
  • continue
  • return
  • discard
    • 只在片元着色器中有效,丢弃当前的片元,终止着色器的执行

函数

和c++类似,使用前必须给出函数声明或函数体

float xxx(float x, float y);

参数限制符

GLSL没有指针的的概念

  • in
    • 默认,不需要指定,将数据拷贝到函数中
  • const in
    • 将只读数据拷贝到函数中
  • out
    • 从函数获取数值(输入函数的值是未定义的)
  • inout
    • 将数据拷贝到函数中,并从函数获取数值

计算不变性

GLSL无法保证不同着色器,完全相同的计算式会得到完全一样的结果。

额外

const float f = sin(10.0)//宿主机的编译器负责计算

float g = sin(10.0)//图形硬件负责

f和g可能不一样

invariant

修饰着色器的输出变量

invariant gl_Position;
invariant centroid out vec3 color;

precise

可以设置任何计算中的变量或者函数返回值。

预处理

宏定义

#define
#undef

#ifdef
#endif
#ifndef
#elif
#else

编译器控制

#pragma optimize(on)
#pragma debug(on)

数据块接口

  • uniform块

       uniform b {
           vec4 v1,
           bool v2;
       };
    
       uniform b {
           vec4 v1,
           bool v2;
       } name;
    
  • in/out块

  • buffer块

uniform块

布局控制

  • shared
    • 默认
  • binding = N
  • packed
  • std140
  • std430
  • offset = N
  • align = N
  • row_major
  • column_major

in/out块

buffer块

内置变量

顶点着色器内置变量

  • gl_Position
    • gl_Position是输出变量,用来保存顶点位置的齐次坐标。该值用作图元装配、裁剪以及其他固定管道操作。如果顶点着色器中没有对gl_Position赋值,那么在后续阶段它的值是不确定的。gl_Position可以被写入多次,后续步骤以最后一次写入值为准。
  • gl_PointSize
    • gl_PointSize是输出变量,是着色器用来控制被栅格化点的大小,以像素为单位。如果顶点着色器中没有对gl_PointSize赋值,那么在后续阶段它的值是不确定的。

片元着色器内置变量

  • gl_FragColor
    • gl_FragColor是输出变量,定义了后续管线中片元的颜色值。gl_FragColor可以被写入多次,后续步骤以最后一次写入值为准。如果执行了discard操作,则片元会被丢弃,gl_FragColor将不再有意义。
  • gl_FragCoord
    • gl_FragCoord是只读变量,保存当前片元的窗口坐标(x, y, z, 1/w),该值是图元装配阶段对图元插值计算所得,z分量表示当前片元的深度值。
  • gl_FragDepth
    • gl_FragDepth是输出变量,用于改变片元的深度值(替代gl_FragCoord.z深度值)。如果在任何地方写入了它的值,那么务必在所有执行路径中都写入它的值,否则未写入的路径上它的值有可能不明确。
  • gl_FrontFacing
    • gl_FrontFacing是只读变量,如果片元属于面朝前的图元,那么它的值为true。该变量可以选取顶点着色器计算出的两个颜色之一以模拟双面光照。
  • gl_PointCoord
    • gl_PointCoord是只读变量,表示当前片元在点图元中的二维坐标,范围是0.0到1.0。如果当前图元不是点,那么gl_PointCoord读取的值将是不明确的。

内嵌函数

可参考官方文档或网上资料,例如《OpenGL之GLSL》

ParamType可以是float、vec2、vec3、vec4,参数类型和返回类型是一致的。

三角函数

  • ParamType radians(ParamType degrees)

    • 把角度转换为弧度
  • ParamType degrees(ParamType radians)

    • 把弧度转换为角度
  • ParamType sin(ParamType radians)

    • 以弧度为单位,计算正弦值
  • ParamType cos(ParamType radians)

    • 以弧度为单位,计算余弦值
  • ParamType tan(ParamType radians)

    • 以弧度为单位,计算正切值
  • ParamType asin(ParamType value)

    • sin的反函数,计算给定值的弧度,value的绝对值 <= 1,返回的弧度范围是[-π/2,π/2]
  • ParamType acos(ParamType value)

    • cos的反函数,计算给定值的弧度,value的绝对值 <= 1,返回的弧度范围是[0,π]
  • ParamType atan(ParamType y_over_x)

    • tan的反函数,计算给定值的弧度,返回的弧度范围是[-π/2,π/2]
  • ParamType atan(ParamType y, ParamType x)

    • tan的反函数,也可以称作atan2,返回一个正切值为y/x的弧度,x和y的符号用来确定角在哪个象限。返回的弧度范围是(−π,π)。如果x和y都为0,则结果是未定义的

指数函数

  • ParamType pow(ParamType x, ParamType y)

    • 幂函数返回x的y次方
  • ParamType exp(ParamType x)

    • exp函数返回常数e的x次方
  • ParamType exp2(ParamType x)

    • exp2函数返回常数2的x次方
  • ParamType log(ParamType x)

    • 以常数e为底x的对数函数
  • ParamType log2(ParamType x)

    • 以常数2为底x的对数函数
  • ParamType sqrt(ParamType x)

    • 返回X的平方根
  • ParamType inversesqrt(ParamType x)

    • 返回x的平方根的倒数

通用函数

  • ParamType abs(ParamType x)

    • 返回x的绝对值
  • ParamType sign(ParamType x)

    • x为正时返回1.0,x为零时返回0.0,x为负时返回-1.0
  • ParamType floor(ParamType x)

    • 返回小于或等于x的最大整数
  • ParamType ceil(ParamType x)

    • 返回大于或等于x的最小值
  • ParamType fract(ParamType x)

    • 返回x的小数部分,即: x - floor(x)。
  • ParamType mod(ParamType x, ParamType y)

    • x – y * floor(x / y),如果x和y是整数,返回值是x除以y的余数
  • ParamType mod(ParamType x, float y)

    • 上面mod的变体:y总是float,对于浮点向量,向量的每个分量除以y
  • ParamType min(ParamType x, ParamType y)

    • 返回两个参数的较小值。对于浮点向量,操作是按分量进行比较的
  • ParamType min(ParamType x, float y)

    • 上面min的变体:y总是float,对于浮点向量,向量的每个分量与y进行比较
  • ParamType max(ParamType x, ParamType y)

    • 返回两个参数的较大值。对于浮点向量,操作是按分量进行比较的
  • ParamType max(ParamType x, float y)

    • 上面max的变体:y总是float,对于浮点向量,向量的每个分量与y进行比较
  • ParamType clamp(ParamType x, ParamType minVal, ParamType maxVal)

    • 如果x大于minVal,小于maxVal,则返回x。如果x小于minVal,则返回minVal。如果x大于maxVal,则返回maxVal
  • ParamType clamp(ParamType x, float minVal, float maxVal)

    • 上面clamp的变体,minVal和maxVal总是float,对于浮点向量,向量的每个分量与minVal和maxVal进行比较
  • ParamType mix(ParamType x, ParamType y, ParamType a)

    • 返回x和y的线性混合,即x * (1 - a) + y * a
  • ParamType mix(ParamType x, ParamType y, float a)

    • 上面mix的变体,a总是float,对于浮点向量,向量的每个分量与a计算
  • ParamType step(ParamType edge, ParamType x)

    • 如果x比edge小,则返回0.0,否则返回1.0
  • ParamType step(float edge, ParamType x)

    • 上面step的变体,edge总是float,对于浮点向量,向量的每个分量与edge计算
  • ParamType smoothstep(ParamType edge0, ParamType edge1, ParamType x)

    • 如果x小于edge0,则返回0.0;如果x大于edge1,则返回1.0。否则,返回值将使用Hermite多项式在0.0到1.0之间进行插值
  • ParamType smoothstep(float edge0, float edge1, ParamType x)

    • 上面smoothstep的变体,edge0和edge1总是float,对于浮点向量,向量的每个分量与edge0和edge1比较

几何函数

  • float length(ParamType x)

    • 返回向量长度,即各分量平方和的平方根,对于浮点标量则返回其绝对值
  • float distance(ParamType p0, ParamType p1)

    • 返回两点之间的距离,两点的距离就是向量d(p0 - p1, 从p1开始,指向p0)的长度,对于浮点标量则返回其绝对值
  • float distance(ParamType p0, ParamType p1)

    • 返回两点之间的距离,两点的距离就是向量d(p0 - p1, 从p1开始,指向p0)的长度,对于浮点标量则返回其绝对值
  • float dot(ParamType x, ParamType y)

    • 返回两个向量的点积,即两个向量各个分量乘积的和,对于浮点标量则返回x和y的乘积
  • vec3 cross(vec3 x, vec3 y)

    • 返回两个向量的叉乘向量,更为熟知的叫法是法向量,该向量垂直于x和y向量构成的平面,其长度等于x和y构成的平行四边形的面积。输入参数只能是三分量浮点向量
  • ParamType normalize(ParamType x)

    • 返回向量x的单位向量,即x / |x|,对于浮点标量直接返回1.0
  • ParamType faceforward(ParamType N, ParamType I, ParamType Nref)

    • 如果dot(Nref, I) < 0那么返回N向量,否则返回–N向量
  • ParamType reflect(ParamType I, ParamType N)

    • I:the incident vector(入射向量), N:the normal vector of the reflecting surface(反射面的法向量),返回反射方向: I – 2 * dot(N,I) * N,N一般是单位向量
  • ParamType refract(ParamType I, ParamType N, float eta)

    • I:the incident vector(入射向量), N:the normal vector of the refracting surface(折射面法向量),eta:折射率。返回入射向量I关于法向量N的折射向量,折射率为eta,I和N一般是单位向量

矩阵函数

不同于传统的向量相乘,这里matrixCompMult返回一个向量,该向量的各分量等于x和y向量各个分量的乘积。

mat2 matrixCompMult(mat2 x, mat2 y)  
mat3 matrixCompMult(mat3 x, mat3 y)  
mat4 matrixCompMult(mat4 x, mat4 y)

// 结果向量z
z[i][j] = x[i][j] * y[i][j]

矢量(向量)关系函数

  • bvec lessThan(vec x, vec y) bvec lessThan(ivec x, ivec y)

    • 结果向量result[i] = x[i] < y[i]
  • bvec lessThanEqual(vec x, vec y) bvec lessThanEqual(ivec x, ivec y)

    • 结果向量result[i] = x[i] <= y[i]
  • bvec greaterThan(vec x, vec y) bvec greaterThan(ivec x, ivec y)

    • 结果向量result[i] = x[i] > y[i]
  • bvec greaterThanEqual(vec x, vec y) bvec greaterThanEqual(ivec x, ivec y)

    • 结果向量result[i] = x[i] >= y[i]
  • bvec equal(vec x, vec y) bvec equal(ivec x, ivec y)

    • 结果向量result[i] = x[i] == y[i]
  • bvec notEqual(vec x, vec y) bvec notEqual(ivec x, ivec y)

    • 结果向量result[i] = x[i] != y[i]
  • bool any(bvec x)

    • 假如参数向量的任意一个分量为true,那么返回true
  • bool all(bvec x)

    • 假如参数向量的所有分量为true,那么返回true
  • bvec not(bvec x)

    • 对布尔向量取反

纹理查找函数

纹理查询的目的是从纹理中提取指定坐标的颜色信息。OpenGL中纹理有两种:

  • 2D纹理(sampler2D)
  • 3D纹理(samplerCube)

顶点着色器和片元着色器中都可以使用纹理查找函数。但是顶点着色器中不会计算细节级别(level of detail),所以二者的纹理查找函数略有不同。
以下函数只在顶点着色器中可用:

vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);
vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);
vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);
vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);

以下函数只在片元着色器中可用:

vec4 texture2D(sampler2D sampler, vec2 coord, float bias);
vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);
vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);
vec4 textureCube(samplerCube sampler, vec3 coord, float bias);

float类型参数bias表示:使用mipmaps计算纹理的适当细节级别之后,在执行实际的纹理查找操作之前添加的偏差。
以下函数在顶点着色器和片元着色器中都可用:

vec4 texture2D(sampler2D sampler, vec2 coord);
vec4 texture2DProj(sampler2D sampler, vec3 coord);
vec4 texture2DProj(sampler2D sampler, vec4 coord);
vec4 textureCube(samplerCube sampler, vec3 coord);

着色器编译

  • glShaderSource
  • glCompileShader
  • glCreateShader
  • glAttachShader
  • glCreateProgram
  • glLinkProgram
  • glUseProgram