Loss of 3D projection when migrating from LWJGL 2 to LWJGL 3 with JOML
I have a small project, which was written with LWJGL 2 and wanted now to move to version 3. I changed the main lib without bigger problems. But in small steps. So I first didn't do a change to the Vector and Matrix classes. Instead, in the new project I added the old lwjgl_util.jar. I could render everything as normal. The only loss I had till this point was the input of keyboard and mouse, but this is not a big problem.
The next and crucial step was to delete the extra .jar file again and change all imports to the org.joml.Vector2f, org.joml.Vector2f and org.joml.Matrix4f classes, and the needed changes in my code. Eclipse says there is no more error, and so says the JVM too.
The code runs, if I print vectors or matrices. They all have data as they should.
But instead of the normal world it should render, there is only the clear color for the background (the correct one btw.).
My thinking is, I got no data from Java to the shader and shader multiplies all matrices to zero and I can't see anything.
I found this line on https://github.com/JOML-CI/JOML/wiki/Migrating-from-LWJGL-2 and have an idea that this could may be my problem, but I don't understand exactly what it means:
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!
So my question now:
How is the handling of the FloatBuffers with this not changing position be done?
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);
}
}
Solution 1:
tl;dr
Remove the call to matrixBuffer.flip()
Longer Explanation
To know why your code does not work requires you to know what Buffer.flip()
(called via your FloatBuffer.flip()
) does exactly:
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.
(bold highlight by me).
You know, a NIO Buffer has a position, mark, limit and capacity. When you create a new NIO Buffer e.g. via BufferUtils.createFloatBuffer(size)
then you will be given a FloatBuffer
that is a view of an underlying direct ByteBuffer
which has a capacity of size
, a limit of size
, a position of 0
and no mark set.
Usually, relative NIO Buffer put operations in the JDK will increment the buffer's position. However, JOML's Matrix/Vector.get(Buffer)
won't do this, much like all LWJGL/OpenGL methods which take a NIO Buffer as parameter, such as GL15.glBufferData(...)
.
So, when you call Matrix4f.get(FloatBuffer)
then the position of the supplied Buffer will not be modified and therefore, calling .flip()
on that buffer afterwards will set the limit
of the buffer to where the buffer's position was (likely 0
).
The next thing you need to know is that LWJGL methods that take a NIO Buffer will use the buffer's .remaining()
(which is .limit() - .position()
) to determine the argument value to any size/length parameters for the underlying native OpenGL function call. In the case of glUniformMatrix4fv()
with native signature:
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
LWJGL will infer the value for the count
parameter based on the .remaining() / 16
of the supplied NIO Buffer. Since your Buffer likely has a .remaining()
of 0
(due to the .flip()
call when said buffer had a position of 0
- due to Matrix4f.get(FloatBuffer)
not having incremented the position) the supplied OpenGL function argument will be 0
, which will cause a noop in this case.