Search code examples
javascriptvectorrotationgame-enginequaternions

Object shrinks when rotated javascript


I have been developing a basic game engine just to learn the process and I have hit a issue with my rotation function.

It works fine except that the object shrinks and appears to invert.

Here is a jsfiddle that illustrates my point.

I think the problem would be in the rotation code its self but i'm not positive.

function Rotation(vec, rot){
if(Math.acos((vec.x + vec.y + vec.z -1)/2) === 0) { return vec; }

var qVec = new Quaternion(vec.x, vec.y, vec.z, 0);
qVec = Quaternions.multiply(qVec, rot);
qVec = Quaternions.multiply(qVec, rot.conjugate());
return new Vector3(qVec.x, qVec.y, qVec.z);
}

Solution

  • Couple things:

    First, the rotation quaternion is not normalized, so it's inverse is not the same as its conjugate. Rotation by a quaternion is defined by:

    formula

    Where q is the vector you're rotating around, p is the vector you're rotating, and p' is the final rotated vector.

    So this is defined using the inverse of q, which is defined as conjugate(q) / magnitude(q)^2. In the case where q is normalized, magnitude(q)^2 == 1, so it's the same as just multiplying by the conjugate.

    Also note the order of operations here. Quat multiplications are non-commutative so their order matters.

    You can fix this by normalizing your rotation quaternion, and fixing the order of operations:

    var qVec = new Quaternion(vec.x, vec.y, vec.z, 0);
    qVec = Quaternions.multiply(rot.normalize(), qVec);
    qVec = Quaternions.multiply(qVec, rot.conjugate());
    return new Vector3(qVec.x, qVec.y, qVec.z);
    

    Second, you want to define your rotation quat as normal to the plane you want to rotate around. In this case, you want to rotate around the x-y plane. The z-axis is normal to this plane, so we want to define the rotation vector along the z-axis:

    function update(){
        for(var i = 0; i < gameObjects.length; i++){
            gameObjects[i].rotation = euler(new Vector3(0, 0, frames/100));
        }
    }
    

    With these changes, I was able to get the box rotating correctly.

    (In terms of why it was scaling up/down, I'm not 100% sure. Still trying to figure that out.)