opengl高级GLSL |
您所在的位置:网站首页 › 1000个比较难拼的字的拼音小学 › opengl高级GLSL |
GLSL的内建变量
着色器都是最简化的,如果需要当前着色器以外地方的数据的话,我们必须要将数据传进来。我们已经学会使用顶点属性、uniform和采样器来完成这一任务了。然而,除此之外,GLSL还定义了另外几个以gl_为前缀的变量,它们能提供给我们更多的方式来读取/写入数据。 顶点着色器变量gl_Position,它是顶点着色器的裁剪空间输出位置向量。如果你想在屏幕上显示任何东西,在顶点着色器中设置gl_Position是必须的步骤。 GLSL定义了一个叫做gl_PointSize输出变量,它是一个float变量,你可以使用它来设置点的宽高(像素)。在顶点着色器中修改点的大小的话,你就能对每个顶点设置不同的值了。 在顶点着色器中修改点大小的功能默认是禁用的,如果你需要启用它的话,你需要: glEnable(GL_PROGRAM_POINT_SIZE);顶点着色器还为我们提供了一个有趣的输入变量,我们只能对它进行读取,它叫做gl_VertexID。当(使用glDrawElements)进行索引渲染的时候,这个变量会存储正在绘制顶点的当前索引。当(使用glDrawArrays)不使用索引进行绘制的时候,这个变量会储存从渲染调用开始的已处理顶点数量。 片段着色器变量gl_FragCoord的x和y分量是片段的窗口空间(Window-space)坐标,其原点为窗口的左下角。z分量等于对应片段的深度值。 gl_FrontFacing,如果我们不(启用GL_FACE_CULL来)使用面剔除,那么gl_FrontFacing将会告诉我们当前片段是属于正向面的一部分还是背向面的一部分。 gl_FrontFacing变量是一个bool,如果当前片段是正向面的一部分那么就是true,否则就是false。比如说,我们可以这样子创建一个立方体,在内部和外部使用不同的纹理: #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_FragDepth,输入变量gl_FragCoord能让我们读取当前片段的窗口空间坐标,并获取它的深度值,但是它是一个只读(Read-only)变量。我们不能修改片段的窗口空间坐标,但实际上修改片段的深度值还是可能的。GLSL提供给我们一个叫做gl_FragDepth的输出变量,我们可以使用它来在着色器内设置片段的深度值。 要想设置深度值,我们直接写入一个0.0到1.0之间的float值到输出变量就可以了: gl_FragDepth = 0.0; // 这个片段现在的深度值为 0.0如果着色器没有写入值到gl_FragDepth,它会自动取用gl_FragCoord.z的值。 然而,由我们自己设置深度值有一个很大的缺点,只要我们在片段着色器中对gl_FragDepth进行写入,OpenGL就会禁用所有的提前深度测试(Early Depth Testing)。它被禁用的原因是,提前深度测试在片段着色器之前运行。 接口块GLSL为我们提供了一个叫做接口块(Interface Block)的东西,来方便我们管理着色器输入输出变量。 #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; }之后,我们还需要在下一个着色器,即片段着色器,中定义一个输入接口块,块名(Block Name)应该是和着色器中一样的(VS_OUT),但实例名(Instance Name)(顶点着色器中用的是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一次。 #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); }因为Uniform缓冲对象仍是一个缓冲,我们可以使用glGenBuffers来创建它,将它绑定到GL_UNIFORM_BUFFER缓冲目标,并将所有相关的uniform数据存入缓冲。在Uniform缓冲对象中储存数据是有一些规则的,一般使用std140布局。 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);现在,每当我们需要对缓冲更新或者插入数据,我们都会绑定到uboExampleBlock,并使用glBufferSubData来更新它的内存。我们只需要更新这个Uniform缓冲一次,所有使用这个缓冲的着色器就都使用的是更新后的数据了。但是,如何才能让OpenGL知道哪个Uniform缓冲对应的是哪个Uniform块呢? 在OpenGL上下文中,定义了一些绑定点(Binding Point),我们可以将一个Uniform缓冲链接至它。在创建Uniform缓冲之后,我们将它绑定到其中一个绑定点上,并将着色器中的Uniform块绑定到相同的绑定点,把它们连接到一起。下面的这个图示展示了这个: 接下来,我们还需要绑定Uniform缓冲对象到相同的绑定点上,这可以使用glBindBufferBase或glBindBufferRange来完成。 glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock); // 或 glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152); |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |