如何使用着色器和矩阵进行翻译?

How to translate using shaders and matrices?

我正在使用 LWJGL 和着色器尝试转换我在着色器程序中绘制的所有内容。 我正在使用 4 x 4 矩阵

1,0,0,x,
0,1,0,y,
0,0,1,z,
0,0,0,1

其中 x、y、z 是我用来翻译的值。然后我用

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex * transformMatrix

其中 transformMatrix 是我从上面的矩阵中得到的统一 mat4。 它可以很好地平移 x 和 y,但不能在 z 轴(向前和向后)上平移。

是矩阵错误还是着色器方法错误? (或两者)

如何解决这个问题,使其翻译成 glTranslatef?谢谢

矩阵本身看起来没问题。请记住,OpenGL 默认情况下对矩阵使用列优先存储,因此当您指定时,该矩阵的元素将按如下方式排序:

{1.0f, 0.0f, 0.0f, 0.0f,
 0.0f, 1.0f, 0.0f, 0.0f,
 0.0f, 0.0f, 1.0f, 0.0f,
 x,    y,    z,    1.0f}

如果您想在代码中坚持行优先顺序,您还可以将 GL_TRUE 指定为 [=15= 的第三个参数 (transpose) ]'.

您似乎卡在了两个不同级别的 OpenGL 之间。为了说明这一点,让我对 OpenGL 的一些主要发展阶段进行编号。以下不是官方术语,我自己编的。

  • 第 1 阶段:固定功能流水线。渲染纯粹是通过指定状态和发出绘制命令来执行的。状态包括矩阵堆栈、光照和material属性等
  • 第 2 阶段:具有固定功能属性的可编程流水线。着色器用于控制渲染,但仍使用矩阵堆栈等固定功能状态。使用 GLSL 代码中的预定义变量访问此状态。
  • 阶段 3:完全可编程。不再使用固定功能状态,所有着色器的输入都使用通用属性和制服指定。

与 OpenGL 版本匹配:

  • OpenGL 1.x 严格使用阶段 1。
  • OpenGL 2.x 代码通常使用第 2 阶段,尽管它完全向后兼容并且仍然支持第 1 阶段的所有内容。它已经包含第 3 阶段所需的大部分内容。
  • OpenGL 3.x 及更高版本仅支持带有 Core Profile 的 Stage 3(在 3.2 中引入)。第 1 阶段和第 2 阶段的所有固定功能方面仅在兼容性配置文件中可用。

您的代码片段表明您正在使用第 2 阶段,并正在尝试转移到第 3 阶段。在此过程中,您在两者之间创建了一个有问题的组合。根据你想去的方向,解决方案是不同的。

固定功能状态的使用

只要您在着色器 (gl_ModelViewProjectionMatrix) 中使用固定函数矩阵堆栈中的矩阵,最简单的解决方案就是完全使用它。

因此,要进行翻译,您可以调用 glTranslatef(),它会将翻译添加到您的模型视图矩阵,然后在 GLSL 代码中使用 gl_ModelViewProjectionMatrix 和类似的内置变量对其进行访问。

固定函数和统一函数的混合体

对于您尝试使用的方法,最合理的解决方案是在内置 gl_ModelViewProjectionMatrix:

之前将额外的平移矩阵与向量相乘
gl_Position = gl_ModelViewProjectionMatrix * transformMatrix * gl_Vertex;

您需要注意,这会应用额外的转换 before 您在模型-视图转换中可能拥有的所有其他模型转换。假设您还使用固定函数调用指定了旋转:

glRotatef(...);

此旋转是模型视图矩阵的一部分,现在将在您添加的翻译之后应用。所以你会旋转翻译后的坐标,这可能不是你想要的。

使用这种方法,无法在其他模型转换后应用转换。你基本上需要的是:

gl_ProjectionMatrix * gl_ViewMatrix * transformMatrix * gl_ModelMatrix * gl_Vertex;

但是由于View矩阵和Model矩阵是在固定函数状态下组合的,所以这是不可能的。

无固定功能状态

为了充分的灵活性,以及​​与当前 Core Profile 的兼容性,您需要停止使用固定功能状态,以及相应的 GLSL 内置变量,如 gl_ModelViewProjectionMatrix。为此,您需要在着色器代码中将所有需要的矩阵指定为统一变量。这使您可以完全控制使用的矩阵以及如何在 GLSL 代码中应用它们。

例如,如果您只需要翻译,则无需使用完整矩阵。您可以使用 vec3 作为制服,只需将其添加到位置向量即可。

完全可编程方法的主要缺点是您不能再使用 glRotatef()gluLookAtgluPerspective() 等便利函数。有提供替代品的开源库,如果您愿意,自己编写类似的功能也很容易。您也不再有矩阵堆栈,因此如果您依赖转换层次结构,则需要在自己的代码中添加更多逻辑。