Java OpenGL Math Library (JOML)

Started by Neoptolemus, February 09, 2015, 09:55:47

Previous topic - Next topic

Neoptolemus

Just tested your code and I'm getting some curious results. I did a straight-up copy and paste and I've noticed that the camera behaves slightly oddly.

If I set the camera's position to be, for example, (0, 2, 2) so it's two units away from my plane and 2 units above it, it looks like this:



However, if I then change the camera's position to something like (0, 2, 1), it now looks like this:



It looks as though the camera's Y position has also changed slightly as it looks like it's higher above the plane than in the first image.

If I change the camera position again to (0, 2, 4) so it's further from the plane, it looks like this:



Now it looks like the Y position is only slightly above the centre of the plane, whereas in the second image it looked like it was quite high up. I didn't get this same result previously. Is this me missing something, perhaps some other transformations I'm missing which would "correct" the final result?

EDIT: Or perhaps I'm just tired and falling for some optical illusion? :P

Kai

Hm... I would be very glad if you could provide the code you are using for that demo.

I am quite certain that the code I provided in the last post computes the correct orthonormal basis for a "lookat" matrix. :)
Your previous computation was missing out on recomputing the "up" vector, which is essential, since the initial vectors will most likely never give an orthonormal basis by themselves, as "up" is likely just always set to (0,1,0) and the direction in which the camera is looking is not orthogonal to up.
Basically, the "lookat" matrix is just an orthonormal basis (right,up,direction) and you need two cross-products to compute that from the initial arguments; one for "right" and one for recomputing "up".

EDIT: I just tested it with the ray tracing demos (as those are very susceptible to all kinds of matrix errors because they compute all sorts of rays and stuff) with various camera positions and directions and the results do seem plausible.

spasi

Quote from: Kai on February 11, 2015, 07:38:50Performance-wise I would not expect it to make a big difference in under the millionth run.
After all these are just 16 floats, most probably also being SIMD-copied by the JIT, but I don't know that.

The problem is off-heap memory access, as I said above, the JVM is not able to reorder FloatBuffer reads and writes. Because of that, direct math on NIO buffers can be significantly slower (30% or more in many cases).

Quote from: Kai on February 11, 2015, 07:38:50Would be interesting to see whether SIMD auto-vectorization also catches on if the math is being done on FloatBuffer.get() and FloatBuffer.put(), and if it at all worked with float fields in the first place.

The JVM does not do auto-vectorization and never will, because of semantics differences. This could only be done using explicit operations provided by a library backed by intrinsics, like in Javascript.

Neoptolemus

Kai,

I'm sure it's more likely to be an error on my part given that you've done some pretty thorough testing, it just seemed odd that my first code (despite being wrong) actually produced good results. Might be a massive coincidence or just that I've not had a chance yet to subject it to any significant tests and therefore the mistake went unnoticed. Let me try implementing a proper freecam mode and get back to you. In the meantime, with your blessing, I'll submit a new build with your version of lookAt, and the transform method too (and I'll add a thanks to you of course!).

Kai

Sure thing. Don't need to mention me there... it's basically exactly what GLU is also doing in gluLookAt.  :)
I do not have the copyright on that, because you cannot really compute a lookat matrix anyhow else. ;)

EDIT: Have edited the lookAt method code in my post a bit: We can make use of Vector3f.distance there, instead of expanding euclidean manually.

Neoptolemus

Quick update: I've added a Quaternion class for handling rotations. It supports the following features:

- Define Quaternion from axis + angle (degrees and radians)
- Define Quaternion from euler angles (degrees and radians)
- Multiplication, division, addition and subtraction
- Generate rotation matrix from Quaternion (store in Matrix4f or floatbuffer)
- Conjugation, normalization, dot product, inversion, length etc.
- Spherical linear interpolation (slerp)

As always, would appreciate some feedback as I've not worked with Quaternions before, so if there are any oversights on my part then let me know and I'll address them :) I've done some initial testing and the results seem to work, but since I had to research this stuff using various websites, there is a chance there is some inconsistency in results.

SHC

Just for information, you can also compute a look-at quaternion, as mentioned in this Awesome StackOverflow answer.

public static Quaternion LookAt(Vector3 sourcePoint, Vector3 destPoint)
{
    Vector3 forwardVector = Vector3.Normalize(destPoint - sourcePoint);

    float dot = Vector3.Dot(Vector3.forward, forwardVector);

    if (Math.Abs(dot - (-1.0f)) < 0.000001f)
    {
        return new Quaternion(Vector3.up.x, Vector3.up.y, Vector3.up.z, 3.1415926535897932f);
    }
    if (Math.Abs(dot - (1.0f)) < 0.000001f)
    {
        return Quaternion.identity;
    }

    float rotAngle = (float)Math.Acos(dot);
    Vector3 rotAxis = Vector3.Cross(Vector3.forward, forwardVector);
    rotAxis = Vector3.Normalize(rotAxis);
    return CreateFromAxisAngle(rotAxis, rotAngle);
}


The above code is C# directly ripped off from that answer. I'd like to see this in the library too, will be helpful to someone.

Neoptolemus

Thanks for the suggestion SHC. I've added the function as both a static function (with supplied destination) and as an instance function (modifies the quaternion it's called upon). Initial tests seem to show it works (I can make a mesh always turn to face the camera), but let me know if anything isn't working.

Kai

Oh that function is sweet, as it allows for smooth tweening between two camera orientations. Will test it soon.
One suggestion, though:
We should parameterize this function a bit more.
Currently, this function depends on some implicit parameters, namely "what is forward" (through some static field in Vector3) and what is "up" (also through some static field).
I would suggest adding these as explicit parameters.

Neoptolemus

I've added overloads for both the static and instance method definitions to include custom up and forward vectors. If you choose not to specify them then the method will use the default Vectors of (0,0,1) for forward and (0,1,0) for up.

BrickFarmer

This library is looking great, and moving along so fast!  Any plans to get this into maven central?
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

Quote from: BrickFarmer on February 17, 2015, 14:55:15
This library is looking great, and moving along so fast!  Any plans to get this into maven central?
Maven-support would be awesome.
Would then also be good to have it into Travis-CI (like LWJGL3 does it) with an automatic publishing to Maven Central.
This would require the following steps:
- setup github user for Travis (like lwjgl3 does it with the github user LWJGL-CI)
- fork the git project for that user
- build a Maven POM for the project with Maven Central deployment information
- setup a Travis-CI Java/Maven project on behalf of the created Github user
If no-one minds, I could take care of creating the POM, the github user (I'd use a new googlemail-address for that and with PM to you, Neoptolemus, for the password of mail account and github user), the forking of the project and a Travis-CI project.
Although I have no experience with Travis. Maybe spasi can help there, too?

Neoptolemus

That sounds like a great idea! I'm happy to let someone else who's used Maven/Travis before fork it and get it on there. Just let me know what I have to do to keep it in sync with what's on Github.

Kai

Quote from: Neoptolemus on February 17, 2015, 15:45:44
Just let me know what I have to do to keep it in sync with what's on Github.
It should work without manually intervention. My plan is to get Travis configured so that you can just happily push changes to your own repository and Travis will do a git fetch and merge on its own fork and everything should be sync'ed then. :)

Neoptolemus

Sounds awesome! Thanks for setting that up :) As always, keep throwing suggestions my way for new features.

My current plans are:

* A Vector2f class for those wanting to do 2D games
* A class for doing surface mathematics like surface normal, binormal, bitangent etc
* Probably some other stuff when I have time to think about it