使用 JOML 从 LWJGL 2 迁移到 LWJGL 3 时丢失 3D 投影

Loss of 3D projection when migrating from LWJGL 2 to LWJGL 3 with JOML

我有一个小项目,它是用 LWJGL 2 编写的,现在想转到版本 3。我更改了主库,没有出现更大的问题。但在小步骤。所以我首先没有对Vector和Matrix做改动类。相反,在新项目中我添加了旧的 lwjgl_util.jar。我可以正常渲染一切。到目前为止我唯一的损失是键盘和鼠标的输入,但这不是什么大问题。

下一步也是关键的一步是再次删除额外的 .jar 文件并将所有导入更改为 org.joml.Vector2f、org.joml.Vector2f 和 org.joml.Matrix4f 类,以及我的代码中所需的更改。 Eclipse 说没有更多的错误,JVM 也这么说。

如果我打印向量或矩阵,代码就会运行。他们都有应有的数据。

但是它应该呈现的不是正常世界,而是背景只有清晰的颜色(顺便说一句,正确的颜色)。

我的想法是,我没有从 Java 到着色器的数据,着色器将所有矩阵乘以零,我什么也看不到。

我在 https://github.com/JOML-CI/JOML/wiki/Migrating-from-LWJGL-2 并认为这可能是我的问题,但我不明白这到底是什么意思:

One important difference is the handling of NIO FloatBuffers when getting values from or writing values into a FloatBuffer. In LWJGL 2 the position of the FloatBuffer will be incremented by load and store operations. In JOML the position will not be changed!

所以我现在的问题是:

如何处理位置不变的 FloatBuffer?

public abstract class ShaderProgram {
    private static FloatBuffer matrixBuffer = BufferUtils.createFloatBuffer(16);
...
    protected void loadMatrix(int location, Matrix4f matrix) {
        matrix.get(matrixBuffer);
        matrixBuffer.flip();
        GL20.glUniformMatrix4fv(location, false, matrixBuffer);
    }
}

tl;博士

删除对 matrixBuffer.flip()

的调用

更长的解释

要知道为什么您的代码不起作用,您需要知道 Buffer.flip()(通过您的 FloatBuffer.flip() 调用)的确切作用:

Flips this buffer. The limit is set to the current position and then the position is set to zero. If the mark is defined then it is discarded.

(由我粗体突出显示)。

你知道,一个NIO Buffer是有位置、标记、限制和容量的。当您创建一个新的 NIO 缓冲区时,例如通过 BufferUtils.createFloatBuffer(size) 然后你会得到一个 FloatBuffer,它是底层 direct ByteBuffer 的视图,其容量为 size , 限制 size, 位置 0 且未设置标记。

通常,relative NIO Buffer 在 JDK 中的 put 操作会增加缓冲区的位置。但是,JOML 的 Matrix/Vector.get(Buffer) 不会这样做,就像所有 LWJGL/OpenGL 方法一样,这些方法将 NIO 缓冲区作为参数,例如 GL15.glBufferData(...).

因此,当您调用 Matrix4f.get(FloatBuffer) 时,所提供的缓冲区的位置将 不会 被修改,因此,之后对该缓冲区调用 .flip() 将将缓冲区的 limit 设置为缓冲区的位置(可能 0)。

接下来您需要知道的是,采用 NIO 缓冲区的 LWJGL 方法将使用缓冲区的 .remaining()(即 .limit() - .position())来确定任何 [=66= 的参数值] 底层原生 OpenGL 函数调用的参数。如果 glUniformMatrix4fv() 具有本机签名:

void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);

LWJGL 将根据提供的 NIO 缓冲区的 .remaining() / 16 推断 count 参数的值。由于您的 Buffer 可能有 .remaining() 0 的(由于当所述缓冲区的位置为 0 时调用 .flip() - 由于 Matrix4f.get(FloatBuffer) 没有增加位置)提供的 OpenGL 函数参数将是 0,在这种情况下会导致 noop。