Jump to content

tweening in babylon?


Recommended Posts

I've been using tween.js with three.js with good results for auto animating camera with hotkeys.


is there something simmilar that will work with babylon?


what I'm trying to achieve for example - press key '1' and camera tweens to a certain location along a path

press key '2' and camera goes to a different location.


any ideas to set me on the right path would be much appreciated.



Link to comment
Share on other sites

We can almost do that right now.

You can at anytime create an animation from the current position to a specific position and launch it:

            var keys = [                {                    frame: 0,                    value: this.position                }, {                    frame: 100,                    value: newPosition                }            ];            var dataType = Animation.ANIMATIONTYPE_VECTOR3;            var animation = new BABYLON.Animation("myTweenedAnimation", this.position, 100, dataType, Animation.ANIMATIONLOOPMODE_CONSTANT);            animation.setKeys(keys);            scene.beginDirectAnimation(this, [animation], 0, 100);
Link to comment
Share on other sites

thanks DeltaKosh - using that code in conjunction with  window.addEventListener("keydown", function (event) -

and reading this great tutorial http://blogs.msdn.com/b/davrous/archive/2014/02/19/coding4fun-tutorial-creating-a-3d-webgl-procedural-qrcode-maze-with-babylon-js.aspx


window.addEventListener("keydown", function (event) {
        //left wall
        //hotkey no. 1
        if (event.keyCode === 49 || event.keyCode === 97) {
            animateCameraPositionAndRotation(camera, camera.position,
                new BABYLON.Vector3(LWallXCamera, cameraHeight, startPos),
                new BABYLON.Vector3(0, faceLeft, camera.rotation.z));
now to see if I can chain animations to make camera move around objects ;)
great forum - thanks!
Link to comment
Share on other sites

  • 2 years later...


     Here is a brief on Tween.js.

          3 Examples Applying Tween.js with Babylon.js: http://anymscape.com/BJSDEMOS/tweendemo4/

          Tween concept was innovated at Pixar at some point (I think), Catmull, etc. This integration is pretty straight-forward. Maybe even harmonious.

          It has good modular packaging for myriad-interpolation-variations. Kind of like a pocket-sized power tool. Most interesting, it gives a cross-context "hybrid-interface" of rich 2D And 3D visual animations.... in the last example.

         Example 1: Hybrid UI - interface-level, just like jquery, d3, etc... moving stuff around.

         Example 2: Complex UI - chain html into rich-components like this (font-awesome) starbar.

         Example 3: 3D world mix - this one is really interesting. RequestAnimation Meld with BeforeRender Loop.

            Because of the nature of the examples, I'll drop the code here. I can do a github. 

           Example 1: Moving a simple txtBox horizontally with a nice Cubic Interpolation Curve:

                                - setup - easy:

    <script src="../lib/tweenjs/stats.min.js"></script><!--optional bonus points-->
    <script src="../lib/tweenjs/Tween.js"></script>
    <script src="../lib/tweenjs/RequestAnimationFrame.js"></script>

                                - minor tricky part next. This master loop needs to go at the bottom of the code. Just like render loops, always have to go last. Infinite loops are so self-centered.

       - Loop for all TWEENJS interpolation updates. Without '.update()' call no TWEENS run.
      function TWEEN_LOOP(time) { 
        TWEEN.update(time); //trigger all tween interpolation updates.
        requestAnimationFrame(TWEEN_LOOP); //recursion, TWEEN_LOOP.

                                  - So put at bottom, and now you can tween 'all the things'... Weird on brain? Yes, it will improve and make sense L8r... Now add initTweens() method like this: 

    <div id="txtBox1" class="csstrick" style="position:absolute; top:100px; left:10px; width:150px; height:20px; background:#a0dde9; padding:15px; border:3px solid #ccc; border-radius:8px; z-index:102; text-align:center;"> tweenjs&babylonjs </div>
      //init tween by object handle
      var dynamicState = { x:50, w:150, h:20}, targetState = { x:400}, txtBoxDiv = document.getElementById('txtBox1');
      //tween in object format.
      var txtboxTweenRight = new TWEEN.Tween(dynamicState).to(targetState, 2000 );
      txtboxTweenRight.onUpdate(function(){ txtBoxDiv.style.left = dynamicState.x+'px';/*console.log('txtbox: '+this.x)*/}); //interpolation steps
      txtboxTweenRight.onComplete(function(){/*console.log('right: done')*/}) //end of tween callback.
      txtboxTweenRight.delay( 44 );
      //init tween with chaining...
      var txtboxTweenLeft = new TWEEN.Tween(dynamicState).to({x: 10}, 2000 ).easing(TWEEN.Easing.Cubic.Out).delay( 44 )
        .onUpdate(function(){ txtBoxDiv.style.left = dynamicState.x+'px'})
        .onComplete(function(){/*console.log('left: done')*/}) //end of tween callback.
      //animate in succession
      var txtBoxAnimation = function(){
          // txtboxTweenLeft.chain(txtboxTweenRight);
      var txtboxtweenWidth = new TWEEN.Tween(dynamicState).to({w: 600}, 2000 ).easing(TWEEN.Easing.Cubic.Out).delay( 44 )
        .onUpdate(function(){ txtBoxDiv.style.width = dynamicState.w+'px'})
        .onComplete(function(){/*console.log('left: done')*/}) //end of tween callback.
      var txtboxtweenHeight = new TWEEN.Tween(dynamicState).to({h: 500}, 2000 ).easing(TWEEN.Easing.Cubic.Out).delay( 44 )
        .onUpdate(function(){ txtBoxDiv.style.height = dynamicState.h+'px'})
        .onComplete(function(){/*console.log('left: done')*/}) //end of tween callback.
      var txtBoxSizeAnimation = function(){

              - That is all the code. You'll get a <div> that goes right then left. And if you un-comment a line,  it will go right then left forever. With nice cubic-out interpolation curves and a hybrid-interface html-overlay via AnimationFrame.

Next, tweening a complex component (star-bar).

Link to comment
Share on other sites

Example 2. A StarBar: http://anymscape.com/BJSDEMOS/tweendemo4/

    Description: It accordions in and out, incrementally highlighting stars in ':blue' and then when 10 are completed, increments totalcount and total star in ':yellow'. Which gives the UX to make you feel like a winner.

    Here is the code:

      <div id="starbar">
        <div class='icotrophy'><i id="icotrophy" title="stars" class="fa fa-star" style='color:#444;'></i> </div>
        <div id="starCount">0</div>
        <span id="starDivider">|</span>
        <div class='icostar' id="icostarz1"><i title="stars" class="fa fa-star"></i></div> 
        <div class='icostar' id="icostarz2"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz3"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz4"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz5"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz6"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz7"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz8"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz9"><i title="stars" class="fa fa-star"></i></div>
        <div class='icostar' id="icostarz10"><i title="stars" class="fa fa-star"></i></div>
        border-radius: 20px;
        background-color: blue;
        border: 1px solid #666;
        /*line-height: 1.4;*/
        /*white-space: nowrap;*/
    .icostar, .icotrophy{
      /*text-shadow: 0 -1px 1px black;*/

    #icostarz1, #icostarz2, #icostarz3, #icostarz4, #icostarz5, #icostarz6, #icostarz7, #icostarz8, #icostarz9, #icostarz10{

      var starBarExpand, starBarCollapse, starBarAnimation, starBarFull=false, starBarEmpty=false; //composite-memebers-design-pattern.
      // txtBoxAnimation;
      function tweenInit_Starbar() {
        var icostarz = document.getElementsByClassName('icostar');
        var icotrophy = document.getElementById('icotrophy');
        var countDiv = document.getElementById('starCount');
        var starbar = document.getElementById('starbar');
        var tweenState_Starbar = {width: 75 };
        var starCount = 0, visCount = 0;
        starBarAnimation = function(){
        starBarExpand = new TWEEN.Tween(tweenState_Starbar).to({width:360}, 2000).delay(44).easing(TWEEN.Easing.Cubic.Out)
            starbar.style.width = tweenState_Starbar.width+'px';
            //show stars at position.
            if(visCount<1&&parseInt(tweenState_Starbar.width)>=100){icostarz[0].style.opacity=1; icostarz[0].children[0].style.color='#000'; visCount++;}
            if(visCount<2&&parseInt(tweenState_Starbar.width)>=130){icostarz[1].style.opacity=1; icostarz[1].children[0].style.color='#000'; visCount++;}
            if(visCount<3&&parseInt(tweenState_Starbar.width)>=160){icostarz[2].style.opacity=1; icostarz[2].children[0].style.color='#000'; visCount++;}
            if(visCount<4&&parseInt(tweenState_Starbar.width)>=190){icostarz[3].style.opacity=1; icostarz[3].children[0].style.color='#000'; visCount++;}
            if(visCount<5&&parseInt(tweenState_Starbar.width)>=220){icostarz[4].style.opacity=1; icostarz[4].children[0].style.color='#000'; visCount++;}
            if(visCount<6&&parseInt(tweenState_Starbar.width)>=250){icostarz[5].style.opacity=1; icostarz[5].children[0].style.color='#000'; visCount++;}
            if(visCount<7&&parseInt(tweenState_Starbar.width)>=280){icostarz[6].style.opacity=1; icostarz[6].children[0].style.color='#000'; visCount++;}
            if(visCount<8&&parseInt(tweenState_Starbar.width)>=310){icostarz[7].style.opacity=1; icostarz[7].children[0].style.color='#000'; visCount++;}
            if(visCount<9&&parseInt(tweenState_Starbar.width)>=340){icostarz[8].style.opacity=1; icostarz[8].children[0].style.color='#000'; visCount++;}
            if(visCount<10&&parseInt(tweenState_Starbar.width)>=355){icostarz[9].style.opacity=1; icostarz[9].children[0].style.color='#000'; visCount++;}
            icotrophy.style.color = '#8facd5'; //lightblue

        starBarCollapse = new TWEEN.Tween(tweenState_Starbar).to({width: 75 }, 2000).easing(TWEEN.Easing.Cubic.Out).delay( 44 )
            starbar.style.width = tweenState_Starbar.width+'px';
            //hide stars at position
            if(visCount===1&&parseInt(tweenState_Starbar.width)<=100){icostarz[0].style.opacity=0; visCount--;}
            if(visCount===2&&parseInt(tweenState_Starbar.width)<=130){icostarz[1].style.opacity=0; visCount--;}
            if(visCount===3&&parseInt(tweenState_Starbar.width)<=160){icostarz[2].style.opacity=0; visCount--;}
            if(visCount===4&&parseInt(tweenState_Starbar.width)<=190){icostarz[3].style.opacity=0; visCount--;}
            if(visCount===5&&parseInt(tweenState_Starbar.width)<=220){icostarz[4].style.opacity=0; visCount--;}
            if(visCount===6&&parseInt(tweenState_Starbar.width)<=250){icostarz[5].style.opacity=0; visCount--;}
            if(visCount===7&&parseInt(tweenState_Starbar.width)<=280){icostarz[6].style.opacity=0; visCount--;}
            if(visCount===8&&parseInt(tweenState_Starbar.width)<=310){icostarz[7].style.opacity=0; visCount--;}
            if(visCount===9&&parseInt(tweenState_Starbar.width)<=340){icostarz[8].style.opacity=0; visCount--;}
            if(visCount===10&&parseInt(tweenState_Starbar.width)<=370){icostarz[9].style.opacity=0; visCount--;}
          .onComplete(function() {
              countDiv.innerHTML = ++starCount; //increment txt number.
              icotrophy.style.color = 'yellow'; //goldstar for reading this far

        //chaining example, enstead fit into gameplay via requestAnimationFrame.
        // starBarExpand.chain(starBarCollapse);
        // starBarCollapse.chain(starBarExpand);

       //updated master loop....       
       - Loop for all TWEENJS interpolation updates. Without this call no TWEENS run.hybrid.
      function TWEEN_LOOP(time) { 
        TWEEN.update(time); //trigger all tween interpolation updates.
        //(optional)flag runtime animations within TWEEN_LOOP
        }else if(starBarEmpty){
        requestAnimationFrame(TWEEN_LOOP); //recursion, TWEEN_LOOP.

          - Results, this starbar is ok. It has some needs (fontawesome icon wrapping - not hiding always, and needs dynamic width count ).

                <link rel="stylesheet" href="../lib/font-awesome/font-awesome-4.7.0/css/font-awesome.min.css">

     Why use with Babylon? Because adds a hybrid-2D-ui-overlay-interface? I agree it may even give you double-loops - which - I hope experts chime in. It seems to me this is mixing cpu loops and gpu loops... on deeper research, seems AnimationFrame can hit GPU depending on context, so, performance hit undetermined. Or maybe it is good to keep lower importance stuff like 2d ui layer interpolation out of gpu optimized code. Curious...


     Anyway, that is 2 cents on tween.js used as an overlay to babylon canvas. Next, it is possible to combine the loops.

Link to comment
Share on other sites

Example 3: A Big Sphere Eats a Little Sphere - or you just imagined that: http://anymscape.com/BJSDEMOS/tweendemo4/

This is only a TEST:

       - Loop for all TWEENJS interpolation updates. Without this call no TWEENS run.
       - use this loop to signal calculation updates from BJS to Tween.js. Idk. Risky?!!  
            scene.registerBeforeRender(function() {
                //tweenjs integration with babylonjs. vcool. this runs all TWEEN interpolations.
                TWEEN.update( window.performance.now() );

 Here is the tween of circles that intersect (similar to a tween.js example, but in 3D, because it is operating on BabylonJS components.

            /*---------------Mixing-TWEENJS && BabylonJS-------------------*/
                var targetOrb, targetOrbState, targetTween; //Member-composite-pattern.
                var trackingOrb, trackingOrbState, trackingTween; //Member-composite-pattern.
                var initOrbTween = function(){
                    targetOrb = new BABYLON.Mesh.CreateSphere("sphere", 14, 1, scene);
                    targetOrb.position= new BABYLON.Vector3(0,10,40);
                    targetOrbState = { x:targetOrb.position.x, y: targetOrb.position.y, z:targetOrb.position.z };
                    targetTween = new TWEEN.Tween( targetOrbState ).to( { x: 10, y: 20, z:-70 }, 4000 ).onUpdate( function() {
                    }).onComplete(function() { });
                    // } ).start();

                    trackingOrb = new BABYLON.Mesh.CreateSphere("sphere", 14, 2, scene);
                    trackingOrb.position= new BABYLON.Vector3(-20,10,10);
                    trackingOrbState = { x:trackingOrb.position.x, y: trackingOrb.position.y, z:trackingOrb.position.z };
                    // new TWEEN.Tween( trackingOrbState ).to( { x: -10, y: 20, z:10 }, 3000 ).onUpdate( function() {
                    trackingTween = new TWEEN.Tween( trackingOrbState ).to(targetOrbState, 4000 ).onUpdate( function() {
                    }).onComplete(function() {
                          // forwardBackward = !forwardBackward; //toggle to go forward.


                babylonSphereAnimation = function(){

       - Loop for all TWEENJS interpolation updates. Without this call no TWEENS run.
       - use this loop if you want to signal calculation updates from BJS to  
            scene.registerBeforeRender(function() {
                //tweenjs integration with babylonjs. vcool. this runs all TWEEN interpolations.
                TWEEN.update( window.performance.now() );


        return scene;

One more thing, button handlers in a testing apparatus, for animation method onclick testing:

      document.getElementById('btn1').onclick = function(e){ 

      document.getElementById('btn2').onclick = function(e){ 

      var babylonSphereAnimation;
      document.getElementById('btn3').onclick = function(e){ 

      document.getElementById('btn4').onclick = function(e){ 
      document.getElementById('btn5').onclick = function(e){ 

      document.getElementById('btn6').onclick = function(e){ 


All in all - 2D overlay animations, not so bad. Free is cheaper than Greensock. And mixing TweenLoop with 3D beforeRender is possible, but needs performance review. The ending code is confusing to understand the tween-clumps. But stepping through the three steps really helps to comprehend the strange tween syntax.

Ok, hope this is useful, bye. : )


Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...