Monday, January 21, 2013

Multiple Renderers in Three.js

‹prev | My Chain | next›

I ended yesterday's attempt at getting multiple Three.js scenes working with no visual output and a rather obnoxious error:
WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost
Today I think to check the actual source of the exception and find:

Actually, that is not a big deal. This is just caused when I drop a preview page so that a new one can be created. To be sure, I need to get rid of this—kids working through 3D Programming for Kids should not have to see this. But really, this is OK—it is likely something new in Chrome 26.

But that still leaves me with no visual output in my Phases of the Moon project. From yesterday, I am currently attempting to clone everything from my first scene into my second scene:
  // ...
  var moon_orbit = new THREE.Object3D();
  moon_orbit2 = moon_orbit.clone();
  moon.position.set(0, 100, 0);
I ended yesterday by trying to comment everything out relating to the first scene just to get the new "picture-in-picture" overlay scene rendered. While fiddling around with re-enabling the main scene, I start taking notice of the litany of error messages that Three.js is spewing my way. Although there are many, they may actually be telling me something useful:
WebGL: INVALID_OPERATION: useProgram: object not from this context
WebGL: INVALID_OPERATION: uniformMatrix4fv: location is not from current program
WebGL: INVALID_OPERATION: uniform3f: location not for current program
WebGL: INVALID_OPERATION: uniform1f: location not for current program
WebGL: INVALID_OPERATION: uniform3fv: location is not from current program
This would seem as though I am including something from the first scene in the second, which is a no-no.

To test this theory out, I delete all of the scene-2 code. I again have the Moon revolving around the Earth in the main scene with an empty picture-in-picture overlay:

This time, I start by adding nothing but new objects to the scene that will go in that overlay:
  var scene2 = new THREE.Scene();

  var renderer2 = new THREE.WebGLRenderer();
  renderer2.setSize(250, 250);
  var directionalLight = new THREE.DirectionalLight( 0xffffff, 5 ); 
  directionalLight.position.set( -1, 0, 0 ); 
  scene2.add( directionalLight );

  var cam2 = new THREE.OrthographicCamera( -125, 125, 125, -125, 1, 1e6 );
  var surface = new THREE.MeshPhongMaterial({ambient: 0x1a1a1a, color: 0xffffff});
  var planet = new THREE.SphereGeometry(15, 30, 25);
  var moon2 = new THREE.Mesh(planet, surface);

  function animate2() {
    renderer2.render(scene2, cam2);
And... it works!

I now have two different WebGL renderers sending two different scenes to two different DOM elements:

If I try to replace the completely new moon2 definition with yesterday's moon.clone(), then I again get the "not from this context/program" WebGL errors. So cloning is out, which makes it much more difficult, thought not impossible to get two different views.

I take a little time to recreate the Moon's orbit around the Earth and the Earth's positioning relative to the center of the Solar System. With that, I am ready to copy the rotation of the Moon's orbit from the main animation thread:
  function animate2() {
    renderer2.render(scene2, earth_cam2);
    moon_orbit2.rotation.set(0, 0, moon_orbit.rotation.z);
And I have an accurate picture-in-picture representation of my scene. Two different scenes, two different cameras showing at the same time:

The runnable, editable code that does this is available.

Day #637

No comments:

Post a Comment