ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Shader(GLSL)

2022-01-22 23:02:08  阅读:377  来源: 互联网

标签:GLSL PS 变量 Shader uniform vec4 VS gl


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
在这里插入图片描述

恒定修饰符
两个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 的最后一个成员

标签:GLSL,PS,变量,Shader,uniform,vec4,VS,gl
来源: https://blog.csdn.net/Mhypnos/article/details/122621162

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有