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