How to build animation for ArcRotateCamera so it can rotate smoothly

Hi guys, so what I’m trying to do is like


I’m trying to build an animation for arcRotateCamera so it can rotate smoothly, i.e. from start position to end position, and with the exact correct upVector as well.
After I tried in playground, I found that only position and upVector property worked in animation(which means the camera actually move during animation).
Other properties, such as rotationQuaternion, alpha, beta(does not move), or absoluteRotation(error report: can not … [object,object]…), do not work when I build animation with them.
The problem is that i’m not so satisfied with the current position and upVector animation, they seem to make camera rotate in a very strange way, espectially upVector property.

Here is the playgroud code:

var createScene = function () {
var scene = new BABYLON.Scene(engine);
scene.beginDirectAnimation()
var light = new BABYLON.PointLight(“Omni”, new BABYLON.Vector3(0, 100, 100), scene);
var camera = new BABYLON.ArcRotateCamera(“Camera”,1.57,0,200, new BABYLON.Vector3(0,0,0), scene);
//camera.setPosition(new BABYLON.Vector3(1, 2, 50));
// camera.attachControl(canvas, true);

//Boxes
var box1 = BABYLON.Mesh.CreateBox("Box1", 10.0, scene);
box1.position.x = -20;

var materialBox = new BABYLON.StandardMaterial("texture1", scene);
materialBox.diffuseColor = new BABYLON.Color3(0, 1, 0);//Green

//Applying materials
box1.material = materialBox;

var animCamPosition = new BABYLON.Animation("animCam", "rotationQuaternion", 24,
                        //   BABYLON.Animation.ANIMATIONTYPE_VECTOR3,)
                          BABYLON.Animation.ANIMATIONTYPE_QUATERNION);

var keysPosition = [];
keysPosition.push({
    frame: 0,
    value: new BABYLON.Quaternion(-1,0,0,0)
});
keysPosition.push({
    frame: 100,
    value: new BABYLON.Quaternion(0,0,0,1)
});

animCamPosition.setKeys(keysPosition);


camera.animations.push(animCamPosition);


scene.beginAnimation(camera, 0, 100, true);





return scene;

}

Sorry I need to correct myself: The alpha and beta propery can build an animation but the animation happens in an instant that it ends so fast that beyond I can tell, but the camera does change.

It would be best to post a link to your playground code.

1 Like

I tried it with ANIMATIONTYPE_FLOAT to animate beta and and it seems to work fine (same for alpha).:slightly_smiling_face: IDK if you can animate position or rotationQuaternion directly thou since they’re maintained internally by ArcRotateCamera. :thinking:
https://playground.babylonjs.com/#T90KID

2 Likes

I usually use this very short and comfortable snippet

BABYLON.ArcRotateCamera.prototype.spinTo = function (whichprop, targetval, speed) {
    var ease = new BABYLON.CubicEase();
    ease.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
    BABYLON.Animation.CreateAndStartAnimation('at4', this, whichprop, speed, 120, this[whichprop], targetval, 0, ease);
}

and then use it as you want, separately or together, for example

       camera.spinTo("radius", 250, 50);
       camera.spinTo("alpha", Math.PI/2, 50);
       camera.spinTo("beta", 1.05, 50);

Example - https://playground.babylonjs.com/#U5SSCN#169 (press Return button).

6 Likes

cc @PolygonalSun

1 Like

For smoothly rotate the camera into the right angle, the solution that @Blake provided works perfectly. Using your alpha and beta for your animation parameter is going to be your safest bet. Also, the solution provided by @labris is another great way to do it, especially if you intend for the desired angle movement to change.

3 Likes

Hi @Richardo just checking in, were the suggestions helpful to solve your question? :slightly_smiling_face:

sorry to say that I tried these methods by it did not work well. The main problem is that I wish the camera could rotate also by it self, i.e the upVector property animation. The animation still move weirdly…by upVector property in my camera

