user1378824
user1378824

Reputation: 207

How to stop rotation in three.js

Honorable coders, I use an html5 slideshow where I have added the rotating mesh landscape (https://github.com/jeromeetienne/threex.terrain). Because this animation slows down other part of the slideshow I want to shut it down when I move to the next slide. I can call a function when the next slide is shown, however, I do not know how to shut down the rotation or simply stop the function. I have tried removing the element 'front_id' that contains the rotating landscape but that does not seem to help and looking at the performance log the GPU is running crazy even when the element is deleted. Any solutions?

My updated failed attempt:

<script type="text/javascript">

var id_an;

function run_land(){

var renderer  = new THREE.WebGLRenderer({
  antialias : true
});
renderer.setSize( window.innerWidth+600, window.innerHeight );
var the_dom = renderer.domElement;
the_dom.id = 'land_id';
document.getElementById('front_id').appendChild(the_dom);
var onRenderFcts= [];
var scene = new THREE.Scene();
var camera  = new THREE.PerspectiveCamera(25, 
window.innerWidth/window.innerHeight, 0.01, 1000);
camera.position.z = 15; 
camera.position.y = 2;
scene.fog = new THREE.Fog(0x565656, 10, 45);
;(function(){
  var light = new THREE.AmbientLight( 0x202020 );
  scene.add( light );
  var light = new THREE.DirectionalLight('white', 5);
  light.position.set(0.5, 0.0, 2);
  scene.add( light );
  var light = new THREE.DirectionalLight('white', 0.75*2);
  light.position.set(-0.5, -0.5, -2);
  scene.add( light );
})()
var heightMap = THREEx.Terrain.allocateHeightMap(512,256);
THREEx.Terrain.simplexHeightMap(heightMap);
var geometry  = THREEx.Terrain.heightMapToPlaneGeometry(heightMap);
THREEx.Terrain.heightMapToVertexColor(heightMap, geometry);
var material  = new THREE.MeshBasicMaterial({
  wireframe: true
});
var mesh  = new THREE.Mesh( geometry, material );
mesh.name = 'the_mesh_name';
scene.add( mesh );
mesh.lookAt(new THREE.Vector3(0,1,0));
mesh.scale.y  = 4.5;
mesh.scale.x  = 5;
mesh.scale.z  = 0.30;
mesh.scale.multiplyScalar(10);
onRenderFcts.push(function(delta, now){
  mesh.rotation.z += 0.2 * delta; 
})

onRenderFcts.push(function(){
  renderer.render( scene, camera );   
})
var lastTimeMsec= null;
function animate(nowMsec){
  requestAnimationFrame( animate );
  lastTimeMsec  = lastTimeMsec || nowMsec-1000/60;
  var deltaMsec = Math.min(200, nowMsec - lastTimeMsec);
  lastTimeMsec  = nowMsec;
  onRenderFcts.forEach(function(onRenderFct){
    onRenderFct(deltaMsec/5000, nowMsec/5000);
  });  
}
id_an = requestAnimationFrame(animate);
}

var end_landscapes = (function() {
  return function() {

  console.log("the id: "+id_an); //this always returns id_an = 4
  cancelAnimationFrame(id_an);
  };

})();

</script>

Thanks TheJim01 you are definitely right. Not sure what I am doing wrong. Here I am defining the animationFrame variable globally but still I am unable to cancel it.

Upvotes: 0

Views: 1994

Answers (1)

TheJim01
TheJim01

Reputation: 8876

Close, but not quite. Look at what you have here:

function animate(nowMsec) {
  requestAnimationFrame(animate);
  lastTimeMsec = lastTimeMsec || nowMsec - 1000 / 60;
  var deltaMsec = Math.min(200, nowMsec - lastTimeMsec);
  lastTimeMsec = nowMsec;
  onRenderFcts.forEach(function(onRenderFct) {
    onRenderFct(deltaMsec / 5000, nowMsec / 5000);
  });
}
id_an = requestAnimationFrame(animate);

You're assigning id_an with the ID of the first call to requestAnimationFrame, but you're not assigning it to IDs of the calls inside animate. Every call to requestAnimationFrame returns a unique ID, and you need to be able to cancel the most recent one to kill the loop.

Try this:

function animate(nowMsec) {
  id_an = requestAnimationFrame(animate);
  lastTimeMsec = lastTimeMsec || nowMsec - 1000 / 60;
  var deltaMsec = Math.min(200, nowMsec - lastTimeMsec);
  lastTimeMsec = nowMsec;
  onRenderFcts.forEach(function(onRenderFct) {
    onRenderFct(deltaMsec / 5000, nowMsec / 5000);
  });
}
animate();

With this small change, id_an gets updated every frame with the latest ID, so when you call cancelAnimationFrame it will cancel the most recent one (which is the one you want to cancel).

Also, you don't need to call requestAnimationFrame to start the loop. Calling animate(); at the end will get things rolling, including subsequent calls to requestAnimationFrame.

Upvotes: 1

Related Questions