欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)

LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)

2025/5/11 17:00:01 来源:https://blog.csdn.net/zaizai1007/article/details/144410606  浏览:    关键词:LearnOpenGL学习(高级OpenGL -> 高级GLSL,几何着色器,实例化)

高级GLSL

内建变量

顶点着色器

gl_PointSoze : float 输出变量,用于控制渲染 GL_POINTS 型图元时,点的大小。可用于粒子系统。将其设置为 gl_Position.z 时,可以使点的距离越远,大小越大。创建出类似近视眼看远处灯光的效果

glEnable(GL_PROGRAM_POINT_SIZE);   //也是需要开启

void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);    gl_PointSize = gl_Position.z;    
}

gl_vertexID: int 型输入变量(只读),存储了正在绘制顶点的ID(当(使用glDrawElements)进行索引渲染的时候,这个变量会存储正在绘制顶点的当前索引。当(使用glDrawArrays)不使用索引进行绘制的时候,这个变量会储存从渲染调用开始的已处理顶点数量。)

片段着色器

gl_FragCoord: vec4型输出变量。存储了屏幕空间坐标(x,y ,以窗口左下角为原点)和图元深度值(z,0 - 1).常用来获取深度值。

我们已经使用glViewport设定了一个800x600的窗口了,所以片段窗口空间坐标的x分量将在0到800之间,y分量在0到600之间。

void main()
{             if(gl_FragCoord.x < 400)FragColor = vec4(1.0, 0.0, 0.0, 1.0);elseFragColor = vec4(0.0, 1.0, 0.0, 1.0);        
}

gl_FrontFacing:  bool 型输入变量。标记了当前图元是否为正面

#version 330 core
out vec4 FragColor;in vec2 TexCoords;uniform sampler2D frontTexture;
uniform sampler2D backTexture;void main()
{             if(gl_FrontFacing)FragColor = texture(frontTexture, TexCoords);elseFragColor = texture(backTexture, TexCoords);
}

给立方体里外使用不同的纹理:

 

gl_FragDepth :float 型输出变量。用于手动设置片段的深度值。在片段着色器中出现后,Early-Z 将被禁用

gl_FragDepth = 0.0; // 这个片段现在的深度值为 0.0
//如果着色器没有写入值到gl_FragDepth,它会自动取用gl_FragCoord.z的值。

从OpenGL 4.2起,我们仍可以对两者进行一定的调和,在片段着色器的顶部使用深度条件(Depth Condition)重新声明gl_FragDepth变量:

layout (depth_<condition>) out float gl_FragDepth;

这样子的话,当深度值比片段的深度值要小的时候,OpenGL仍是能够进行提前深度测试的。

接口块

但当程序变得更大时,你希望发送的可能就不只是几个变量了,它还可能包括数组和结构体。

接口块的声明和struct的声明有点相像,不同的是,现在根据它是一个输入还是输出块(Block),使用inout关键字来定义的。

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;out VS_OUT
{vec2 TexCoords;
} vs_out;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);    vs_out.TexCoords = aTexCoords;
}

这次我们声明了一个叫做vs_out的接口块,它打包了我们希望发送到下一个着色器中的所有输出变量

之后,我们还需要在下一个着色器,即片段着色器,中定义一个输入接口块。

#version 330 core
out vec4 FragColor;in VS_OUT
{vec2 TexCoords;
} fs_in;uniform sampler2D texture;void main()
{             FragColor = texture(texture, fs_in.TexCoords);   
}

只要两个接口块的名字一样,它们对应的输入和输出将会匹配起来。这是帮助你管理代码的又一个有用特性,它在几何着色器这样穿插特定着色器阶段的场景下会很有用。

Uniform 缓冲对象

OpenGL为我们提供了一个叫做Uniform缓冲对象(Uniform Buffer Object)的工具,它允许我们定义一系列在多个着色器程序中相同的全局Uniform变量。当使用Uniform缓冲对象的时候,我们只需要设置相关的uniform一次

因为Uniform缓冲对象仍是一个缓冲,我们可以使用glGenBuffers来创建它,将它绑定到GL_UNIFORM_BUFFER缓冲目标,并将所有相关的uniform数据存入缓冲。在Uniform缓冲对象中储存数据是有一些规则的

#version 330 core
layout (location = 0) in vec3 aPos;layout (std140) uniform Matrices
{mat4 projection;mat4 view;
};uniform mat4 model;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);
}

这里,我们声明了一个叫做Matrices的Uniform块,它储存了两个4x4矩阵。Uniform块中的变量可以直接访问,不需要加块名作为前缀。

接下来,我们在OpenGL代码中将这些矩阵值存入缓冲中,每个声明了这个Uniform块的着色器都能够访问这些矩阵。

其中,layout(std140) 指定了Uniform块布局。默认情况下,Uniform块布局是Shared型,这类布局的各变量偏移量会随设备和系统的不同而变化。但我们希望Uniform块中各变量的偏移量能被手工计算出,以便让块内各变量能与UBO中各变量相对应。std140布局便是我们需要的。

在std140布局中,每个变量都有一个基准对齐量(Base Alignment),它是一个变量在Uniform块中占据的空间。每个变量还有一个对齐偏移量(Aligned Offset),它是一个变量从块起始位置的偏移量,它必须是Base Alignment的倍数。简而言之,前者是size,后者是offset。

Uniform 块布局

Uniform块的内容是储存在一个缓冲对象中的,它实际上只是一块预留内存。因为这块内存并不会保存它具体保存的是什么类型的数据,我们还需要告诉OpenGL内存的哪一部分对应着着色器中的哪一个uniform变量。

假设着色器中有以下的这个Uniform块:

layout (std140) uniform ExampleBlock
{float value;vec3  vector;mat4  matrix;float values[3];bool  boolean;int   integer;
};

4 字节是 1 N

layout (std140) uniform ExampleBlock
{// 基准对齐量       // 对齐偏移量float value;     // 4               // 0 vec3 vector;     // 16              // 16  (必须是16的倍数,所以 4->16)mat4 matrix;     // 16              // 32  (列 0)// 16              // 48  (列 1)// 16              // 64  (列 2)// 16              // 80  (列 3)float values[3]; // 16              // 96  (values[0])// 16              // 112 (values[1])// 16              // 128 (values[2])bool boolean;    // 4               // 144int integer;     // 4               // 148
}; 

使用 Uniform 缓冲

我们已经讨论了如何在着色器中定义Uniform块,并设定它们的内存布局了,但我们还没有讨论该如何使用它们。

首先,我们需要调用glGenBuffers,创建一个Uniform缓冲对象。一旦我们有了一个缓冲对象,我们需要将它绑定到GL_UNIFORM_BUFFER目标,并调用glBufferData,分配足够的内存。

unsigned int uboExampleBlock;
glGenBuffers(1, &uboExampleBlock);
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
glBufferData(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // 分配152字节的内存
glBindBuffer(GL_UNIFORM_BUFFER, 0);

参考:高级GLSL - LearnOpenGL CN

LearnOpenGL学习笔记(十) - 高级GLSL、几何着色器、实例化与抗锯齿 - Yoi's Home

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词