Shader(GLSL)

GLSL语言编写,主要两类Vertex shader,Fragement shader

Shader构造:
预处理
变量定义
通过输入参数和函数算法,计算输出结果(main函数)

预处理:
预处理的运算在编译时执行

只有一个#行的一行会被忽略掉
#

宏定义 后面可以跟和不跟宏参数
#define
#undef

条件判断宏 只能跟随数字运算或者define定义的宏定义,未被define定义过的标识符不会被默认为0,使用会导致error,不支持字母常量
#if
#ifdef
#ifndef
#else
#elif
#endif

将错误信息放到shader的log中,可通过OpenGL的api获取shader的log,error后面整行信息都会出现shader的log中,存在#error的shade会被视为错误的shader
#error

通过跟随的参数控制编译
#pragma

引入extension
#extension

glsl版本,需在最前
#version

#line

预定义的宏定义
LINE:当前所在行数加1
FILE:当前文件文件名
VERSION:当前glsl版本
GL_ES:判断当前shader是否运行在OpenGL ES的系统中

GLSL中的变量类型
void bool int float

vec2 vec3 vec4 (保存float值)
bvec2 bvec3 bvec4
ivec2 ivec3 ivec4

如果只给一个参数,则向量中其他值也会使用此值,比如给vec4一个1.0的值:提供给向量的参数只能是1个或者对应向量个数,比如vec4类型不能提供2个参数

vec4 v5 = vec4(1.0);
等价于
vec4 v5 = vec4(1.0,1.0,1.0,1.0);

通过 “.” 符号获取,向量分量为{x, y, z, w} , {r, g, b, a} 或 {s, t, r, q} 。{x, y, z, w}是位置相关的分量,{r, g, b, a}是颜色相关的分量,{s, t, r, q}是纹理坐标相关的分量

mat2 mat3 mat4
(二维,保存矩阵,保存22 , 33,4*4个float值,只有float值。顺序:第一列从上到下,第二列从上到下,以此类推)
如果只提供一个参数,则该值做为矩阵对角线的值,也就是单位矩阵,比如mat4(1.0),就是4x4单位矩阵
例如
mat[4]当做vec4
mat4[0][1]为第一个vec4中第二个元素,当做float

如果通过一个 matrix 来对另外一个 matrix 进行赋值,那么传入参数的第 i 行第 j 列,会按照相同的位置传给被赋值的 matrix,其他未赋值地方从单位阵对应位置获取

需要注意的是,GLSL中的向量表示竖向量,所以与矩阵相乘进行变换时,矩阵在前,向量在后(与DirectX正好相反)

采样器:采样器是专门用来对纹理进行采样工作的,在GLSL中一般来说,一个采样器变量表示一副或者一套纹理贴图。所谓的纹理贴图可以理解为我们看到的物体上的皮肤。
在 OpenGL ES 中生成贴图,然后传给 GLSL 使用。
sample2D 和 sampleCube 就是用于保存从 OpenGL ES 传入,在 Shader 中使用的 2D 贴图或者 CubeMap 贴图的 handle。

结构
c++中类与结构一个默认私有(类)一个默认公开(结构),没有本质区别
这里结构体与c语言结构体相同,c语言结构中没有成员函数

数组
GLSL中只支持一维数组,所有的基本类型或者struct都可以组装成数组,不支持在定义array的时候进行初始化
array可以当作函数输入参数,不能当做函数输出函数。

GLSL不支持指针

GLSL中的数据类型主要分为标量、向量、矩阵、采样器、结构体、数组、空类型七种类型

GLSL 使用嵌套式范围系统,在同一个范围不能定义两个变量名相同的变量,在不同的范围可以。根据作用域的不同,一个变量会覆盖另外一个变量,并且在该作用域中,无法访问被覆盖的变量。

共享全局变量:可被多个shader访问。vertex shader和fragment shader分别拥有一个自己的全局范围。函数只能定义在全局范围 中,不能定义在语句块中。

限定符

const
struct 的结构体的成员,不可以被 const 修饰,但是使用自定义 struct 变量类型创建的变量,可以被 const 修饰,然后通过 struct 的构造函数进行初始化。
array 不能被初始化,所以它们不能被 const 修饰。
作为函数的参数,表明传入的参数是只读的

