This looks really interesting. Due to the major flaws of LWJGL’s math library (missing lots of important functions, like slerp for quaternions and vectors) I opted to rip out LibGDX’s math library for We Shall Wake/Insomnia. This has both the advantage and drawback of having native code for certain slow functions (matrix multiplication, matrix inverting, etc), but the additional dependencies and natives inflate the size of the game, and more code means that things can go wrong in more places. In addition, LibGDX’s math library is completely dependent on static temporary variables, making it useless for multithreading, which I’ve had to hack around by replacing certain functions and/or add thread-local temp variables instead. All in all, between those two LibGDX’s lib was the better one despite all its flaws.
JOML seems to offer some really interesting features, but also seems to lack a few extra features I could really use. I took a look at it, and here’s a list of my feedback.
- Quaternion should be renamed to Quaternionf to follow the same convention as everything else.
- Generally, AngleAxis is called AxisAngle. AngleAxis just doesn’t ring the same. =P
- In some rare cases, Insomnia suffers from floating point precision problems in some matrix calculations. Many game engines calculate all matrices at double precision and finally converts everything to single precision when uploading it to OpenGL, but neither LibGDX or LWJGL’s library has support for that. JOML actually does, but it’s incomplete. For this to work, I would need an identical set of functions for both Matrix4f and Matrix4d, but the double version doesn’t have many important functions. Also, a function to store a Matrix4d in a FloatBuffer would be nice.
- The performance of my skeleton animation is probably THE most performance critical section in the entire engine, and it involves constructing a matrix from a translation, a scale and a quaternion rotation. LibGDX has an excellent extremely fast method for doing this (line 202).
- I calculate a lot of normal matrices from view matrices. A function that can extract a 3x3 normal matrix from a 4x4 matrix would be nice.
- Many calculations actually only require a 4x3 matrix (view matrix, object transform matrices, bone matrices). A separate 4x3 matrix class would be overkill, but functions to only store the rotation and translation part of the matrix (12 floats) in a float buffer would be nice. It’s also possible to make an optimized matrix multiplication function if you know that the last row is (0, 0, 0, 1), which could help you beat LibGDX’s native performance in my skeleton calculation.
- LibGDX doesn’t actually have a Vector4 class, only Vector3. Matrix4s can transform Vector3s by mul() (assumes W is 1.0 and discards the calculated W value) and proj() (assumes W is 1.0 and divides by the calculated W value). Such a function would definitely ease porting from LibGDX and save me a lot of time.
All that’s left after that would be performance, but I strongly believe you can beat LibGDX due to the questionable design choices they made. Matrix multiplication is definitely the slowest part of my engine (taking up a sizeable percentage on the CPU time taken by an entire frame), and an optimized 4x3 matrix multiplication would be able to cut the matrix multiplication cost by a lot. Add the better naming convention, multithreading readiness and double precision calculations and you have a really attractive library for me.
EDIT:
Would also prefer radians instead of degrees. It’s so confusing when I have to mix Java’s Math functions with the library. Also, your rotation functions have this:
float cos = (float) Math.cos(Math.toRadians(ang));
float sin = (float) Math.sin(Math.toRadians(ang));
You should cache the radian angle instead of calculating it twice. Not sure if Hotspot takes care of that for you, probably not.