I'm using LWJGL and JOML to create a 3D view of hexagons whose positions lie on a torus.

I have a number (NxM) hexagons, whose centres and normals I have calculated to be placed on the torus to completely cover the torus surface, but in the "game" engine I'm using I need to convert each item being rendered to a position and 3 rotation angles. I'm struggling to go from the 3 normals of the item to the 3 angles.

EDIT: Subsequent to posting this I have got some way in creating a matrix with the angles and converting to Euler angles, everything is now turned according to those angles, but they aren't facing directions I expect.

The background

I'm trying to create a visualisation of a Conway Game of Life using hexagons but instead of a simple plane, mapping each hexagon onto a Torus.

I've done the maths to calculate the centres of every hexagon, and the 3 direction unit vectors that they need to point to, when in their places around the torus.

For illustrative purposes, here's a view of the torus and 2 hexagons that would lie on it (not real, this is just me mocking it up in Blender)

torus with hexagons on

What I'm struggling to understand is how to rotate the single mesh for a hexagon to its calculated normals at the position I want to place it.

i.e. How do I rotate some "unit" hexagon mesh (loaded from an OBJ file exported from Blender) to point in the direction of the 3 normals I've calculated they should be for each hexagon around the torus.

I have read a similar question here, but I'm struggling to get from the idea of the 4d rotation matrix to how I convert that to a Vector3f for rotations. I have the 3 vector normals, could create the 4d matrix, but I need a Vector3f (the rotations about x/y/z) to the mesh is drawn correctly.

My code is here. I'm following this guide for using LWJGL to create GameItems (my hexagons) and position/rotate them from a loaded obj file mesh, but as I say, I'm struggling to calculate the rotation Vector3f needed to point in the same direction I've calculated.

Here's the code section relevant to the problem at hand:

    val mesh = loadMesh("/conwayhex/models/simple-hexagon.obj")

    hexGrid.hexAxes().forEach { (location, axis) ->
        // axis is a Matrix3f with my 3 normals at the centre of the hexagon, e.g
        // cX  cY  cZ
        //  0  -1   0
        //  0   0  -1
        //  1   0   0

        val gameItem = GameItem(mesh)
        gameItem.position = location
        gameItem.scale = 0.2f // TODO: calculate this according to the torus size

        // what rotation do I give this?
        // How do I calculate it from the given axis for the current item?
        gameItem.rotation = Vector3f(30f, 30f, 30f)

        gameItems += gameItem

The output of the application given the above static 30 degree rotation is:

enter image description here

Can anyone help me unserstand how I apply the rotation to my items so they align to what I've calculated they should be?

  • \$\begingroup\$ Hi, if you don't get an answer here I suggest also asking this questions on math.stackexchange.com . Also, if it's at all possible, providing us with images of current state and finished state of this would help greatly to understand what you are trying to achieve and what results you expect to get, and what part of calculations you are struggling with. My understanding is that you are trying to place hexagons based on torus faces and its normals, but I still don't fully understand what the end result should look like, maybe it's just me, but it took a good 5-10 min for me to get that \$\endgroup\$ Jan 9, 2021 at 4:19
  • \$\begingroup\$ Thanks for the comment. since posting this, I've been working on the camera positioning within the world, so I can more easily get to the parts that look wrong and work out why. I've also made a better hexagon with additional markers so I can tell what its relative x/y/z planes are. I'll update this question to include a smaller summary of what I'm trying to achieve. Thanks for your answer too, I'll digest this soon. I did wonder if this or math.stackexchange.com would be the best place for this question. \$\endgroup\$ Jan 10, 2021 at 12:01
  • \$\begingroup\$ I think it's the best to ask this kind of question here first since it's more related to gamedev than only math, but since audience is different but passionate about similar things it wouldn't hurt to get answer on another platform if one wasn't able to provide the right answer. \$\endgroup\$ Jan 11, 2021 at 1:34

2 Answers 2


3 direction unit vectors contain all the needed information for rotation. So there are 2 solutions:

  1. Having calculated the centres and the 3 direction unit vectors you can build a matrix that would transform local space mesh to world space. GameItem would have single Matrix4f field instead of position, scale and rotation fields. You then just pass actual matrix to renderer.

This pseudocode should handle it:

Matrix4f Create(Vector3f eye, Vector3f forward, Vector3f up, float scale) 
    Vector3f f = normalize(forward);
    Vector3f u = normalize(up);
    Vector3f s = normalize(cross(f, u));
    u = cross(s, f);

    s *= scale;
    u *= scale;
    f *= scale;

    Matrix4f result = new Matrix4f(1.0f);
    result.m00 = s.x;
    result.m10 = s.y;
    result.m20 = s.z;
    result.m01 = u.x;
    result.m11 = u.y;
    result.m21 = u.z;
    result.m02 = f.x;
    result.m12 = f.y;
    result.m22 = f.z;

    return translate(result, new Vector3f(-eye.x,-eye.y,-eye.z));
  1. As an alternative you can decompose mentioned matrix into euler angles. In that case do not apply scale to it (or just pass 1.0):

How to extract euler angles from transformation matrix?

  • \$\begingroup\$ Thanks again for taking time to look at this, a lot of this was already in my code, I'm so new to this that I was confused over multiple parts. My "engine" already applies the correct matrix rotations and scalings to get the view and models correct for my world, what I was missing was "how do I set the item's rotation?", which wasn't working when I was using simple x,y,z rotation values, but converting to quarternion made it work immediately. \$\endgroup\$ Jan 10, 2021 at 13:32

I converted to using a quarternion to hold the value of the rotation which I could readily create from the normals, so the "fix" was for me to understand how rotations work better.

For the libraries I was using, the fix was simply:

val q = Quaternionf().setFromNormalized(axes)

Here's an image from inside the torus better showing what I was trying to achieve initially (i.e. the placement and rotation of the hexagons onto the torus). This is from my application.

torus of hexagons

Next step is to animate these according to game of life rules.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .