【OpenGL手册-20】GL Shader Language(GLSL)语法基础

2024-03-24 12:28

本文主要是介绍【OpenGL手册-20】GL Shader Language(GLSL)语法基础,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 一、说明
  • 二、变量‍
    • 2.1基本类型
    • 2.2内置变量
    • 2.3修饰符
    • 2.4 数组‍
    • 3.5 结构体‍
  • 三、表达式
    • 3.1操作符
    • 3.2 运算符‍
    • 3.3 数组访问‍
  • 四、控制流‍
    • 4.1 循环‍
    • 4.2 控制语句‍
  • 五、函数
    • 5.1自定义函数
    • 5.2内置函数

一、说明

该教程是跟着色器语言相关,在接下来的文章中我们将会分两节详细讲解着色器语言GL Shader Language(GLSL)的一些基本概念和语法知识。这期教程可以说是干货满满的一期了,希望能够帮助大家了解着色器语言。

在可编程管线中,必须使用GLSL编写顶点着色器和片源着色器,而GLSL的语法和C语言有很多相似之处,本篇文章将介绍GLSL的基础语法。更多细节和说明可以查阅官方文档

在VSCode中可以创建后缀为.glsl的文件编写着色器代码,并通过ShaderToy进行实时预览调试。

二、变量‍

GLSL的命名规范建议使用驼峰式,命名规则和C语言类似。 GLSL的变量名称可以使用字母,数字以及下划线,不能以数字开头, gl_作为GLSL保留前缀只能用于内部变量。还有一些GLSL内置函数名称是不能够作为变量的名称。

2.1基本类型

下表是GLSL的基本数据类型:

数据类型描述
void跟C语言的void类似,表示空类型。作为函数的返回类型,表示这个函数不返回值。
bool布尔类型,可以是true 和false,以及可以产生布尔型的表达式。
int整型 代表至少包含16位的有符号的整数。可以是十进制的,十六进制的,八进制的。
float浮点型
bvec2包含2个布尔成分的向量
bvec3包含3个布尔成分的向量
bvec4包含4个布尔成分的向量
ivec2包含2个整型成分的向量
ivec3包含3个整型成分的向量
ivec4包含4个整型成分的向量
mat2或者 mat2x2 2×2的浮点数矩阵类型
mat3或者mat3x33×3的浮点数矩阵类型
mat4x44×4的浮点矩阵
mat2x32列3行的浮点矩阵(OpenGL的矩阵是列主顺序的)
mat2x42列4行的浮点矩阵
mat3x23列2行的浮点矩阵
mat3x43列4行的浮点矩阵
mat4x24列2行的浮点矩阵
mat4x34列3行的浮点矩阵
sampler1D用于内建的纹理函数中引用指定的1D纹理的句柄。只可以作为一致变量或者函数参数使用
sampler2D二维纹理句柄
sampler3D三维纹理句柄
samplerCubecube map纹理句柄
sampler1DShadow一维深度纹理句柄
sampler2DShadow二维深度纹理句柄

2.2内置变量

定点着色器可用的内置变量如下表:

名称类型描述
gl_Colorvec4输入属性-表示顶点的主颜色
gl_SecondaryColorvec4输入属性-表示顶点的辅助颜色
gl_Normalvec3输入属性-表示顶点的法线值
gl_Vertexvec4输入属性-表示物体空间的顶点位置
gl_MultiTexCoordnvec4输入属性-表示顶点的第n个纹理的坐标
gl_FogCoordfloat输入属性-表示顶点的雾坐标
gl_Positionvec4输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。
gl_ClipVertexvec4输出坐标,用于用户裁剪平面的裁剪
gl_PointSizefloat点的大小
gl_FrontColorvec4正面的主颜色的varying输出
gl_BackColorvec4背面主颜色的varying输出
gl_FrontSecondaryColorvec4正面的辅助颜色的varying输出
gl_BackSecondaryColorvec4背面的辅助颜色的varying输出
gl_TexCoord[]vec4纹理坐标的数组varying输出
gl_FogFragCoordfloat雾坐标的varying输出

