首页 > 其他分享 >OpenGL学习(三)——GLSL

OpenGL学习(三)——GLSL

时间:2024-01-30 10:23:06浏览次数:19  
标签:GLSL OpenGL float 学习 vec4 bvec genType gl 着色器

OpenGL学习(三)——GLSL

参考资料:

GLSL

着色器(Shader)是运行在GPU上的小程序,用来完成渲染管线的一个环节。从基本意义上来说,着色器只是一种把输入转化为输出的程序。

着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。

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

数据类型

基础数据类型:intfloatdoubleuintbool

3种容器类型:向量(Vector)、矩阵(Matrix)和纹理采样器(Sampler)

结构体类型:和C语言一样,只是不支持嵌套定义

数组类型:和C语言一样

内建变量

向量

向量是一个可以包含有2、3或者4个分量的容器,分量的类型是基础类型中的一种。

类型 含义
vecn 包含n个float分量的向量(即默认是float类型)
bvecn 包含n个bool分量的向量
ivecn 包含n个int分量的向量
uvecn 包含n个unsigned int分量的向量
dvecn 包含n个double分量的向量

其中n代表分量的数量

获取分量:通过.x.y.z.w来获取它们的第1、2、3、4个分量。也允许你对颜色使用rgba,或是对纹理坐标使用stpq访问相同的分量。

向量重组
vec2 a(1.0, 2.0);
vec4 b = a.xyxx;
vec3 c = (a, 3.0)
vec4 d = a.xxxx + c.yxzy;

矩阵

类型 含义
mat2 或者 mat2x2 2×2的浮点数矩阵类型
mat3或者mat3x3 3×3的浮点数矩阵类型
mat4x4 4×4的浮点矩阵
mat2x3 2列3行的浮点矩阵(OpenGL的矩阵是列主顺序的)
mat2x4 2列4行的浮点矩阵
mat3x2 3列2行的浮点矩阵
mat3x4 3列4行的浮点矩阵
mat4x2 4列2行的浮点矩阵
mat4x3 4列3行的浮点矩阵

纹理采样器

类型 含义
sampler1D 用于内建的纹理函数中引用指定的1D纹理的句柄。只可以作为一致变量或者函数参数使用
sampler2D 二维纹理句柄
sampler3D 三维纹理句柄
samplerCube cube map纹理句柄
sampler1DShadow 一维深度纹理句柄
sampler2DShadow 二维深度纹理句柄

内建变量

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

名称 类型 描述
gl_Color vec4 输入属性-表示顶点的主颜色
gl_SecondaryColor vec4 输入属性-表示顶点的辅助颜色
gl_Normal vec3 输入属性-表示顶点的法线值
gl_Vertex vec4 输入属性-表示物体空间的顶点位置
gl_MultiTexCoordn vec4 输入属性-表示顶点的第n个纹理的坐标
gl_FogCoord float 输入属性-表示顶点的雾坐标
gl_Position vec4 输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。
gl_ClipVertex vec4 输出坐标,用于用户裁剪平面的裁剪
gl_PointSize float 点的大小
gl_FrontColor vec4 正面的主颜色的varying输出
gl_BackColor vec4 背面主颜色的varying输出
gl_FrontSecondaryColor vec4 正面的辅助颜色的varying输出
gl_BackSecondaryColor vec4 背面的辅助颜色的varying输出
gl_TexCoord[] vec4 纹理坐标的数组varying输出
gl_FogFragCoord float 雾坐标的varying输出

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

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

修饰符

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

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

函数

每个shader中必须有一个main函数,其他和C语言一样。

内置函数

角和三角函数
语法 说明
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)
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小节详细描述了这一点。

基本程序结构

#版本声明
对于定点着色器用layout关键字
输入变量声明;
输出变量声明;

void main() {
    执行代码逻辑
    为内置变量、输入变量和输出变量赋值
}

输入与输出

每个着色器都有输入和输出,这样才能进行数据交流和传递。

  • in 关键字:指定输入变量
  • out 关键字:指定输出变量

只要指定的输出变量与下一个着色器的输入变量匹配,就能实现流水线式的传递。匹配的要求是变量类型和变量名都一样

对于顶点着色器:需要加一个 layout 标识,并且指定 location = 0 。不指定的话就要通过在OpenGL代码中使用glGetAttribLocation查询属性位置值(Location)

对于片段着色器:需要一个 vec4 的颜色输出变量。

CPU与GPU通信——CPU更改着色器中的变量

使用Uniform来实现CPU中的程序向GPU中的着色器发送数据。Uniform是全局的,因此不需要通过流水线式的 in/out 来传递,而是可以直接在任何一个着色器中直接访问。

