GLSL为什么把早期的varying关键字改为了in/out?

阅读次数 129

我对这个问题一直比较好奇,早期varying的定义不是挺好的么?把一个项目的GLSL代码可以直接复制到另一个项目中,但是后面改为in/out之后,比较早时候写的GLSL代码就得手动把varying改成in/out,不是说我比较懒不愿意这么做,尽管我确实比较懒。但是我更想了解下这背后的原因是啥?

1 Answers

varying 关键字改为 inout 是一种有意的设计决策,主要出于以下几点原因:

  1. 语义清晰varying 关键字在早期 GLSL 中用于表示顶点着色器和片段着色器之间的数据传递。然而,这种语义并不完全明确。通过使用 inout 关键字,开发者可以更清楚地理解数据是在哪个阶段被输入或输出的。

  2. 一致性与扩展性:现代 OpenGL 着色语言设计中,inout 关键字不仅限于顶点着色器和片段着色器之间的数据传递,它们还广泛用于其他类型的着色器(如几何着色器、计算着色器等)中的数据传递。因此,使用统一的 inout 语法则更具一致性,并且易于扩展。

  3. 可读性和维护性:使用 inout 可以使代码更加易读和易于维护。当看到 inout 关键字时,可以立即知道变量的作用域和生命周期,从而更容易理解和调试代码。

  4. 避免混淆:在某些情况下,varying 可能会导致一些混淆。例如,在某些上下文中,它可能被误解为全局变量。而 inout 则明确地指出了变量的作用范围。

总结来说,虽然将 varying 改为 inout 需要对旧代码进行一些修改,但这种改变是为了提高代码的清晰度、一致性和可维护性。长远来看,这对开发者和整个生态系统都是有益的。

比如配合上几何着色器,in/out有更清晰的举例哪个是顶点着色器传递过来的,哪些是为片元着色器输出的?

确实,使用 inout 关键字在配合几何着色器时,可以使代码的意图更加清晰。下面是一个简单的例子来说明这一点。

假设我们有一个顶点着色器、几何着色器和片段着色器。我们将使用 inout 关键字来明确数据的传递方向。

顶点着色器 (Vertex Shader)

#version 330 core

layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;

out vec2 TexCoord; // 输出到几何着色器

void main() {
    gl_Position = vec4(vertexPosition, 1.0);
    TexCoord = vertexTexCoord;
}

几何着色器 (Geometry Shader)

#version 330 core

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

in vec2 TexCoord[];

out vec2 TexCoordGS; // 输出到片段着色器

void main() {
    for (int i = 0; i < 3; i++) {
        TexCoordGS = TexCoord[i];
        gl_Position = gl_in[i].gl_Position;
        EmitVertex();
    }
    EndPrimitive();
}

片段着色器 (Fragment Shader)

#version 330 core

in vec2 TexCoordGS; // 从几何着色器输入

out vec4 FragColor;

uniform sampler2D ourTexture;

void main() {
    FragColor = texture(ourTexture, TexCoordGS);
}

在这个例子中:

  • 在顶点着色器中,TexCoord 是一个 out 变量,它将顶点纹理坐标传递给几何着色器。
  • 在几何着色器中,TexCoord 是一个 in 数组,它接收来自顶点着色器的纹理坐标。TexCoordGS 是一个 out 变量,它将处理后的纹理坐标传递给片段着色器。
  • 在片段着色器中,TexCoordGS 是一个 in 变量,它接收来自几何着色器的纹理坐标。

通过这种方式,每个着色器阶段的数据传递方向非常明确,代码的可读性和可维护性得到了显著提升。