attribute
一般用于传入各个顶点各不相同的量。如顶点颜色、坐标等。
从OpenGL ES向VS传输数据使用。
只能被定义在VS中,在别的shader中定义attribute变量会报错
属于只读变量
只能修饰float、vec2、vec3、vec4、mat2、mat3、mat4(只包含float类型变量的变量)
如果 attribute 修饰的变量为 float,也会占用一个 vec4 的位置,所以 attribute 应该尽可能的组合成 vec4 类型的变量。而 mat4 则占用了 4 个 vec4 的位置,mat2 占用了 2 个,mat3 占用了 3 个。
不能修饰 array 或者 struct 类型的变量
shader中所有attribute的必须是全局变量
一个shader中使用的attribute的数量是有限的,不同平台,支持的数量也不同

uniform
一般用于对于3D物体中所有顶点都相同的量。比如光源位置,统一变换矩阵,纹理贴图等。
从OpenGL ES中同时向VS和PS传输数据使用。
属于只读变量,可修饰任何类型的变量。
uniform的尺寸有限制,不同平台,支持的uniform的尺寸不同
除了开发者定义的uniform,shader本身有build-in的uniform,也会被计入计算uniform的尺寸,用于判断尺寸限制
被称为global变量,区别于local和attribute中的全局变量,uniform不知在当前shader是全局变量,如果一个VS和PS被连接在一起使用,将会使用同一个global uniform name spcae。即,若在VS和PS分别定义变量名相同的uniform,则变量类型和精度修饰符等信息必须完全相等,可认为是两则为同一个变量。

varying
表示易变量,一般用于顶点着色器传递到片元着色器的量。
从VS向PS传输数据使用
在 VS 中定义一个 varying 变量,则VS 中运算的每一个点都会包含一个 varying 变量对应的值,但VS 只会针对 OpenGL ES 传入的几个点做运算,得到最终的顶点坐标值。如果将这几点的颜色通过attribute传入VS,VS得到顶点的颜色值,再通过varying把颜色传入PS,在传递过程中,光栅化的时候,会根据顶点包含的颜色值进行插值,赋值给产生的新点。然后在PS中,对所有产生的点进行运算,针对每个点运算时每个点都会有个varying值(经过光柵化产生的新值)
光栅化受到single-sample和multi-sample的影响,就是插值的算法不同。
varing在VS中是可读可写的,在未写之前读取,获得的是undefine。
varing在PS中是可读不可写。读取的是PS当前处理像素点经过光栅化后生成的varing值。
若在VS和PS中定义了相同变量名的varing变量,必须类型相同,精度修饰符可不同
PS中定义并使用的varing,必须在VS中定义,若VS中未赋值,则PS中读取的值undefine
varing可修饰float、vec2、vec3、vec4、mat2、mat3、mat4或对应的array类型,不可以是struct
必须是全局变量

GPU同时多核的,所以在VS或PS自己的多次运算间 ,不可以传输数值,否则会导致无法并行运算

GLSL中,uniform是共享全局。varing不被认为共享全局,因为必须在VS和PS中同时定义,并通过VS传给光栅化,再传给PS。共享全局的变量必须拥有相同的名字、类型、存储、精度修饰发

参数修饰符:用于函数的参数列表中
in:输入参数,无修饰符时默认为此修饰符。在函数中也可以被修改,但是其实修改的是函数中的那个变量的副本,并非传入的那个函数,所以在函数之外,这个参数的值是不变的。(传值函数)
out:输出参数。参数在传入时为初始化,需在函数中进行赋值,在调用该函数的代码块中被使用。不能被const修饰
inout:既可以作为输入参数,又可以作为输出参数。不能变const修饰。参数可在函数中进行更新赋值,在函数外,也会被使用。

精度修饰符
浮点精度:与顶点着色器不同的是,在片元着色器中使用浮点型时,必须指定浮点类型的精度
highthp:VS支持的最低要求
mediump:PS支持的最低要求
lowp
Shader(GLSL)

