0

My 3D models rotates around wrong axis. Everything except X-axis works. When I set angle of Y and Z to 0 then X works fine but if rotate it eg. 90 degrees around Z-axis and rotate around X after that it rotates around Z too. So when Y or Z is used X rotates around Z. So if I make my model rotate 90 degrees around Z and -90 degrees around X it stays completely still.

My function for transformation matrix. If I move matrix.translate(position); to under rotations my model rotates in huge circle (maybe around worlds origin).

public static Matrix4f createTransformationMatrix(Vector3f position, Vector3f rotation, Vector3f scale) {

    Matrix4f matrix = new Matrix4f();

    matrix.scale(scale);

    matrix.translate(position);

    matrix.rotate((float) Math.toRadians(rotation.x), new Vector3f(1, 0, 0));
    matrix.rotate((float) Math.toRadians(rotation.y), new Vector3f(0, 1, 0));
    matrix.rotate((float) Math.toRadians(rotation.z), new Vector3f(0, 0, 1));

    return matrix;
}

Conversion of matrix to floatbuffer so I can pass it to shaders:

public static FloatBuffer toFloatBuffer(Matrix4f matrix) {

    FloatBuffer buffer = BufferUtils.createFloatBuffer(16);

    buffer.put(matrix.m00());
    buffer.put(matrix.m01());
    buffer.put(matrix.m02());
    buffer.put(matrix.m03());
    buffer.put(matrix.m10());
    buffer.put(matrix.m11());
    buffer.put(matrix.m12());
    buffer.put(matrix.m13());
    buffer.put(matrix.m20());
    buffer.put(matrix.m21());
    buffer.put(matrix.m22());
    buffer.put(matrix.m23());
    buffer.put(matrix.m30());
    buffer.put(matrix.m31());
    buffer.put(matrix.m32());
    buffer.put(matrix.m33());

    buffer.flip();

    return buffer;
}

Usage in shader:

gl_Position = transformationMatrix * vec4(position, 1.0) * viewMatrix * projectionMatrix;

The models' zero point has been set to its origin and I am sure that all data send to those functions are correct. I have been debugging this for while now. I am using LWJGL 3.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Maineri
  • 53
  • 7
  • 2
    If you combine rotations, then the second rotation is applied in the coordinate system after the first translation. Example: If you rotate 90 degrees around X, afterwards the local Y-axis points along the global Z-Axis and so on. – BDL Oct 30 '17 at 21:20
  • 2
    Unrelated, but the transformation order in your shader looks wrong. Unless view and projection are transposed, it doesn't make sense to multiply them from the right side. – BDL Oct 30 '17 at 21:20
  • @Rabbid76 that still doesn't solve my problem – – Maineri Oct 31 '17 at 14:06
  • @Rabbid76 I really don't know what you mean but can't you just look at the code above. The input vector rotation just contains degrees (0-360). I think it's Gimbal Lock as somebody answered because the Y rotation input is 90. I just don't know how to fix it. – Maineri Oct 31 '17 at 19:18
  • @Rabbid76 well there has to be some solution other people use – Maineri Oct 31 '17 at 19:26
  • @Rabbid76 I just want to be able to rotate my objects anyway I want. – Maineri Oct 31 '17 at 19:33

1 Answers1

2

I think you are facing the Gimbal Lock. That means, it matters in which order the rotations are applied, and then you may get strange results such as the results you have experienced.

To solve this problem, you will have to use Quaternions.

Basically, you will have to :

  • Create Rotation Quaternions and multiply them with other Rotation Quaternions.
  • You have to create a Rotation Quaternion that represents X-Axis-Rotation, and so on for Y and Z-Axis

  • You multiply them

  • Finally, you'll have to convert the resulting Quaternion into a matrix.

Read here about how to implement Rotation Quaternions in OpenGL ?

Edit :

Read here about how to convert a Quaternion to a Matrix : Convert Quaternion rotation to rotation matrix?

Here's my Camera class(unfortunately, it uses JOGL libraries like Quaternion, but should be portable to LWJGL. It provides scaling, moving, rotation around center in Euler or Quaternion way, as well as methods to retrieve pointing direction etc.

