Clean up Threejs WebGl contexts - three.js

I have a problem while cleaning up my WebGl-Scenes. I'm using Three.js with a WebGlRenderer. In my application I have to change the views quite often and therefore need to render new scenes all the time. Uptil now I destroy and reinitialize the entire Threejs scene. After switching the scenes about 15 - 20 times I get following warning:
WARNING: Too many active WebGL contexts. Oldest context will be lost.
After switching a couple of times more the context is lost completly and the application crashes.
Is there a way to destroy the current WebGl context, when cleaning up? Or does the WebGlRenderer always create a new WebGl context when being instantiated?
I'm using Three.js R64.

I've got same problem, but i couldn't solve it using SPA, because of requirements.
There is .forceContextLoss() method in WebGLRenderer (rev 71, maybe was early) for this situations.
So, my code in 'deallocate' method is somemethig like
_self.renderer.forceContextLoss();
_self.renderer.context = null;
_self.renderer.domElement = null;
_self.renderer = null;

You can keep the same renderer for different scenes. The renderer does not care what scene it will render. You can supply a different Scene everytime you call render() if you like.
// instantiate only once and keep it
var renderer = new THREE.WebGLRenderer();
// current scene and camera. Switch whenever you like
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(...);
fillScene(scene);
// rendering always uses current scene
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
/* ...
* somewhere in your application
* ...
*/
if(condition) {
// switch scene
scene = new THREE.Scene();
fillOtherScene(scene);
}

You should create and use only one WebGlRenderer. In my SPA (single page application) I had weird problem with camera/scene in THREE.js after few redirects. It was because WebGlRenderer was created every time when one particular page was rendered. There was no error in console log (only the warning you wrote).
Bug appeared as change in camera position and problems with rendering.

Related

Render loop exploding

I made a small demo/boilerplate for loading a custom mesh with Threejs and inspecting it using orbital controls.
The problem here is that when rotating the object the render loop seems to explode and I can't figure out why.
https://codepen.io/rosefalk/pen/ooBYme?editors=0010
function render() {
console.log('render')
canvasPosition = document.getElementById( "container" ).children;
renderer.render( scene, camera );
requestAnimationFrame( render );
}
If you look in the console it's chugging away merily at what I assume is ~60 calls a second until you start rotating, then it goes up at extreme rate.
Solution - Removal of this part:
controls.addEventListener( 'change', render );
When controls are updating it calls render, render calls itself and that explodes the whole thing, adding a massive amount of extra calls. It's a remnant from when it made sense to only update the scene on user interaction.

spotLightHelper not pointing to target when loaded from json scene

I am using the latest version of Three.js(82) and importing my spot light from blender exporter(json). I have the following code when looping over all the scene objects after loading:
// loop
if(object instanceof THREE.SpotLight){
lightHelper = new THREE.SpotLightHelper(object);
scene.add(lightHelper);
}
// after loop
spot = scene.getObjectByName("Spot",true);
spot.target = scene.getObjectByName("Cube",true);
// in render() funcition
lightHelper.update();
The spotlight helper shows up but it never points to the target. If I try to add a spotlight to the scene manually, it works fine. I think it has to do something with the spotlight being in the child scene. Can anyone suggest a fix for this?

Three.js StereoEffect cannot be applied to CSS3DRenderer

I'm in the process of developing a chrome VR web app. Now I'm desperately trying to figure out how to render a website into my into my stereoscopic scene which has some meshes in it.
So I have my renderer for the meshes, which works well. The following code is only the relevant snippets:
var renderer = new THREE.WebGLRenderer();
Then i have my stereoeffect renderer which receives the webgl renderer:
var effect = new THREE.StereoEffect(renderer);
Next is that I create the website renderer, and apply it to the stereoeffect:
var rendererCSS = new THREE.CSS3DRenderer();
var effectHUD = new THREE.StereoEffect(rendererCSS);
Then I have scenes which are being rendered:
var scene = new THREE.Scene();
var sceneCSS = new THREE.Scene();
function render(dt) {
effect.render(scene, camera);
effectHUD.render( sceneCSS, camera );
}
No what I receive is this:
A stereoscopic image of my mesh, but a non stereoscopic image of the website. The problem is that the when I try to add the css renderer into the StereoEffect renderer, the setViewport function (among others, probably) are missing.
I've tried adding the website object to the webgl renderer, but it doesn't want to render my website, so adding the website object to the scene with the meshes doesn't work.
Any help is greatly appreciated!
I've been having the same problem.
It appears there was a CSS Stereo renderer but it's been removed along with all examples. This could have been for any number of reasons so use the following with caution, or until they reintroduce compatibility:
After searching I found a remaining copy of their demo from which you can mine the code and copy its CSS3DStereoRenderer.js file.
Hopefully this helps.

Three.js Hemisphere Light

I`m examining a different types of light with dat.GUI and three.js (r72) and get stucked on dinamically turning on/off the HemisphereLight.
I have a one instance of each light being added to the scene:
var pointLight = new THREE.PointLight(this._whiteColor);
pointLight.visible = false;
var hemisphereLight = new THREE.HemisphereLight(this._whiteColor, this._whiteColor);
hemisphereLight.visible = false;
ect...
and a buttons for turning on/off with simple handler. Like this:
me._sceneObjects.hemisphereLight.visible = value;
So, before rendering all lights are present in the scene, but not visible.
When executing a handler for Hemisphere light - it stay invisible. After excluding hemisphereLight.visible = false; works fine.
Currently I`m disabling this light after rendering a 1st frame:
function render() {
some code ...
if (!sentenceExecuted && firstCall > 0) {
hemisphereLight.light.visible = false;
sentenceExecuted = true;
} else {
firstCall++;
}
};
I will be grateful for any suggestions to fix this without workaround.
Sorry for possible mistakes in English.
WestLangley, thank you for the link to Wiki article.
After reading and trying the examples I have found my mistake.
Originally I wanted to add "invisible" (using Object3D.visible) for render lights into a scene and then turn them on/off dynamically.
Some lights (in my case HemisphereLight and SpotLight) do not work this way because of internal three.js rendering algorythm (buffers for geometries and materials were built without considering my lights).
To achieve dynamic lightning an author of the article suggest to:
Add light with intensity = 0 and then increase it (such light is taken into account by render)
Force material to be updated (material.needsUpdate = true) for affected scene objects after setting light visibility to true.

Can't seem to make a functional THREE.js collada loader

I'm having issues getting a custom made collada object with no built in camera or lighting to render. I more or less copied what I had seen in a few collada examples to create my own loader, which looks like this:
var loader = new THREE.ColladaLoader();
var room, scene, stats;
loader.load('../Models/Rooms/boot.dae', function colladaReady( collada ){
collada.scene.getChildByName('Cube',true).doubleSided = true;
room = collada.scene;
room.scale.x = room.scale.y = room.scale.z = 1;
room.updateMatrix();
init();
});
The init function is fairly basic and looks like this
scene = new THREE.Scene();
scene.add( room );
scene.add( camera );
renderer.render(scene, camera);
Here is the actual object I'm trying to render. I have also tried it out with the monster.dae file that is in the examples folder without success. The Chrome javascript console isn't showing any errors, so I'm not quite sure where to look in my code. It all resembles functional examples, so I'm not sure why it's not functional. Is there something I'm unaware of that is relevant to collada loading?
RESOLVED: The item was rendering, but had no skin or texture associated with it. So it was rendering at the same colour as the background, which understandably appears to not be rendering at all. Discovered by adding a grid to the ground just to check.

Resources