恒定修饰符
两个VS中,同样的表达式对输入gl_Position赋值,且输入参数一致,可能shader运行的gl_Position值不同。shader不会把变量定义的值保存起来,而是在使用变量的时候,根据场景重新运算,当变量和不同精度的值运算时,因为精度不同运算的结果也不同。
invariant可以避免这种差别。可以将某个变量定义成invariant,也可以定义一个全局的invariant,使该shader所有可被定义成invariant的变量都定义为invariant

discard
跳转语句,只能用于PS中,用于抛弃当前像素的计算,不会更新该像素点的buffer信息了。例如检测当前alpha小于0,则抛弃

内置变量
内置变量与自定义的varing变量不同。varing变量本质是在VS和PS中各定义一个名字类型一样的变量来一一对应。而内置变量则是在VS和PS都存在。

gl_Position:
顶点坐标
只存在于VS中,属于VS中的内置变量。在VS中,需将顶点坐标写入这个变量中。所有都VS都有将值写入这个变量的运算。在VS结束后,在pipeline,GPU光栅化的时候,这个值会被用于组元装配,即把若干点按照一定的规律组成三角形等形状。跟姐这些顶点坐标,进行裁剪、剔除(判断属于物体的内表面还是外表面,根据规则可不对物体的外表面或内表面进行绘制,相应的顶点需被剔除),没有赋值则为undefine,此时被读取编译器提示。
是一个vec4变量,精度为highp

gl_PointSize:
点的大小
只存在于VS中。属于VS的内置变量,说明点的尺寸,单位是像素。(若变量设为4,则代表2*2的像素方块)没有赋值虽然为undefine,但光栅化时默认值1来处理,通常设置绘图为点绘制才有意义。一般不用重新赋值。
是float值,精度为mediump

gl_FragColor
当前片元颜色,即写入该像素点的颜色
是一个 vec4,精度是 mediump

gl_FragData
vec4类型的数组。包含 gl_MaxDrawBuffers 个值。向其写入的信息,供渲染管线的后继过程使用。精度是 mediump

gl_FragColor和gl_FragData都为PS的输出参数,否则经过PS计算后将被传给OpenGL ES,参与到OpenGL ES的固定管线中。可以给两者任一赋值,但不能同时赋值。若shader执行了discard,则两者的值都会被舍弃。

gl_FragCoord
当前片元相对窗口位置所处的坐标。
PS的输入参数,只读。是vec4。分别对应x,y,z,1/w。
x,y为当前片元窗口的相对坐标。非整数,小数不分恒为0.5 。x - 0.5 和 y - 0.5 分别位于[0, windowWidth - 1]和[0, windowHeight - 1]内。windowWidth 和 windowHeight 都以像素为单位,即 glViewPort 指定的宽高。
z是固定管线计算出的当前片元的深度。位于[0.0,0.1]间。如果用gl_FragColor = vec4(vec3(gl_FragCoord.z), 1.0)将其可视化,多半会看到一片白。这是由于变换的非线性,大多数点的深度都非常接近于 1。用 gl_FragColor = vec4(vec3(pow(gl_FragColor.z, exp)), 1.0)并将 exp 取为合适的值,就能看到从黑到白的深度变化了。距离观察者近的颜色深,接近 0.0;距离观察者远的颜色浅, 接近 1.0
z/w可得到当前片元和camera间的距离
是一个 vec4,精度是 mediump

gl_FrontFacing
bool型,
PS的输入参数,只读。选择顶点属于几何物体(光栅化生成此片元的对应图元)的正反面,true为正,false为反。例如,从两种光照选择一个来模仿物体的两面光照。

gl_PointCoord
PS的输入参数。只读。二维坐标,指出该点组元的当前像素点位置,若当前组元不是点,则gl_PointCoord为undefine
是vec2,精度是mediump

上述内置变量都为全局变量

内置常量

gl_MaxVertexAttribs 值为8
VS 中至少要支持不能超过 gl_MaxVertexAttribs 这么多的 attribute。即任一硬件必须生成超过8个位置给attribute。
若使用超过8个attribute,要调用api查看当前设备是否支持