public class Camera {
    public Matrix4 matrix;
    public Quaternion rotation;
    public Vector3 position;
    public Vector3 scale;
    public Vector3 center;
    public Vector2 frictionx;
    public Vector2 frictiony;
    public Vector2 frictionz;
    public Camera() {
        matrix=new Matrix4();
        rotation=new Quaternion();
        position=new Vector3(0f,0f,0f);
        scale=new Vector3(1f,1f,1f);
        center=new Vector3(0f,0f,0f);
        frictionx=new Vector2(0,0);
        frictiony=new Vector2(0,0);
        frictionz=new Vector2(0,0);
    }
    public float tryFric(float a, float b) {
        try {
            float r=a/b;
            if (r == Float.NaN) {
                return 0;
            }
            return r;
        }
        catch (Exception e) {
            return 0;
        }
    }
    public void getFrictions(Vector3 pointing) {
        frictionx.x=tryFric(pointing.y,pointing.x);
        frictionx.y=tryFric(pointing.z,pointing.x);
        frictiony.x=tryFric(pointing.x,pointing.y);
        frictiony.y=tryFric(pointing.z,pointing.y);
        frictionz.x=tryFric(pointing.x,pointing.z);
        frictionz.y=tryFric(pointing.y,pointing.z);
    }
    public Vector3 getPointing(Vector3 vec) {
        float[] in=new float[] {vec.x,vec.y,vec.z};
        float[] out=new float[3];
        rotation.conjugate();
        rotation.rotateVector(out, 0, in, 0);
        rotation.conjugate();
        Vector3 p=new Vector3(out[0],out[1],out[2]);
        getFrictions(p);
        return p;
    }
    public void move(float x, float y, float z) {
        position.x+=x;
        position.y+=y;
        position.z+=z;
    }
    public void setPosition(float x, float y, float z) {
        position.x=x;
        position.y=y;
        position.z=z;
    }
    public void moveCenter(float x, float y, float z) {
        center.x+=x;
        center.y+=y;
        center.z+=z;
    }
    public void setCenter(float x, float y, float z) {
        center.x=x;
        center.y=y;
        center.z=z;
    }
    public void scale(float x, float y, float z) {
        scale.x*=x;
        scale.y*=y;
        scale.z*=z;
    }
    public void setScale(float x, float y, float z) {
        scale.x=x;
        scale.y=y;
        scale.z=z;
    }
    public void rotateQuaternion(float angle, float x, float y, float z) {
        Quaternion rotationy=new Quaternion();
        rotationy.rotateByAngleY(angle*y);
        rotation.mult(rotationy);
        Quaternion rotationx=new Quaternion();
        rotationx.rotateByAngleX(angle*x);
        rotation.mult(rotationx);
        Quaternion rotationz=new Quaternion();
        rotationz.rotateByAngleZ(angle*z);
        rotation.mult(rotationz);
        rotation.normalize();
    }
    public void rotateEuler(float angle, float x, float y, float z) {
        rotation.rotateByEuler(angle*x, angle*y, angle*z);
    }
    public Vector3 getPointing() {
        Matrix4 as_matrix=new Matrix4();
        as_matrix.loadIdentity();
        as_matrix.rotate(rotation);
        float[] out=new float[3];
        float[] in=new float[] {0,0,-1};
        as_matrix.multVec(in, out);
        Vector3 pointing=new Vector3(out[0],out[1],out[2]);
        return pointing;
    }
    public Matrix4 getMatrix() {
        Matrix4 rot_as_mat=new Matrix4();
        rot_as_mat.loadIdentity();
        rot_as_mat.translate(center.x, center.y, center.z);
        rot_as_mat.rotate(rotation);
        Matrix4 result=new Matrix4();
        result.loadIdentity();
        result.scale(scale.x, scale.y, scale.z);
        result.multMatrix(rot_as_mat);
        result.translate(position.x,position.y,position.z);
        matrix=result;
        return result;
    }
}

Hope it helps !

Note :

  • You may have to experiment with the rotation quaternion multiplication order to achieve different results
Luatic
  • 8,513
  • 2
  • 13
  • 34
  • I still see no difference.. How am I supposed to translate the resulting quaternion into the matrix? – Maineri Oct 31 '17 at 17:55
  • @Maineri : Take a look at this : https://stackoverflow.com/questions/1556260/convert-quaternion-rotation-to-rotation-matrix – Luatic Oct 31 '17 at 19:27
  • @user7185317 Still does not work.. Can I just use quaternionRotationX.rotateX(xRotInRadians) etc.. or how should I create the rotation quaternion? – Maineri Oct 31 '17 at 19:34
  • @Maineri : Yes, that should be right. Unfortunately, I am using jogl, but ill paste relevant code in my post. – Luatic Nov 01 '17 at 10:18
  • I am have kinda hard time understanding that. What does friction mean in this? And how can I rotate my model matrix the easiest way with this? What functions to call? Like that rotate euler. What am I supposed to give it as input? – Maineri Nov 01 '17 at 18:12
  • @user7185317 and do I have to reset rotation quaternion back to (0, 0, 0, 1) every time I use rotateQuaternion again? – Maineri Nov 01 '17 at 18:20