I’m sorry to hear that. Can you elaborate a bit more about what you need the camera to do? Do you want it to rotate in its own right axis by animating the up vector, like in this picture?

1 Like

I want to rotate by the forward direction. the camera twists by it self. (roll by it self)
I wrote 2 animation for the camera, position and upVector.


In the second position, the camera not only change its position, but also rolled by it self, so
the upVector is also changed.
Hope I make my self clear.

Just a quick thought - maybe you need to use camera.rebuildAnglesAndRadius() function when animating.
Do you have some repro in PG?

I would write one when I got time. thank you so much for keeping care about my problem btw

1 Like

has anyone compared babylon animation performance to GSAP? I’m interested to know because it is by far the most performant javascript animation engine out there. I used it on a babylon camera myself like this :

function lookAt() {

        if (isActionCameraActive) {

            gsap.to(applicationCache.bl.camera, {alpha: (90+((2.5 - positionIndexCurrent)/2.5)*camAlphaMax) * 0.01745329251,beta: (90+((1.5 - (floorIndexCurrent-1))/1.5)*camBetaMax) * 0.01745329251});

        }

    }
1 Like

Hey guys, I have written an example for you so that you can check the code and see what is going on with my problem. If you can open my example and try to click the buttons to change the camera, you would see the extreme collide of camera vision, which I’ve been confused for a long time.
@inteja @Blake @labris @bghgary @PolygonalSun @carolhmj
thanks for you guys!
BTW, I have solved the collide of vision by changing the animation order:
camera.animations = [animatePos,animateVec]
camera.animations = [animateVec,animatePos]
if you try this you can see a big difference, but I wonder why it is so different.
So here is my code, just simply copy it to a html file and run it would be good.
I dont know why my html tags changed to dom element, so I changed them with , be careful with that.

