How do i render a Tween animation using "on demand rendering" instead of a render loop?

Hi,

I’m building a 3D lobby with Blender and Three.js, with various doorways around my scene which, when clicked, will cause the camera to animate over to the doorway and open a popup. This is my first proper Three.js projects so i haven’t got much experience!

I’m using the Tween.js library to animate my camera positions on click, and it works fine when i include TWEEN.Update(); in a render loop. The problem is, because i’m using a render loop, my scene is rendering all the time when it really only needs to render when A) the user clicks a doorway to trigger the tween, or B) the OrbitControls are used.

If I remove the render loop I CAN get the the scene updating with OrbitControls using

controls.addEventListener( 'change', render);

However, I don’t know how to render the tween animation anymore. Could anybody point me in the right direction? i almost need a loop that only runs on demand and then stops.

My move function is included below. Target lookAt co-ordinates (TargetObject X,Y,Z) and camera position (camera X,Y,Z) and animation length in time (time) are passed into the function:

//ANIMATE CAMERA TO NEW POSITION

function moveTo(targetObjectX, targetObjectY, targetObjectZ, cameraX, cameraY, cameraZ, time) {
  
  // SET START AND END POSITIONS FOR THE CAMERA
  var from = {
    x: camera.position.x,
    y: camera.position.y,
    z: camera.position.z,
    lookx: currentTargetObjectX,
    looky:currentTargetObjectY,
    lookz:currentTargetObjectZ,
  };

  var to = {
    x: cameraX,
    y: cameraY,
    z: cameraZ,
    lookx:targetObjectX,
    looky:targetObjectY,
    lookz:targetObjectZ,
  };
  
  tween = new TWEEN.Tween(from)
    .to(to, time)
    .easing(TWEEN.Easing.Quadratic.InOut) 
   
    .onUpdate(function () {
      // SET CAMERA POSITION AND ROTATION THAT THE CAMERA WILL START THE ANIMATION FROM
      camera.position.set(from.x, from.y, from.z);
      camera.lookAt(
        from.lookx, from.looky, from.lookz
      );
    })
    .onComplete(function () {
      
      document.body.style.cursor = "default";
      // OPEN AN INFORMATION POPUP IF REQUIRED
      if (popUpOpen == true) {
      setTimeout (function() {modalInner.classList.remove("hidden"); }, 300);
      
      }

    })
    .start();
  }

As I said the function worked fine when i included a render loop originally (below):

// ----------------- UPDATE FUNCTIONS (THESE DRAW THE SCENE AND UPDATE IT ON CHANGES) ------------------

// GAME LOGIC
var update = function( ){
  TWEEN.update();
};

// DRAW SCENE
var render = function( ){
  renderer.render( scene, camera);
};

// RUN GAME LOOP (UPDATE, RENDER, REPEAT)
var GameLoop = function( ) {
  requestAnimationFrame (GameLoop);
  update( );
  render( );
};

// RUN UPDATE FUNCTION AT LEAST ONCE (IT WILL BE AUTOMATICALLY REPEATED WITHIN THE FUNCTION)
GameLoop( );

Any help will be gratefully received!

try calling render() in your tweens onUpdate callback.
eg,

tween = new TWEEN.Tween(from)
.to(to, time)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(function () {
  // SET CAMERA POSITION AND ROTATION THAT THE CAMERA WILL START THE ANIMATION FROM
  camera.position.set(from.x, from.y, from.z);
  camera.lookAt(
    from.lookx, from.looky, from.lookz
  );
  render()
})
.onComplete(function () {
...
etc
2 Likes

Hi @seanwasere, that makes perfect sense but still doesn’t work. My render function is now simply this:

function render() {
renderer.render( scene, camera);
}

does it need anything else?

You still need to call Tween.update in the loop, otherwise onUpdate won’t fire.

Normally, what I do for this situation is, whenever you want the tween to play, disable the controls and start the loop. Then, in onComplete, stop the loop and re-enable the controls.

View my example on this page.
On Demand Rendering Using Tween : https://sbcode.net/extra_html/tween.html
You can see the source code using the <> button at bottom right.

Double click anywhere on the floor in the example.

In the source code,

  • Take note of my animation loop with the render call commented out and see what else i’m doing.
  • Look at the tween commands where I use the onUpdate callback.
  • Look at the controls code where I also call render
  • Look at all the sections in the code where there is a comment “this line is unnecessary if you are re-rendering within the animation loop”

The example comes from this page : https://sbcode.net/threejs/tween/

2 Likes

That works!

Thanks @seanwasere (and also @looeee).

So just to clarify for anyone else that needs this solution, call render() in your Tween onUpdate callback and use the animate and render functions below:

function animate() {
requestAnimationFrame(animate);
TWEEN.update();
//render();
}

// DRAW SCENE
function render( ){
renderer.render( scene, camera);
console.log(‘rendering’);
};
animate();

I added a console.log in the render function just so i could check it wasn’t rendering when idle.

Thanks again!