Rotation problem

Rotate by setFromAxisAngle with unnormalized axis give this deformation on scale in some axis. That’s normal behaviour? This can view after 1000+ summ degrees rotation.
Using unnormalized quaternion - same behaviour.
image

What about add this base usefull method for vectors and quats?

//return Number
pc.Vec3.angle = function(from, to) {
    var _from = from.normalize();
    var _to = to.normalize();
    var dot = _from.dot(_to);
    if (dot > 1)
        return (Math.acos(1 / dot)) * pc.math.RAD_TO_DEG;
    else 
        return (Math.acos(dot)) * pc.math.RAD_TO_DEG;
};



// return Number
pc.Vec3.signedAngle = function(from, to, axis) {
    var unsignedAngle = pc.Vec3.angle(from, to);
    var cross_x = from.y * to.z - from.z * to.y;
    var cross_y = from.z * to.x - from.x * to.z;
    var cross_z = from.x * to.y - from.y * to.x;
    var sign = Math.sign(axis.x * cross_x + axis.y * cross_y + axis.z * cross_z);
    return unsignedAngle * sign;
};
pc.Quat.lookRotation = function(forward, up) {
    var _forward = forward.clone();
    var _up = up.clone();
    _forward = _forward.normalize();
    var vector = _forward.normalize();
    var vector2 = (new pc.Vec3()).cross(_up, vector).normalize();
    var vector3 = (new pc.Vec3()).cross(vector, vector2);
    var m00 = vector2.x;
    var m01 = vector2.y;
    var m02 = vector2.z;
    var m10 = vector3.x;
    var m11 = vector3.y;
    var m12 = vector3.z;
    var m20 = vector.x;
    var m21 = vector.y;
    var m22 = vector.z;

    var num8 = (m00 + m11) + m22;
    var quaternion = new pc.Quat();
    if (num8 > 0.0)
    {
        var num = Math.sqrt(num8 + 1.0);
        quaternion.w = num * 0.5;
        num = 0.5 / num;
        quaternion.x = (m12 - m21) * num;
        quaternion.y = (m20 - m02) * num;
        quaternion.z = (m01 - m10) * num;
        return quaternion;
    }
    if ((m00 >= m11) && (m00 >= m22))
    {
        var num7 = Math.sqrt(((1.0 + m00) - m11) - m22);
        var num4 = 0.5 / num7;
        quaternion.x = 0.5 * num7;
        quaternion.y = (m01 + m10) * num4;
        quaternion.z = (m02 + m20) * num4;
        quaternion.w = (m12 - m21) * num4;
        return quaternion;
    }
    if (m11 > m22)
    {
        var num6 = Math.sqrt(((1.0 + m11) - m00) - m22);
        var num3 = 0.5 / num6;
        quaternion.x = (m10 + m01) * num3;
        quaternion.y = 0.5 * num6;
        quaternion.z = (m21 + m12) * num3;
        quaternion.w = (m20 - m02) * num3;
        return quaternion;
    }
    var num5 = Math.sqrt(((1.0 + m22) - m00) - m11);
    var num2 = 0.5 / num5;
    quaternion.x = (m20 + m02) * num2;
    quaternion.y = (m21 + m12) * num2;
    quaternion.z = 0.5 * num5;
    quaternion.w = (m01 - m10) * num2;
    return quaternion;
};


// return Quat
pc.Quat.fromToRotation = function(from, to) {
    var _from = from.clone();
    var _to = to.clone();
    var axis = new pc.Vec3().cross(_from, _to).normalize();
    var angle = pc.Vec3.signedAngle(_from, _to, axis);
    var result = new pc.Quat().setFromAxisAngle(axis, angle).normalize();
    return result;
};

Hi @KpoKec,

Thanks for sharing this code.

Try posting a feature request in the engine repo, the Playcanvas team may be interested in getting this in the pc.math class.

It’s possible for a quaternion to affect scale. I’m not sure why but it seems to be something inherent with quaternions rather than the engine.

I’ve been thinking about creating a math extension with functions like this and some others that I found useful from the Unity math library.

1 Like

Just normalize parameters, no?

Why not in corresponding classes?

Checking and sqrt can be an expensive operation.

Possible engine bloat. We want to try to keep the engine size as small as possible. Having it start as an extension means that it can be evaluated on usefulness and we can always bring it to the engine at a later date.

No unnecessary sqrt

if (axis.lengthSq > 1) axis.normalize();

Internal calls can be with optimized methods, with suffix “Internal” and without checks, if necessary