How can I control when render three js scene - javascript

All examples that I saw, uses a loop structure to render the scene, like that:
renderer.render(cena, camera);
function render(){
renderer.render(cena, camera);
//code to render
requestAnimationFrame(render);
}
render();
But I want to control the rendering in another structure, only when I interact with a thing... like
while(true){
//code - operations
alert('press ok to another step'); // or wait 2 sec
renderer.render(scene,camera);
}
What is the correct method to do this?

Of course, if you want, you can call renderer.render at anytime, although it would probably be a lot better to render it in the requestAnimationFrame() (much better performance).
If you really have a need to change something that you don't want to be renderer (say, several async functions modifying scene object), you can always do something like this.
function render(){
//code to update scene
if (toRender) renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
Set toRender to false while you're updating the scene, this prevent the renderer from re-drawing your scene, then set toRender back to true to have it draw the scene in the next frame.

as shown in this example, you can simply call renderer.render()
http://threejs.org/examples/#raytracing_sandbox

Related

Why is the call to requestAnimationFrame(render) commonly put at the top of a render function which thereby calls itself recursively?

I have seen it in many examples and often even official docs that use requestAnimationFrame in some form. For example:
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
why is requestAnimationFrame here put on top in the function body? To me it seems this could possibly cause congestion of the call stack or execution environment, because what happens if the render function is called by requestAnimationFrame before the rest of its function body has finished executing because the next animation frame became available?? (And the same for all subsequent calls, clogging things up)
To me it intuitively seems more sane to put the requestAnimationFrame(render); statement as the last statement of the function body. So this way the rest of the function is always guaranteed to have finished execution until another call to the render function is made.
Is there some internal mechanism I am missing or misunderstand and is putting it at the top actually the recommended approach or why is it seen so often? Please help me understand, thanks.
The render function will not be called before the current frame has been displayed, which will only occur after the current call to render has returned.
Let's say you are currently computing the nth frame. When you call requestAnimationFrame,the given callback is queued in the (n+1)th frame's queue. Next frame will be processed only after the current frame has been displayed.
This post pretty well describes the frames lifecycle and its relation to requestAnimationFrame.

Three js render a static scene

From the tutorial on setting up a basic scene here the standard way to call the renderer is something like:
function render() {
requestAnimationFrame( render );
renderer.render( scene, camera );
}
render();
However I am generating a static image so creating frames seems like overkill. Is there any way to render the scene once and then have the rendered image persist?
What I needed to do was delay the call to
this.renderer.render(this.scene, this.camera);
until after all calculations in the scene were finished. Calling it immediately after initialising the renderer was resulting in drawing a white screen as nothing else had been calculated yet.
As a stopgap measure I've put it in a window.setTimeout functions, but I guess the proper way to do it is to put it in a callback function when all the other calculations are finished.
Instead of calling render() just call renderer.render( scene, camera );

THREE.Object3D or scene or other class provide any tags or methods that I can detected my object has been changed?

Using three.js render obj model in browser.
Here is my logic of program:
function animate() {
requestAnimationFrame(animate);
render(scene, camera);
}
function render(scene, camera){
scene.traverse(function(object) {
scene = setLODDistance(scene, thresHold);
});
renderer.render(scene, camera);
}
animate();
function setLODDistance will return a scene object which has been calculated by LOD.
but I do not want to call this function every fps, I just want to call it after my object in browser been translated or rotated or scaling.
so in THREE.Object3D or scene or other class provide any tags or methods that I can detected my object has been changed(translated or rotated or scaling) ??
thx
You can try to use Object.watch(), poly fill here: link.

Using webworkers in THREE.js

I have a larger model that freeze my scene.
As I don't need this model from the beginning it would be cool to load this model in the background. Are webworkers a solution for this?
Can anyone guide me how to accomplish it , or is it possible at all ?
Thanks.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var loader = new THREE.JSONLoader();
loader.load("models.js", function (smooth) {
smooth.mergeVertices();
smooth.computeFaceNormals();
smooth.computeVertexNormals();
var modifier = new THREE.SubdivisionModifier(1);
modifier.modify(smooth);
var mesh = new THREE.Mesh(smoothnew THREE.MeshBasicMaterial({
color: 0x00ff00
}));
scene.add(mesh);
});
var render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
JavaScript is single threaded and uses "cooperative" scheduling for its events, which means that if you have a function with a long loop that doesn't give up its execution nothing else will be able to be executed in the meantime.
Your method in the loader is essentially that, a single method that'll run its computations to completion before allowing other JavaScript code to run. So rather than using a worker you might be able to split it up a bit by making it more event driven and improve the experience that way, something like this:
loader.load("models.js", function (smooth) {
smooth.mergeVertices();
smooth.computeFaceNormals();
smooth.computeVertexNormals();
window.setTimeout( function() {
var modifier = new THREE.SubdivisionModifier(1);
modifier.modify(smooth);
window.setTimeout( function() {
var mesh = new THREE.Mesh(smoothnew THREE.MeshBasicMaterial({
color: 0x00ff00
}));
scene.add(mesh);
}, 100 );
}, 100 );
});
(The points where I added setTimeout() are entirely arbitrary since I have no way of knowing where the biggest delays are without a jsfiddle to run your code + data).
This will only really work if none of these method calls themselves take up the majority of time. If e.g. mergeVertices() itself takes up most of the CPU time the only way to solve the freezing is by offloading that computation to a worker. The you'll need to pass the data around, compute it on the worker, and have the main code add it to the scene (the worker doesn't have access to the WebGL context). The complexity of that solution might not make the effort worth it however.
Workers are not suitable for a solution that requires DOM manipulation

