【问题标题】:GLSL - Using custom output attribute instead of gl_PositionGLSL - 使用自定义输出属性而不是 gl_Position
【发布时间】:2023-12-26 00:14:02
【问题描述】:

我目前正在使用着色器 (3.3) 学习 OpenGL。有一件事我似乎无法解决。我已经读过在 OpenGL 3+ 中不推荐使用 gl_Position 和 gl_FragCoords 等内置变量,因此我想使用自己的输出变量。

所以不要这样:

#version 330\n
layout(location=0) in vec2 i_position;
out vec4 o_position;
void main() 
{
    gl_Position = vec4(i_position, 0.0, 1.0);
};

这是我写的:

#version 330\n
layout(location=0) in vec2 i_position;
out vec4 o_position;
void main() 
{
    o_position = vec4(i_position, 0.0, 1.0);
};

着色器在这两种情况下编译都没有问题,但第二个代码只产生空白屏幕。我是否需要以某种方式指定哪个变量是输出变量?

【问题讨论】:

  • 这些built-in variables 都没有被弃用。在核心配置文件(兼容性配置文件)之前,有反映固定管道属性的内置函数,如 gl_Colorgl_Normal 等。
  • 哦,那我很抱歉。我读过一些gl_* 变量已被弃用,并认为它们都是。谢谢你的澄清。无论如何,如何使它与自定义输出变量一起使用?还是只使用 gl_Position 属性来设置顶点位置?
  • 您仍然必须使用gl_Position。该变量很特殊,因为它指定了顶点和片段着色器(裁剪、光栅化等)之间的固定功能块使用的坐标。您不能用您定义的变量替换它。除了@BrettHale 已经提到的示例之外,gl_FragColor 曾经是 fragment 着色器的预定义输出,也已被弃用。
  • 我明白了。我认为如果你可以在片段着色器中指定自定义输出,你可以在顶点着色器中这样做,显然我错了。再次感谢您的澄清。我还有很多东西要学,但到目前为止,OpenGL 一直很有趣。
  • 你可以这样做,但gl_Positiongl_PerVertex 的一部分。更准确地说,它是一个非可选部分,渲染管道中仍有固定功能部分需要gl_PerVertex.gl_Positiongl_FragCoord,正如您所提到的,实际上是根据该变量计算得出的 - 在除以 w 和视口转换之后。

标签: opengl glsl vertex-shader


【解决方案1】:

这主要由 cmets 覆盖,但为了获得适当的答案,让我总结一下核心配置文件中哪些预定义的 GLSL 变量已经消失,哪些仍然存在。

在大多数情况下,预定义变量已从核心配置文件着色器中删除,这是从 API 中删除大部分固定功能管道的直接后果。有很多 uniform 变量反映了根本不存在的状态。典型例子包括:

  • 修复函数转换状态(gl_ModelViewMatrixgl_ProjectionMatrix等)。
  • 照明参数 (gl_Light*)。
  • 材料参数 (gl_Material*)。
  • 剪切平面 (gl_Clip*)。

同样,接收固定函数顶点属性的顶点着色器输入已消失,因为核心配置文件仅支持通用属性。其中包括gl_Vertexgl_Normalgl_Color 等。

以前也有一些预定义的varying 变量,如gl_FrontColorgl_BackColorgl_TexCoord,它们都已经消失了,可以通过定义自己的out/in 轻松替换变量。

预定义的片段着色器输出 gl_FragColorgl_FragData 也消失了。这是一个有趣的案例,因为原因不是功能弃用。我的理解是,它们已被弃用,因为它们不够灵活,无法适应当前的功能。由于gl_FragColor 的类型是vec4,片段着色器的输出必须是带有浮点分量的向量。如果您的渲染目标具有不同的类型,这将无法正常工作,例如如果您要渲染到整数纹理。

那么还剩下哪些预定义变量呢?虽然比以前少得多,但仍然有一些,它们都与可编程管道中仍然存在的固定功能有关。示例包括:

  • 顶点着色器和片段着色器之间的顶点坐标接口,主要由顶点着色器中的gl_Position输出和片段着色器中的gl_FragCoord输入组成。在顶点着色器和片段着色器之间仍有许多固定功能块,例如裁剪和光栅化。那些固定的功能块在顶点坐标上运行,所以预定义的变量仍然有意义。
  • 与实例化相关的一些变量(gl_VertexIDgl_InstanceID)。
  • gl_ClipDistance 支持使用任意平面进行裁剪,这仍然以固定函数形式存在。
  • gl_FrontFacing。三角形的缠绕顺序由固定函数评估,并提供给片段着色器。

这些列表都不是详尽无遗的,但我希望这是一个有用的概述,并提供一些背景知识。与往常一样,规范文档提供了最终的完整答案。

【讨论】:

  • 感谢大家的回答,他们真的向我澄清了很多。 OpenGL 是一个相当复杂的 API,所以很多东西一开始并不明显。
【解决方案2】:

正如我们的同事所说,gl_Position 没有被弃用。我刚买了一本关于 OpenGL 4.3 的 OpenGL Superbible 6th edition 书,在第一页(第 18 页)就在使用这个功能。

我只能推荐买这本书。它是由设计 OpenGL 的人编写的,非常具有指导意义。

我以前也和你一样迷路,因为我试图通过互联网或 stackexchange 学习,而在我拿到这本书之后,我在 OpenGL 上度过了一段美好的时光。我认为我在三周内通过这本书学到的东西将比在互联网上学习 5 年更有价值。 OpenGL 并不复杂,也不是很多人说的“野兽”,只要你从这本书中学会了它。如果您通过互联网学习它,我相信它不仅仅是野兽!

这本书一开始就说他不会教任何非核心 OpenGL 的东西,所以你可以确保不要像你那样陷入陷阱。

您可以以低至 50 美分的价格在亚马逊购买这本书。我只能推荐它!

【讨论】:

  • 我想他做到了,如果第一句话。然后证实了我的怀疑,互联网并不是了解 OpenGL 的着色版本发生了什么的丰富资源。真可惜,因为 OpenGL 有一个 wiki。