[html]
[body]
[canvas id=“canvasID” style=“width:100%;height:100%”][/canvas]
[button onclick=“toPos1()”]position1[/button]
[button onclick=“toPos2()”]position2[/button]
[script src=“https://cdn.babylonjs.com/babylon.js”][/script]
[script]
class SceneImpl{
constructor(canvas){
let engine = new BABYLON.Engine(canvas, true);
this._scene = new BABYLON.Scene(engine);
this._camera = new BABYLON.ArcRotateCamera(“camera1”,0,0,500,new BABYLON.Vector3(0,0,0),this._scene);
this._camera.upVector = new BABYLON.Vector3(-0.178,0.394,0.901);
let light = new BABYLON.PointLight(“light1”,new BABYLON.Vector3(1,1,1),this._scene);
this._scene.registerBeforeRender(()=>{
light.position = this._camera.position.scale(100);
light.direction = -this._camera._position;
});
engine.runRenderLoop(()=>{
this._scene.render();
})
}
}
let animationCamera = function(a_position,a_up_vector){
let camera = impl._camera;
let framerate = 20;
let animateVec = new BABYLON.Animation(“animVec”,“upVector”,framerate,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
let keyframePos = ;
keyframePos.push({frame:0,value:camera.upVector});
keyframePos.push({frame:20,value:a_up_vector});
animateVec.setKeys(keyframePos);
let animatePos = new BABYLON.Animation(“animPos”,“position”,framerate,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
let keyframePos1 = ;
keyframePos1.push({frame:0,value:camera.position});
keyframePos1.push({frame:20,value:a_position});
animatePos.setKeys(keyframePos1);
camera.animations = [animatePos,animateVec];
impl._scene.beginAnimation(camera,0,40,false,2);

}
let impl = new SceneImpl(document.getElementById(“canvasID”));
let box = new BABYLON.MeshBuilder.CreateBox(“box”,{size:100},impl._scene);
function toPos1(){
animationCamera (new BABYLON.Vector3(-353.55,0,-353.55),new BABYLON.Vector3(-0.707,0,0.707));
}
function toPos2(){
animationCamera (new BABYLON.Vector3(0,0,-500),new BABYLON.Vector3(0.000001,-1,0));
}

[/script]
[/body]

[/html]

Could you put this example to Playground?
Otherwise it may be really difficult to help.

1 Like

will do on next Monday!

Hi @labris I finished my playground repo here:
sample.zip (6.3 KB)

or you can check the code here and copy it to PG

var createScene = function () {
// This creates a basic Babylon Scene object (non-mesh)
var scene = new BABYLON.Scene(engine);

// This creates and positions a free camera (non-mesh)
var camera = new BABYLON.ArcRotateCamera("camera1",0,0,500,new BABYLON.Vector3(0,0,0),this._scene);
camera.upVector = new BABYLON.Vector3(-0.178,0.394,0.901);

// This creates a light, aiming 0,1,0 - to the sky (non-mesh)
var light = new BABYLON.PointLight("light1",new BABYLON.Vector3(1,1,1),this._scene);
scene.registerBeforeRender(()=>{
    light.position = camera.position.scale(100);
    light.direction = camera._position;
});

var animationCamera = function(a_position,a_up_vector){
    let framerate = 20;
    let animateVec = new BABYLON.Animation("animVec","upVector",framerate,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
    let keyframePos = [];
    keyframePos.push({frame:0,value:camera.upVector});
    keyframePos.push({frame:20,value:a_up_vector});
    animateVec.setKeys(keyframePos);
    let animatePos = new BABYLON.Animation("animPos","position",framerate,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
    let keyframePos1 = [];
    keyframePos1.push({frame:0,value:camera.position});
    keyframePos1.push({frame:20,value:a_position});
    animatePos.setKeys(keyframePos1);
    camera.animations = [animatePos,animateVec];
    scene.beginAnimation(camera,0,40,false,2);

}
    var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
var guiButton = BABYLON.GUI.Button.CreateSimpleButton("guiButton", "pos1");
guiButton.width = "200px"
guiButton.height = "40px";
guiButton.color = "white";
guiButton.cornerRadius = 10;
guiButton.background = "blue";
guiButton.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
guiButton.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
guiButton.top = -50;
    var guiButton1 = BABYLON.GUI.Button.CreateSimpleButton("guiButton", "pos2");
guiButton1.width = "200px"
guiButton1.height = "40px";
guiButton1.color = "white";
guiButton1.cornerRadius = 10;
guiButton1.background = "blue";
guiButton1.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
guiButton1.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
guiButton1.top = 0;
advancedTexture.addControl(guiButton);
advancedTexture.addControl(guiButton1);

guiButton.onPointerDownObservable.add(()=>{animationCamera (new BABYLON.Vector3(-353.55,0,-353.55),new BABYLON.Vector3(-0.707,0,0.707))});
guiButton1.onPointerDownObservable.add(()=>{animationCamera (new BABYLON.Vector3(0,0,-500),new BABYLON.Vector3(0.000001,-1,0))});
// Our built-in ‘sphere’ shape.
var box = new BABYLON.MeshBuilder.CreateBox(“box”,{size:100},scene);

return scene;

}

Hey there, I modified your PG to animate alpha and beta. I wonder if animating those will work for you or if not could you explain more what you’re trying to do with the up vector? The original diagram seems to only show the alpha changing so I’m not sure. :slight_smile:

2 Likes

If you can imagine an airplane which can rotate around three axis(yaw,pitch and roll), and link it to a BABYLON camera, you would know what I’m trying to do :smiley:
ArcRotateCamera have alpha and beta so it can rotate along two directions (like yaw and pitch in airplane), but there is no such variable that controll how the camera rolls by itself, it is like you are looking at somewhere with your head tilted to the side, which is why I use upVector, since it tells the camera which direction is considered as up, so I can control the rolling state of the camera.
@carolhmj drew a picture earlier in this question, imagine the camera rotate along FWD direction (the blue arrow), it explains what I am trying to do.
Hope I made myself clear.

2 Likes