通过在变量定义前加上 uniform 来将变量声明为Uniform。然后在CPU程序中先需要找到着色器中uniform属性的索引/位置值。当我们得到uniform的索引/位置值后,我们就可以更新它的值了。

如果你声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误

while(!glfwWindowShouldClose(window))
{
    // 输入
    processInput(window);

    // 渲染
    // 清除颜色缓冲
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // 记得激活着色器
    glUseProgram(shaderProgram);

    // 更新uniform颜色
    float timeValue = glfwGetTime();
    float rgbGreenValue = sin(timeValue) / 2.0f + 0.5f;
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
    glUniform4f(vertexColorLocation, 0.0f, rgbGreenValue, 0.0f, 1.0f); // 设置vec4的4个分量的值

    // 绘制三角形
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 交换缓冲并查询IO事件
    glfwSwapBuffers(window);
    glfwPollEvents();
}

glUniform 函数的后缀选择:

后缀 含义
f 函数需要一个float作为它的值
i 函数需要一个int作为它的值
ui 函数需要一个unsigned int作为它的值
3f 函数需要3个float作为它的值,其他个数以此类推
fv 函数需要一个float向量作为它的值

注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先启用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的。

标签:GLSL,OpenGL,float,学习,vec4,bvec,genType,gl,着色器
From: https://www.cnblogs.com/3to4/p/17996545

相关文章

  • Power BI - 5分钟学习创建合并列
    每天5分钟,今天介绍PowerBI如何创建合并列什么是合并列顾名思义合并列就是把两个列信息拼接到一个列中显示。工作中经常会有类似需求,把产品编码和产品名称放到一个筛选器或者单元格中展示。那我们在PowerBI中应该如何进行类似创建合并列的操作呢?首先导入样例产品表;(Excel数据......
  • 非内积级联学习
    1.首页推荐非内积召回现状非内积召回源是目前首页推荐最重要的召回源之一。同时非内积相比于向量化召回最终仅将user和item匹配程度表征为embeding内积,非内积召回仅保留itemembedding,不构造user显式表征,而是通过一个打分网络计算用户-商品匹配程度,极大的提升了模型精准度的上限,......
  • Unity3D DrawCall和openGL、光栅化等有何内在联系详解
    Unity3D是一款跨平台的游戏引擎,广泛应用于游戏开发领域。在Unity3D中,DrawCall是一个重要的概念,它与OpenGL、光栅化等技术有着密切的内在联系。本文将详细解释DrawCall的概念,并给出相关技术的详细解释和代码实现。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础......
  • 寒假学习15
    今天接着学习声音转换训练: 点击脚本可以查看转换进度: http://localhost:6006/在转换声音数据的时候显示错误 问了问gpt:还是无法解决。......
  • ControlNet学习实战1--字体海报
    最近玩AI绘画的过程中,突然发现了一个可以生成特点字体海报的技巧,特此记录学习一下。本片文章介绍大家制作一张2024龙年海报。ControlNet介绍ControlNet是一个应用于Stable_diffusion一个插件,该插件可以让AI更加精准的生成准确的想要的图片,关于这些内容后期会专门更加细致的说明......
  • Java学习(day1)
    注释单行注释`//publicclass多行注释/*publicclasshellopvsm*/文档注释~~~(没啥用)/**213213**/标识符首字符可以字母、下划线、美元符(不能是数字和其他符号)StringAhello="Q";Stringheloo="Q";String$he="Q";String_hello="Q";大小写敏感......
  • 大三寒假学习进度笔记20
    今日对LangChain进行了一些了解。LangChain是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序。它提供了一套工具、组件和接口,可简化创建由大型语言模型(LLM)和聊天模型提供支持的应用程序的过程。LangChain可以轻松管理与语言模型的交互,将多个组件链接在一......
  • 【实战项目】想自己通过C语言编写贪吃蛇吗?先来学习一下什么是WIN32API
    WIN32API前言大家好,很高兴又和大家见面了!!!在开始今天的内容前,咱们先闲聊一下。博主是从2023.8.19号晚上23:28左右正式开始接触C语言,在此之前,我也只是一个对编程一窍不通的小白,我的本科专业是给排水科学与工程,一个就业前景还不错但是不太适合我本人的专业。在经历了一些事情之后,我......
  • 李宏毅《机器学习》总结 - RNN & LSTM
    在slot-filling问题(如给一个句子,自己分析出时间、地点等)如果只连着不同的FC,那么会导致无法读出是arrive还是leave的情况,导致错误因此,需要NN来考虑到整个句子的信息,也就是需要有memory,这就是RNNRNN原理有了memory,就可以初步解决同一个信息由于句子不同导致的意......
  • Java编程学习(intellij idea)
    打开IntelliJIDEA新建Project新建Module新建Package输入Package名,enter新建JavaClass在Class中编程......