JOML

Started by Kai, May 31, 2015, 14:08:57

Previous topic - Next topic

Kai

Hi,

I've been working for the last three days extensively on moving JOML forward to reach a broadly usable state and polished it a lot. The goal is to allow JOML to be applicable to any usage patterns that might exist for such a narrow framework.
Hopefully, we succeeded in it.

Notable features:
- lean and mean
- very low requirements (Java 1.4)
- completely allocation-free
- can be used in a multithreaded application
- fluent interface style methods
- resembles very closely the functions of OpenGL and GLU

More information is available at GitHub.

If you want, go ahead and use it.
Please make sure to provide us with any feedback, or post any issues you encounter, or change requests you have, on the GitHub Issues section!

Before really using JOML also please make sure to read on the Design entry in its Wiki, which specifies the operational semantics of JOML, so that you always know what happens. :)

Thanks!
- the JOML team ;)

kappa

really nice work, looking forward to using it.

spasi

Looking great. One request: Could you make buffer operations use indices relative to the current buffer position? I.e. make it compatible with how LWJGL handles buffer arguments. This way you won't have to rewind/flip after a matrix get/put.

Kai

Thanks.
Ah, yes, that would indeed make usage look nicer.
The main purpose for using the position-changing relative put operation is that you can then chain multiple Matrix.get() operations on the same FloatBuffer (for example when filling a UBO with multiple matrices) without the client needing to advance the buffer position in-between calls.
But I think I will add a Matrix4f.get(FloatBuffer, boolean) where the boolean means "should or should not advance the buffer position" and then make the default get(FloatBuffer) use false.

EDIT: Okay, is in. 1.1.1-SNAPSHOT release contains these changes.

spasi