gl_MaxVertexUniformVectors 值为 128 (vec4)
gl_MaxFragmentUniformVectors 值为16
gl_MaxVertexUniformVectors 定义了 VS 中至少需要支持不超过 gl_MaxVertexUniformVectors 个的 uniform
第二个常量 gl_MaxFragmentUniformVectors 定义了 PS 中至少需要支持不超 过 gl_MaxFragmentUniformVectors 个的 uniform
VS支持128个vec4,若使用了129个float的uniform或者33个mat4的uniform都会报错

gl_MaxVaryingVectors
varying 变量同时存在于 VS 和 PS 中才算有意义,因此不区分VS和PS。即一对shader中,最多只能存在gl_MaxVaryingVectors个varing变量。计量标准也是vec4

假如定义了未被使用的attribute、uniform、varing,会被优化掉,是不会被计入计算限制的数量中。

gl_MaxVertexTextureImageUnits 值为0
VS中可用纹理单元的最大数量.。VS基本不使用texture,texture基本在PS中用,所以为0

gl_MaxCombinedTextureImageUnits 值为8
VS/PS的可用纹理单元的最大数量的总和。VS和PS两个一样的uniform被认为是一个uniform,称为combine
texture一般作为uniform传入,因为基本在PS中使用,若通过attribute传入VS,在通过varing传入PS,比较复杂,且varing是需要被光栅化处理的,所以varing越少,性能越好。

gl_MaxTextureImageUnits
可用纹理图像单元的最大数量

gl_MaxDrawBuffers
指最多可支持的绘制buffer,即多重渲染目标最大支持数量.

gl_DepthRange
是窗口坐标中的深度范围,用于存放在三维空间中的视野空间中的深度范围
一个特殊的内置变量,一个内置uniform。这个变量就是一个uniform(上述的变量常量是独立于attribute、varing
uniform)类型是一个 struct gl_DepthRangeParameters,该 struct 有三个成员变量,分别是 near、far、 diff。

struct gl_DepthRangeParameters
{
highp float near; //near z  
highp float far; //near far 
highp float diff; //far - near  
};
}uniform gl_DepthRangeParameters gl_DepthRange;

由于默认 PS 是不支持 high 的,所以在这些设备中,这三个成员变量就相当于精度修饰符为 mediump

由于gl_DepthRange占用一个uniform的名额,实际开发者在VS中只能定义127个uniform

内置函数
matrixCompMult(x,y):将矩阵相乘
lessThan(x,y):返回向量xy的各个分量执行x< y的结果,类似的有greaterThan,equal,notEqual
lessThanEqual(x,y):返回向量xy的各个分量执行x<= y的结果,类似的有类似的有greaterThanEqual
any(bvec x):x有一个元素为true,则为true
all(bvec x):x所有元素为true,则返回true,否则返回false
not(bvec x):x所有分量执行逻辑非运算

length(x):计算向量x的长度
distance(x,y):返回向量xy之间的距离
dot(x,y):返回向量xy的点积
cross(x,y):返回向量xy的差积
normalize(x):返回与x向量方向相同,长度为1的向量

纹理采样函数有texture2D、texture2DProj、texture2DLod、texture2DProjLod、textureCube、textureCubeLod及texture3D、texture3DProj、texture3DLod、texture3DProjLod等。
texture表示纹理采样,2D表示对2D纹理采样,3D表示对3D纹理采样
Lod后缀,只适用于顶点着色器采样
Proj表示纹理坐标st会除以q
texture2D拥有三个参数,第一个参数表示纹理采样器。第二个参数表示纹理坐标,可以是二维、三维、或者四维。第三个参数加入后只能在片元着色器中调用,且只对采样器为mipmap类型纹理时有效。
texture2DProj 函数,传入的纹理坐标区别于刚才的 vec2,而使用 vec3 和 vec4。 与刚才纹理坐标的区别是,这里虽然传入 vec3 或者 vec4,但是也是当作 vec2 使 用的,只是前两个成员会除以 vec3 或者 vec4 的最后一个成员

上一篇:vs 在线安装,无法连接到网络


下一篇:cf1198 C. Matching vs Independent Set(思维)