[SOLVED] Smooth rotation

I like to know if there is already a better or cleaner way to do a smooth rotation than I do at this moment.

In the update:

    if (playerMoveDirection !== null) {
        this.rotateTime += dt;
        this.rotateSpeed = 0.1;
            
        var original_rotation = new pc.Quat();
        var final_rotation = new pc.Quat();

        original_rotation.copy(this.entity.getRotation());
        this.entity.lookAt(playerMoveDirection, this.entity.getPosition().y, playerMoveDirection); 
        final_rotation.copy(this.entity.getRotation());

        this.entity.setRotation(original_rotation);

        var new_rotation = this.rotateTowards(original_rotation, final_rotation, this.rotateSpeed);

        this.entity.setRotation(new_rotation);

        if (this.rotateTime > this.rotateSpeed){
            playerMoveDirection = null;
            this.rotateTime = 0;
        }
    }
  

Other needed functions:

// Quat functions
// Get the dot product between two quaternions
Player.prototype.dot = function (quat_left, quat_right) {
    var dot = quat_left.x * quat_right.x + quat_left.y * quat_right.y + 
        quat_left.z * quat_right.z + quat_left.w * quat_right.w;

    return dot;
};

// Returns the angle in degrees between two rotations /a/ and /b/.
Player.prototype.quatAngle = function (quat_a, quat_b) {
    var dot = this.dot(quat_a, quat_b);
    
    if(quat_a.equals(quat_b) )
    {
        return 0;
    }        
    
    var rad2Deg = 1 / (Math.PI / 180);

    var angle = Math.acos(Math.min(Math.abs(dot), 1)) * 2 * rad2Deg;

    return angle;   
};

// Rotates a rotation A towards B.
Player.prototype.rotateTowards = function (quat_a, quat_b, percent) {
    var angle = this.quatAngle(quat_a, quat_b);
        
    if (angle === 0)
    {
        return quat_b;
    }
    
    return new pc.Quat().slerp(quat_a, quat_b, percent); 
};

Nobody?

Hi @Albertos,

Your code seems correct reading it out of context, not sure if there is an easier solution given two angles.

When I have two positions (instead of rotations) and I am using lookAt usually I use a tween to do a smooth rotation. Much like this thread we solved together:

Hay @Leonidas, thanks for your reaction! It is actually the same thing as then. However, with the use of Tween I have unfortunately not been able to achieve the good result. In itself, the current way works fine, but I hate the amount of code (and various other functions) it takes.

1 Like

Yes, good point, maybe try refactoring your code to a single function that you can use anywhere in your game?

Okay, maybe I can make it work with Tween after all. :sweat_smile:

For that I like to know how I can add this line:

.on('complete', function () {
    console.log('tween completed');
});

to this tween:

    if( this.tween ){
        this.tween.stop();
        this.tween = undefined;
    }
        
    this.lookTo.copy(new pc.Vec3(inputPoint.getPosition().x, this.entity.getPosition().y, inputPoint.getPosition().z));
        
    this.tween = this.app
    .tween(this.lookFrom)
    .to(this.lookTo, 2, pc.SineInOut)
    .on('update', function () {
    this.entity.lookAt(this.lookFrom);
    }.bind(this))
    .start();

So, you can add it in the same way you add the update method:

    this.tween = this.app
    .tween(this.lookFrom)
    .to(this.lookTo, 2, pc.SineInOut)
    .on('update', function () {
       this.entity.lookAt(this.lookFrom);
    }.bind(this))
   .on('complete', function () {
       console.log('tween completed');
    })
    .start();

I had tried something like this but probably in the wrong order. It remains difficult with so many brackets and other signs. Thanks!

1 Like

This way works almost completely:

Player.prototype.updateDirection = function () {
    this.lookTo.copy(new pc.Vec3(inputPoint.getPosition().x, this.entity.getPosition().y, inputPoint.getPosition().z));
                
    this.tween = this.app
    .tween(this.lookFrom)
    .to(this.lookTo, 0.2, pc.Linear)
    .on('update', function () {
       this.entity.lookAt(this.lookFrom);
    }.bind(this))
    .on('complete', function () {
       this.updateDirection();
    }.bind(this))
    .start();
};

This is not in a update function

But there are still a few things to solve:

  • When I increase 0.2 to 0.5 or more, the character will flip in all directions excluding the Y axis, if I move the character at the same time.

  • I have also a problem with the Y axis when the character is jumping at the same time.

I think it has to do with the fact that the current position of the character is not updated in this tween. Probably because this will only be done when the tween has ended. Is there a solution to that?

Okay, I tried again and then I found out that I don’t even need all the extra functions (at least as it seems now). So this is what it looks like now in the update:

Player.prototype.updateDirection = function (dt) {
    if (this.direction !== null) {
        this.rotateTime += dt;
        this.rotateSpeed = 0.05;

        var originalRotation = new pc.Quat();
        var finalRotation = new pc.Quat();

        originalRotation.copy(this.entity.getRotation());
        this.entity.lookAt(this.direction); 
        finalRotation.copy(this.entity.getRotation());
        this.entity.setRotation(originalRotation);

        this.entity.setRotation(new pc.Quat().slerp(originalRotation, finalRotation, this.rotateSpeed));

        if (this.rotateTime > this.rotateSpeed){
            this.direction = null;
            this.rotateTime = 0;
        }
    }
};

When I need to change the rotation of the entity I only have to use something like this:

    this.direction = new pc.Vec3(inputPoint.getPosition().x, this.entity.getPosition().y, inputPoint.getPosition().z);
1 Like

Thanks for sharing @Albertos! Good job putting everything in one place.

1 Like

You may want to check out Unity’s math function sources for this type of thing. They have a rotateTowards functions that seems ideal here

Indeed, Unity has many more options and there is also much more information and tutorials on the internet to realize ideas. Unfortunately I don’t have the knowledge to translate the options Unity offers into code suitable for PlayCanvas.

Can you provide a complete example, thank you?