I wouldn't use boolean parameters, it's bad API design (especially in Java that doesn't support named parameters). Better have a get(FloatBuffer buffer, int matrixIndex) for that use case, the matrix will be stored at buffer.position() + matrixIndex * 16. Or something equivalent.

Kai

Okay.
In 1.1.3-SNAPSHOT there is now Matrix4f.get(FloatBuffer) which stores the matrix at the buffer's current position() and does not advance the buffer position.
Additionally, there is now a Matrix4f.get(int, FloatBuffer) which takes the absolute index/position of the buffer (just like the non-relative put operations in NIO) at which the matrix should be stored, and which also does not advance the buffer position.

mcmacker4

Hi, I have a question:

Since lwjgl_util has lost compatibility with lwjgl3 i am now using JOML to load a projection matrix into opengl's projection matrix. The problem now is that glViewport doesn't seem to do anything. How would i solve the aspect ration problem instead?

Also for my own convenience i implemented a method into JOML's source code (in Matrix4f class precisely) that puts the matrix into a FloatBuffer and returns the FloatBuffer. I just thought you may want to use it (or not):

public FloatBuffer asFloatBuffer() {
    ByteBuffer bb = ByteBuffer.allocate(4 * 4 * 4);
    bb.order(ByteOrder.nativeOrder());
    FloatBuffer fb = bb.asFloatBuffer();
    fb.put(new float[] {
    	    this.m00, this.m01, this.m02, this.m03,
    	    this.m10, this.m11, this.m12, this.m13,
    	    this.m20, this.m21, this.m22, this.m23,
    	    this.m30, this.m31, this.m32, this.m33
    });
    fb.flip();
    return fb;
}
    
public static FloatBuffer asFloatBuffer(Matrix4f mat) {
    ByteBuffer bb = ByteBuffer.allocate(4 * 4 * 4);
    bb.order(ByteOrder.nativeOrder());
    FloatBuffer fb = bb.asFloatBuffer();
    fb.put(new float[] {
    	    mat.m00, mat.m01, mat.m02, mat.m03,
    	    mat.m10, mat.m11, mat.m12, mat.m13,
    	    mat.m20, mat.m21, mat.m22, mat.m23,
    	    mat.m30, mat.m31, mat.m32, mat.m33
    });
    fb.flip();
    return fb;
}

Kai

Hello,

there are the Matrix4f.get(FloatBuffer) as well as Matrix4f.get(int, FloatBuffer) methods to "get" the matrix into a FloatBuffer.

I hate to say that your implementations violate an important design goal/principle of JOML, trying to be as efficient as possible with Java.
Part of reaching this goal is to be "allocation-free," which means that no method in JOML ever will allocate anything.
Your methods do allocate three objects: a NIO ByteBuffer, a FloatBuffer view on it and a float array.

In order to remain allocation-free, JOML uses the "parameter as return value pattern".
The Matrix4f.get(FloatBuffer) therefore receives the "destination" FloatBuffer as parameter into which the matrix will be written.
See the JavaDocs of this method.

EDIT:

If you want to have the FloatBuffer returned rather than the Matrix4f when calling get() on it for method chaining to be able to call further methods on FloatBuffer,
you could yourself add another method to Matrix4f like so:
public FloatBuffer toFloatBuffer(FloatBuffer fb) {
  get(fb);
  return fb;
}


Note that you need not invoke FloatBuffer.rewind() or .flip() or .clear() on the FloatBuffer afterwards, as JOML will not alter its position().

mcmacker4

I have a problem with the aspect ratio. When using LWJGL2 and gluPerspective() from lwjgl_util, if I had an aspect ratio different to 1 everything stretched so I used glViewport to solve this. Now that I am using JOML the glViewport seems to do nothing. Any ideas on how to solve this?
Here is my code to create the projection matrix:

glMatrixMode(GL_PROJECTION);
Matrix4f perspMat = new Matrix4f();
perspMat.perspective(
		Graphics.fov,
		Game.width / Game.height,
		Graphics.znear,
		Graphics.zfar
);
FloatBuffer fb = ByteBuffer.allocateDirect(4*4*4)
	        .order(ByteOrder.nativeOrder())
		.asFloatBuffer();
perspMat.get(fb);
glViewport(0, 0, Game.width, Game.height);	//This seems to do absolutely nothing
glLoadMatrixf(fb);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();


Also on this note:
Quote from: Kai on June 01, 2015, 14:18:19
Note that you need not invoke FloatBuffer.rewind() or .flip() or .clear() on the FloatBuffer afterwards, as JOML will not alter its position().

As you can see in the code above, i am not using any of those two methods. If I do use fb.flip() i get this error:
java.lang.IllegalArgumentException: Number of remaining buffer elements is 0, must be at least 16

Kai

glViewport is not meant to correct aspect ratio in the perspective projection.

It is meant to define what parts of the window will receive the OpenGL rendering output.
Or in other words: glViewport defines the transformation from normalized device coordinates to pixel coordiantes.

I am surprised that, as you said, with LWJGL 2 glViewport actually did fix the stretching in the perspective projection due to different aspect ratios. glViewport has nothing to do with the perspective projection matrix or any other matrix stack. It merely defines the transformation between NDC and pixels.

Your usage of Matrix4f.perspective is correct, provided that Game.width and/or Game.height are floating point values. If they are integers, which I assume they were, since they are likely in pixel width/height, you NEED to cast either of the two to float!

mcmacker4

Ok, casting Game.width as float fixed the problem. Thank you very much.

Kai

JOML now got a Wiki, with the most important entry being about its Design,
which is about to explain the design decisions and the exact operational semantics of JOML, to get a feeling of how to work with JOML.

BrickFarmer

Are there still plans to upload JOML to maven central, or is it already there somewhere?
Oculus Rift CV1, MBP 2016 - 2.9 i7 - Radeon Pro 460  OSX 10.12.4,  Win7 - i5 4670K - GTX1070.
Oculus Rift VR Experiments: https://github.com/WhiteHexagon

Kai

I was hoping that Spasi could set up a LWJGL-hosted Nexus OSS repository to hold all of the LWJGL and JOML artifacts.

Uploading to Maven Central directly is quite a cumbersome process, as you first need to have a Sonatype account, then an approved project that you are allowed to upload to Maven central.
Then you must provide PGP signatures with your artifacts, therefore need a PGP client to do that.
And there are a few more steps involved.

Using an organization-hosted Maven repository is a well-established step chosen by many organizations such as Atlassian, SpringSource and Apache.

A client of LWJGL or JOML would then only need to have a <repository> tag either in their settings.xml or in their project's pom.xml to reference that new repository. We could provide that tag definition on the JOML or LWJGL site as a snippet for you to copy-and-paste to make integration for clients as painless as possible, which is also what most other organizations do.

Or we get an approval from Sonatype to have LWJGL's repository being included as a virtual third-party repository, so that effectively LWJGL and JOML would then be found when querying Maven central directly.

spasi

This is a good idea and I'll try to make it happen, but I don't know when I'll have time for it.