ThreeJS Stop Rendering

I am working with ThreeJS on a basic 3d scene that has OrbitControls. Everything works great, except it causes my entire site to lag, as it is looping itself even when the user is not looking at it. I want a function that I can call to start and stop the rendering when certain conditions are met (in this case, the user isn't viewing the canvas). I have a start function that works just fine, but the stop function does not seem to be working, as my site goes unbearably slow after ThreeJS has initialized.
I have looked and looked for a solution to this problem, and have found a couple 'solutions', but for whatever reason they do not work with my application. My assumption is that these solutions are from old versions of ThreeJS.
Here is my code in my main.js file:
var scene,
camera,
controls,
render,
requestId = undefined;
function init() {
scene = new THREE.Scene();
var threeJSCanvas = document.getElementById("threeJS");
camera = new THREE.PerspectiveCamera( 75, threeJSCanvas.width / threeJSCanvas.height, 0.1, 1000 );
controls = new THREE.OrbitControls( camera );
// Controls and Camera settings
// Create Geometry.
}
function render() {
requestId = requestAnimationFrame(render);
renderer.render(scene, camera);
}
function start() {
render();
}
function stop() {
window.cancelAnimationFrame(requestId);
requestId = undefined;
}
In my other javascript file, there is a conditional inside of my pageChange function (this is a multipage app), that looks like the following:
if (page == 5) { // The page with the canvas on it
if (!locationsRendered) {
init();
locationsRendered = true;
}
} else { // If the page is not the page with the canvas on it
if (locationsRendered) {
stop();
}
}
locationsRendered is initialized earlier in this second javascript file in the local scope.
Any help would be much appreciated, as I can not let this simple 3D scene lag my entire app after it has been loaded. It's just not realistic.
If your scene is static, there is no reason for an animation loop. You only need to re-render when the camera moves due to a mouse or touch event.
Just use this pattern:
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
function render() {
renderer.render( scene, camera );
}
three.js r.67
I was using trackball controls in my scene and therefore couldn't use the solution above (as the trackball controls continue updating after mouse events finish triggering).
To solve this problem, I used:
function animate() {
renderer.render(scene, camera);
controls.update();
}
renderer.setAnimationLoop(animate);
That runs the animation loop indefinitely. To pause the animation, one can then specify null as the animation loop:
renderer.setAnimationLoop(null); // pause the animation
And to resume the animation, just pass the animation loop again:
renderer.setAnimationLoop(animate); // resume the animation
An alternative solution to completely stopping the render loop is to reduce the frames per second rate and thereby reducing resource consumption.
This approach is particularly useful if you need responsive update on your scene while not necessarily animating, but also need to snap back normal speeds when you need to.
a simple setTimout() achieves this nicely.
var fps 10;
function render() {
//reduce framerate
setTimeout(()=>{
requestAnimationFrame(render);
//must be called to enable rotating
controls.update();
renderer.render(scene, camera);
}, 1000/fps)
};

Categories

Resources