片段着色器的内置变量如下表:

名称类型描述
gl_Colorvec4包含主颜色的插值只读输入
gl_SecondaryColorvec4包含辅助颜色的插值只读输入
gl_TexCoord[]vec4包含纹理坐标数组的插值只读输入
gl_FogFragCoordfloat包含雾坐标的插值只读输入
gl_FragCoordvec4只读输入,窗口的x,y,z和1/w
gl_FrontFacingbool只读输入,如果是窗口正面图元的一部分,则这个值为true
gl_PointCoordvec2点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。
gl_FragData[]vec4使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。
gl_FragColorvec4输出的颜色用于随后的像素操作
gl_FragDepthfloat输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替

2.3修饰符

变量的声明可以使用如下的修饰符:

修饰符描述
const常量值必须在声明时初始化。它是只读的不可修改的。
attribute表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能在函数内部。一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或者结构体
uniform一致变量。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。
varying顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。
centorid varying在没有多重采样的情况下,与varying是一样的意思。在多重采样时,
centorid varying在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。
invariant(不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。
in用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。(相当于C语言的传值),这个是函数参数默认的修饰符
out用在函数的参数中,表示该参数是输出参数,值是会改变的。
inout用在函数的参数,表示这个参数即是输入参数也是输出参数。

2.4 数组‍

GLSL中只能使用一维数组。数组的类型可以是一切基本类型或者结构体。声明方式如下:

vec4 transMatrix[4];
vec4 affineMatrix[4] = {0, 1, 2, 3};
vec4 rotateMatrix = affineMatrix;

3.5 结构体‍

结构体的定义方式和C语言类似,可以组合基本类型和数组来形成用户自定义的类型, 区别是GLSL的结构体不支持嵌套定义,只有预先声明的结构体可以嵌套其中,参考代码如下:

struct rotateMatrix {
float x;
float y;
float z;
float coeff[8];
}struct positionInfo {
vec2 coord;
float value;
rotateMatrix matrix;
}

三、表达式

3.1操作符

GLSL语言的操作符与C语言相似。如下表(操作符的优先级从高到低排列)

操作符描述
()用于表达式组合,函数调用,构造
[]数组下标,向量或矩阵的选择器
.结构体和向量的成员选择
++ –前缀或后缀的自增自减操作符
+ – !一元操作符,表示正 负 逻辑非
* /乘 除操作符
+ -二元操作符 表示加 减操作
<> <= >= == !=小于,大于,小于等于, 大于等于,等于,不等于 判断符
&&
^^逻辑与 ,或, 异或
?: 条件判断符
= += –= *= /=赋值操作符
, 表示序列

位操作符(&,|,^,~, <<, >> ,&=, |=, ^=, <<=, >>=)是GLSL保留的操作符,将来可能会被使用。还有求模操作(%,%=)也是保留的。

3.2 运算符‍

下表显示glsl用到的运算符,如下表(操作符的优先级从高到低排列):

运算符说明结合性
()聚组:a*(b+c)N/A
[] () . ++ –数组下标__[],方法参数__fun(arg1,arg2,arg3),属性访问a.b,自增/减后缀a++ a–L - R
++ – + - !自增/减前缀++a --a,正负号(一般正号不写)a ,-a,取反!falseR - L
* /乘除数学运算L - R
+ -加减数学运算L - R
< > <= >=关系运算符L - R
== !=相等性运算符L - R
&&逻辑与L - R
^^逻辑排他或(用处基本等于!=)L - R
II逻辑或L - R
? :三目运算符L - R
= += -= *= /=赋值与复合赋值L - R
,顺序分配运算L - R

3.3 数组访问‍

和C语言一样, 数组的下标从0开始。取值范围是[0, sizeOfArray - 1]。如果越界了,会提示编译失败。

四、控制流‍

4.1 循环‍

和C语言一样,GLSL语言可以使用for, while, do/while的循环方式,语法和C语言一样,参考下面代码:

for (int s = 0; s < 7; s++) {
vec2 r;
r = vec2(cos(uv.y * i0 - i4 + time / i1), sin(uv.x * i0 - i4 + time / i1)) / i2;
r += vec2(-r.y, r.x) * 0.3;
uv.xy += r;i0 *= 1.93;
i1 *= 1.15;
i2 *= 1.7;
i4 += 0.05 + 0.1 * time * i1;
}

4.2 控制语句‍

GLSL语言可使用if/else语句进行逻辑控制,语法和C语言一致

五、函数

5.1自定义函数

自定义函数规则和C语言差不多,每个shader中必须有一个main函数。参数的修饰符(in, out, inout, const等)是可选的。下面代码示例:

#pragma glslify: snoise = require('glsl-noise/simplex/2d')
float noise(in vec2 pt) {
return snoise(pt) * 0.5 + 0.5;
}
// GLSL的函数是支持重载的。函数可以同名但其参数类型或者参数个数不同即可
float noise(in vec2 pt, in float value) {
return snoise(pt) * 0.5 + value;
}void main () {
float r = noise(gl_FragCoord.xy * 0.01);
float g = noise(gl_FragCoord.xy * 0.01 + 100.0);
float b = noise(gl_FragCoord.xy * 0.01 + 300.0);
gl_FragColor = vec4(r, g, b, 1);
}

5.2内置函数

角和三角函数

语法说明
genType radians (genType degrees)角度转弧度(degrees to radians)
genType degrees (genType radians)弧度转角度(radians to degrees)
genType sin (genType angle)三角函数-正弦sine
genType cos (genType angle)三角函数-余弦cosine
genType tan (genType angle)三角函数-正切tangent
genType asin (genType x)反三角函数-反正弦arc sine
genType atan (genType y, genType x)反三角函数-反余弦arc cosine
genType atan (genType y_over_x)反三角函数-反正切arc tangent

指数函数

语法说明
genType pow (genType x, genType y)x的y次方,(x^y)。如果x<0,则结果是undefined;如果x=0并且y<=0,则结果是undefined
genType exp (genType x)x的自然指数,(e^x)
genType log (genType x)x的自然对数,(\log_ex),即(\ln{x})x<=0时结果是undefined
genType exp2 (genType x)2的x次方,(2^x)
genType log2 (genType x)以2为底,x的自然对数,(log_2x),x<=0时结果是undefined
genType sqrt (genType x)对x进行开根号,(\sqrt{x}),x<0时结果是undefined
genType inversesqrt (genType x)sqrt的倒数,(\frac{1}{\sqrt x}),x<=0时结果是undefined

常用函数

语法说明
genType abs (genType x)x的绝对值
genType sign (genType x)判断x是正数、负数,还是零
genType floor (genType x)返回不大于x的最大整数
genType ceil (genType x)返回不小于x的最小整数
genType fract (genType x)返回x的小数部分,即x-floor(x)
genType mod (genType x, genType y)返回x – y * floor (x/y)
genType min (genType x, genType y)返回x和y的较小值
genType max (genType x, genType y)返回x和y的较大值
genType clamp (genType x, genType minVal, genType maxVal) min (max (x, minVal), maxVal),如果minVal > maxVal,则返回undefined
genType mix (genType x, genType y, genType a)返回x * (1−a) + y * a
几何函数
语法说明
:--------:-------------:
genType length (genType x)计算向量的长度, (\sqrt{x12+x22+…})
genType distance (genType p0, genType p1)p0和p1之间的距离,即length(p0-p1)
genType dot (genType x, genType y)向量x与向量y的点积
genType cross (vec3 x, vec3 y)向量x与向量y的叉积
genType normalize (genType x)返回向量x对应的单位向量,即方向相同,长度为1
genType faceforward(genType N, genType I, genType Nref)如果dot(Nref, I) < 0,则返回N,否则返回-N
genType reflect (genType I, genType N)I是入射光的方向,N是反射平面的法线,返回值是反射光的方向。I – 2 * dot(N, I) * N。N必须是单位向量。
genType refract(genType I, genType N, float eta)I是入射光的方向,N是反射平面的法线,折射率是eta,返回值是折射后的光线的向量。I和N必须是单位向量。
矩阵函数
语法说明
mat matrixCompMult (mat x, mat y)返回矩阵x乘以矩阵y的结果。例如result[i][j] 等于 x[i][j] * y[i][j]。注意:如果想进行线性代数里的乘法,请使用符号“*”。

向量关系函数

语法说明
bvec lessThan(vec x, vec y) bvec lessThan(ivec x, ivec y)判断x<y
bvec lessThanEqual(vec x, vec y) bvec lessThanEqual(ivec x, ivec y)判断x<=y
bvec greaterThan(vec x, vec y) bvec greaterThan(ivec x, ivec y)判断x>y
bvec greaterThanEqual(vec x, vec y) bvec greaterThanEqual(ivec x, ivec y)判断x>=y
bvec equal(vec x, vec y) bvec equal(ivec x, ivec y) bvec equal(bvec x, bvec y)判断x==y
bvec notEqual(vec x, vec y) bvec notEqual(ivec x, ivec y) bvec notEqual(bvec x, bvec y)判断x!=y
bool any(bvec x)判断x的元素是否有true
bool all(bvec x)判断x的元素是否全部为true
bool not(bvec x)判断x的元素是否全部为false

Texture查找函数

vec4 texture2D (sampler2D sampler, vec2 coord)
vec4 texture2D (sampler2D sampler, vec2 coord, float bias)
vec4 texture2DProj (sampler2D sampler, vec3 coord)
vec4 texture2DProj (sampler2D sampler, vec3 coord, float bias)
vec4 texture2DProj (sampler2D sampler, vec4 coord)
vec4 texture2DProj (sampler2D sampler, vec4 coord, float bias)
vec4 texture2DLod (sampler2D sampler, vec2 coord, float lod)
vec4 texture2DProjLod (sampler2D sampler, vec3 coord, float lod)
vec4 texture2DProjLod (sampler2D sampler, vec4 coord, float lod)
使用texture坐标coord来查找当前绑定到采样器的texture。对于函数名中含有Proj的函数来说,texture的坐标(coord.s,coord.t)会先除以coord的最后一个坐标。对于vec4这种变种来说,坐标的第三个元素直接被忽略。
vec4 textureCube (samplerCube sampler, vec3 coord)
vec4 textureCube (samplerCube sampler, vec3 coord, float bias)
vec4 textureCubeLod (samplerCube sampler, vec3 coord, float lod)
使用coord这个坐标去查找当前绑定到采样器的cube map。coord的方向用来表示去查找cube map的哪一个二维平面。OpenGL说明书的2.0版本的3.8.6小节详细描述了这一点。
以上就是我们今天的教程啦,感兴趣的伙伴们可以关注我们公众号了解更多教程。


这篇关于【OpenGL手册-20】GL Shader Language(GLSL)语法基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/841596

相关文章

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs),如GPT-4、Claude-3和Gemini的快

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

c++基础版

c++基础版 Windows环境搭建第一个C++程序c++程序运行原理注释常亮字面常亮符号常亮 变量数据类型整型实型常量类型确定char类型字符串布尔类型 控制台输入随机数产生枚举定义数组数组便利 指针基础野指针空指针指针运算动态内存分配 结构体结构体默认值结构体数组结构体指针结构体指针数组函数无返回值函数和void类型地址传递函数传递数组 引用函数引用传参返回指针的正确写法函数返回数组