Forum

Procedural camera position/rotation tweening

21 September 2015 22:00
Situation:

We are trying to implement blend4web into our project. A scene with multiple cameras positioned in various places is loaded into our app. We want to be able to read position and rotation of a chosen camera that exists in loaded scene and then tween the active camera to that position by changing its position and rotation every frame for a duration of tween.

(Please note that all of the code presented here is a pseudo-code.)

We are using “transform” module to retrieve target camera’s position:

var camTrans:Vec3 = request(“transform”).get_translation( myTargetCamera );

and set the target camera’s position by using:

request(“transform”).set_translation( myActiveCamera, newPositionX, newPositionY, newPositionZ );

This part works as expected.

When we are retrieving target camera’s rotation using “transform” module:

var camRotation:Quad = require(“transform”).get_rotation( myTargetCamera );

we get rotation values that seem to be incorrect.


For example when we export Blend4Web file from Blender I can see that “camera_01” is set to position of
x= 1.854, y= 3.409, z= -3.953
and its rotation to (in quat)
x=0.558, y=0.224, z=0.286 and w=0.746


After loading the file in our app and reading “camera_01” position and translation, translation numbers (x,y,z) are identical to what we see in Blender at export but the rotation values are incorrect:
x=0.428, y=0.195, z=-0.095 and w=0.877.


Questions:

How can we get correct camera rotation that is the same as it was in Blender at export?
How can we tween camera position and rotation from on-enter-frame-render approach.


Example of what we are trying to do (in pseudo-code):

var targetPosition:Vec3 = require(“transform”).get_translation( targetCamera );
var targetRotation:Quat = require(“transform”).get_rotation( targetCamera );

this.addEventListener( “onEnterFrame”, render );
Tween.To( currentPosition, tweenDurationTime, {x:targetPosition.x, y:targetPosition.y, z:targetPosition.z } );
Tween.To( currentRotation, tweenDurationTime, {x:targetRotation.x, y:targetRotation.y, z:targetRotation.z, w:targetRotation.w } );


function render() {
require(“transform”).set_translation( myActiveCamera, curentPosition.x, curentPosition.y, curentPosition.z );
require(“transform”).set_rotation( myActiveCamera, curentRotationQuat.x, curentRotationQuat.y, curentRotationQuat.z, curentRotationQuat.w );
}




Thank you.
22 September 2015 14:26
Hi!

How can we get correct camera rotation that is the same as it was in Blender at export?
Each camera can change its rotation during the scene initialization. It depends on the "Move Style" property which means different constraints, e.g. vertical aligning. You can set the "STATIC" move style for all of the scene cameras, so they won't be affected at all.

How can we tween camera position and rotation from on-enter-frame-render approach.
This can be done by using our sensors system.

Generally, we need to create a sensor manifold to process camera animation:
m_controls.create_sensor_manifold(camobj, "CAMERA_TWEENING", m_controls.CT_CONTINUOUS,
        [t_sensor, e_sensor], logic_func, cam_move_cb);


For this we need to create an elapsed sensor (to slightly move the camera every frame) and a timeline sensor (to count tweening time):
var t_sensor = m_controls.create_timeline_sensor();
var e_sensor = m_controls.create_elapsed_sensor();


Also we need to define a logic function which checks the total time passed and signalizes us about the animation ending.

var logic_func = function(s) {
    return s[0] - _global_timeline < TWEENING_TIME;
}


Sensor manifold executes a callback depending on the result of the logic function:

var cam_move_cb = function(camobj, id, pulse) {

        if (pulse == 1) {
            // we're in the middle of the animation

            // calculate an amount of time passed since the animation start
            var elapsed = m_controls.get_sensor_value(camobj, id, 1);
            _delta += elapsed / TWEENING_TIME;

            // perform linear intrerpolation beetween starting and ending position/rotation based on the global _delta parameter

            // set new transforms
        } else {
            // finishing the animation: set ending position/rotation to avoid possible calculation errors
        }
    }


A manifold of this type (CT_CONTINUOUS) generates positive pulse every time when a logic function returns true (animating every frame) and a single negative pulse otherwise (finishing the animation).

We need to reset our global variables when the animation starts:
function start_animation() {
    _global_timeline = m_main.global_timeline();
    _delta = 0;
}


Please, also take a look at the Camera Animation code snippet. Something similar is happening in the "init_camera_animation" function.
22 September 2015 16:19
I work with serge. We do not want to use your animation, really all we want to do is use blend4web's rendering capabilities and blender export features. We have a system for developing apps and animating. The core of what we want to do is always.

Each frame we have our own render() method where we

function render(){
      updateCameraTargetTransform();
      updateCameraraPosition();
      cameraLookAtTarget();      
}


This way we can use our own tweening solution to animate the camera target and the camera. Our API allows us to interchange different 3D rendering methods.

function animateToCamera( animationTime, cameraName){
     var cam =  IScene.getCameraByName(cameraName);
      var camTarget= cam.getTarget();
          
      Tween.To(IScene.getCamTarget(), animationTime, {x:camTarget.x, y:camTarget.z, z.camTarget});
      Tween.To(IScene.getActiveCamera(), animationTime, {x:cam.x, y:cam.z, z:cam.z});
}


22 September 2015 17:29
Thank you very much for your response.

Setting cameras to STATIC solved the problem
22 September 2015 18:14

Setting cameras to STATIC solved the problem
Good to know! If you have any other questions we're glad to help.

This way we can use our own tweening solution to animate the camera target and the camera. Our API allows us to interchange different 3D rendering methods.

OK. If I understand you correctly, you want to perform tweening through the blend4web low-level API. Am I right?
23 September 2015 00:19
Not really. Most animation/tweening libraries we work with allow you to pass generic objects to the tweener and it will automatically adjust the properties/values over time - so for example:

Tween.to( camera, 2, {x:30, y:30:, z:30});


The above code will animate the supplied object - in this instance a camera, and over '2' seconds will animate the x,y,z properties until they reach the desired values.

Because your API is more of a functional approach, we don't have the control to adjust the X,Y,Z properties directly (or any other properties).

This is fine though since we just use interfaces for our objects - for example a our Camera Animator class will have
a 'target' and a 'camera' property which will both be of type IObject3D. We then create a concreted Blend4WebObject3D which just implements IObject3D - that allows us to set x,y,z (or whatever values) then internally in the Blend4WebObject3D we call the appropriate blend4web specific api.

By using the interface above, if for whatever reason we need to change 3D engines, we just need to create classes that implement our IObject3D interface- but our core application code does not need to change.





23 September 2015 08:20
Most animation/tweening libraries we work with allow you to pass generic objects to the tweener and it will automatically adjust the properties/values over time
Gotcha! I remember myself using similar tweening library when I was a Flash/ActionScript programmer.

Because your API is more of a functional approach, we don't have the control to adjust the X,Y,Z properties directly (or any other properties).
Yeah, we worked hard to disallow such things.

This is fine though since we just use interfaces for our objects - for example a our Camera Animator class will have
a 'target' and a 'camera' property which will both be of type IObject3D. We then create a concreted Blend4WebObject3D which just implements IObject3D - that allows us to set x,y,z (or whatever values) then internally in the Blend4WebObject3D we call the appropriate blend4web specific api.
I see. Looks like you already have a developed application framework and just want to replace the rendering engine. Good to hear that you found an appropriate solution. Please feel free to ask any further questions or even request missing features, we'll be happy to help!
The Founder | Twitter | Facebook | Linkedin
 
Please register or log in to leave a reply.