这一章编程实践的内容不多,主要是glsl高级的语言特征。原教程写的很好了。learnopengl-高级glsl
这一节代码实践不多,阅读一遍,重在理解,做个笔记,加强记忆。
一、GLSL内建变量
1. 顶点着色器变量
- gl_PointSize 设置顶点大小,默认禁用修改,DEMO:
// 主程序
glEnable(GL_PROGRAM_POINT_SIZE);
//着色器
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
gl_PointSize = gl_Position.z;
}
- gl_VertexID,基本没什么用,可读不可写,存储了正在绘制顶点的当前ID
2. 片段着色器变量
- gl_FragCoord,x和y分量是片段的窗口控件坐标,原点在左下角,可以通过gl_FragCoord分量对输出颜色做些特殊处理,DEMO:
void main()
{
if(gl_FragCoord.x < 400)
FragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
gl_FragCoord使用
- gl_FrontFacing,判断正向还是背向,和面剔除有相同的功效,demo:
// 根据前脸还是后脸输出不同的纹理
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D frontTexture;
uniform sampler2D backTexture;
void main()
{
if(gl_FrontFacing)
FragColor = texture(frontTexture, TexCoords);
else
FragColor = texture(backTexture, TexCoords);
}
gl_FrontFacing使用
- gl_FragDepth,这个稍微复杂点,可以用来修改片段的Z坐标,即深度值,如果没有设置gl_FragDepth,默认的回取gl_FragCoord.z。
gl_FragDepth有个缺陷,会导致提前深度测试冲突禁用,原理很好理解,因为只要到真正片段着色器运行才知道实际的深度值,提前深度测试没有意义。从4.2版本开始有个折中的方案,定义gl_FragDepth变量的规则,提供给提前深度测试参考,做个粗略的评估
layout (depth_<condition>) out float gl_FragDepth;
condition的值
demo:
#version 420 core // 注意GLSL的版本!
out vec4 FragColor;
layout (depth_greater) out float gl_FragDepth;
void main()
{
FragColor = vec4(1.0);
gl_FragDepth = gl_FragCoord.z + 0.1;
}
二、接口块
类似c语言中的struct,java中的类,不过多赘述,上代码,一看就明白,注意in和out的定义
#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;
}
三、Uniform缓冲对象
主要讲Uniform块,稍微复杂了点,可以简单理解为类的静态变量,所有类对象可以共享,在opengl特殊的编程环境下整的略复杂。重点是理解内存对齐的策略和绑定的关系。
1. 内存绑定关系,不同的shader可以绑定到相同的uniform缓冲对象上
内存绑定关系分三步,创建uniform缓冲对象-->绑定shader对应uniform 字段到绑定点-->uniform缓冲对象绑定到相同的绑定点。关键代码:
// 生成uniform 缓冲对象
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);
// 将shader中的uniform字段绑定到相同的“绑定点”
unsigned int lights_index = glGetUniformBlockIndex(shaderA.ID, "Lights");
glUniformBlockBinding(shaderA.ID, lights_index, 2);
// 有两种方式,第二种稍微灵活点,可以支持更多的复用和拓展场景
glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock);
// 或
glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
2. 理解Uniform块的每个成员的对齐偏移量,理解下面这段代码就可以了。
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 // 144
int integer; // 4 // 148
};
网友评论