Is renderer.render() blocking or non-blocking? - javascript

I need to take a screen shot after every rendered frame completes, but I'm finding that some screen shots are duplicates, so I'm wondering if I might be saving the screen shot before the render is finished. Thus...
Does renderer.render() block until it finishes rendering?
If not, is there a way to know via callback or event when it is complete?

I created a render test with 50k cubes which on my laptop takes about 6-10 seconds.
The fiddle is here: http://jsfiddle.net/1ma18gLf/
The function does block based on the test. Use the browser console to watch the result and see the base64 image.
The question then becomes does webGL paint to the canvas separately regardless of what JavaScript is doing.
You could try a manual clear before the render:
var renderer = new THREE.WebGLRenderer( { preserveDrawingBuffer: true } );
renderer.autoClear = false;
//In your render loop:
renderer.clear();
renderer.render( scene, camera );

Related

three.js: detect when render completed

I want to detect when rendering completed. I tried to use the following way,
scene.add( mesh );
render();
mesh.onBeforeRender = function(renderer, scene){
...
}
mesh.onAfterRender = function(renderer, scene){
...
}
however, onBeforeRender/ onAfterRender were repeated and continued for my object(mesh) in my case, (maybe I use the mesh has some materials, and I use requestAnimationFrame), and I could not find the finishing the one object of render completed.
Is there any way to find the finishing render?
Similar questions are:
THREE.js static scene, detect when webgl render is complete
Three.js render complete
As I said in my comment, drawing is usually complete after the call to WebGLRenderer.render.
Things that can make it seem like that's not the case include:
Not all shapes are loaded (especially true if you're loading files)
Your scene is very large and complex, requiring a lot of GPU processing
Unfortunately, there is nothing built-in that registers that the GPU has finished creating the color buffer, or even that the canvas was updated.
The best your could do--and it would be computationally expensive--would be to store the last frame's data, and compare it against the current frame.
const buffer = new Uint8Array( canvasWidth * canvasHeight * 4 )
renderer.context.readPixels( 0, 0, canvasWidth, canvasHeight, renderer.context.RGBA, renderer.context.UNSIGNED_BYTE, buffer )
Now, you might miss collecting the pixel data, too. If the renderer clears the color buffer before you get to call readPixels, then your buffer may end up filled with zeroes.

Three.JS instance can't be re-created

I'm trying to destroy (or destruct or dispose) an 'instance' of Three.JS using this:
Full example: https://jsfiddle.net/v7oLzs4m/58/
function kill() {
const rendererDomWas = renderer.domElement;
renderer.dispose();
controls.dispose();
renderer = scene = camera = controls = null;
document.body.removeChild( rendererDomWas );
shouldRender = false;
}
function animate() {
if(!shouldRender) {return} // no more requesting animation frames if 'shouldRender' is false
frameID = window.requestAnimationFrame( animate );
renderer.render( scene, camera );
}
(i.e. disposing, setting references to null, and stopping the draw loop from touching renderer while shouldRender is false)
It appears to work at first (The renderer content stops showing) but when I re-create the instance, it never comes back.
It's as if something is still... holding onto the GLContext which prevents it from being invoked again.
Why can't I re-create a new instance of Three.JS?
I'm not sure why this works (since I was already doing this in my Fiddle...)
But it turns out the secret ingredient (for me) to letting Three.JS get GC'd/disposed is this:
window.cancelAnimationFrame(frameID);
I suppose that this stops the render function from being stored in the hardware-level draw loop, which holds references to GLContext (and the chain)
The GC can't ever happen unless the 'loop is broken'
(Correct me if I'm wrong please)

How to pre initialize textures in THREE.JS

I preload and create materials textures before start render and animate of objects.
But THREE JS upload texture to GPU only when object will be shown in camera.
So when new object comes on a screen animation is jerking because of texture sends on GPU.
The question is how to send textures to GPU during creation of texture for avoiding it during runtime?
Loading images to GPU takes a lot of time.
My guess is to walk your object tree, set each object's frustumCulled flag to false, call renderer.render(scene, ...) once, then put the flags back to true (or whatever they were).
function setAllCulled(obj, culled) {
obj.frustumCulled = culled;
obj.children.forEach(child => setAllCulled(child, culled));
}
setAllCulled(scene, false);
renderer.render(scene, camera);
setAllCulled(scene, true);
You can also call renderer.setTexture2D(texture, 0) to force a texture to be initialized.
Try renderer.initTexture(texture: THREE:Texture) for r0.149.0

THREE.js static scene, detect when webgl render is complete

I am creating a static scene with a lot of objects and I want to save as image after it is rendered. How do I do that in THREE.js r69?
Most probably, you are not going in the right direction.
if you have some function like this
function animate() {
requestAnimationFrame(animate);
render ();
}
The render is doing it's work all the time.
When you are seeing the scene unfinished, it's because the meshes haven't finished loading, not because the render hasn't finished rendering.
So, you have to listen for some onload event on the models that you are loading, that will depend on the method that you use to load them (and that you don't explain, so I can't help you more)
Given the code in your reply, it isn't clear when you add the mesh to the scene. Anyway, I would try something in the line of
function loaderCallback() {
mesh = new THREE.Mesh (...
scene.add (mesh);
requestAnimationFrame(saveImage);
render ();
}
the function invoked at requestAnimationFrame should be called when render finishes.

Three js memory management

I have a large scene with a lot of Mesh and MorphAnimMesh. I want to free memory when the meshes are removed. If i know right this is the best way to do:
for ( var i = scene.children.length - 1; i >= 0 ; i -- ) {
var obj = scene.children[i];
scene.remove(obj);
obj.deallocate();
obj.geometry.deallocate();
obj.material.deallocate();
obj.material.map.deallocate();
}
if i check the memory usage at task manager after this, nothing changes. ( tried to wait a few min for GC but nothing. ) Google Chrome memory snapshot shows the objects still there. morphTargets in THREE.Geometry #1862203 etc.
Tried to set the obj to null, but still no memory decrease.
Any idea what am i doing wrong?
Its a game with levels and the player can change from one to another. After a few change memory usage increases to really high. Thats why i want to remove all object from memory before the level change.
Most likely, you need to add some, or all, of the following:
geometry.dispose();
material.dispose();
texture.dispose();
Check out these examples:
http://mrdoob.github.com/three.js/examples/webgl_test_memory.html
http://mrdoob.github.com/three.js/examples/webgl_test_memory2.html
three.js r.60
I did try all the dispose and deallocate methods but nothing worked.
Then I did the following for my ionic application which is using webgl renderer to render a 360 image.
this.renderer = new THREE.WebGLRenderer({ antialias: true });
RicohView.prototype.stopRendering = function () {
this.canRender = false;
this.renderer.forceContextLoss();
this.renderer.dispose();
console.log('renderer disposed');
cancelAnimationFrame(this.requestId);
}
requestId is something which can be captured from
this.requestId = requestAnimationFrame(render);

Categories