I am done with the Moon simulator chapter in 3D Game Programming for Kids and am ready to move onto other things (like more actual games). It occurs to me, however, that I do not know how to allow two cameras to be active at the same time in Three.js. I was able to do this king of thing in CubicVR.js / Gladius, but am not even sure it is possible in Three.js.
In the chapter, I include some side-by-side comparisons of the Moon's position and its phase:
Those screenshots are labor intensive—I need to screen capture each (and resize the print scale of each). This would not be something that I would have the kids do, but it would be great to have the Moon's phase superimposed on the overhead shot.
Unfortunately, as best I can tell, there is no way to accomplish this in Three.js. The render that spits the scene out onto canvas, takes only one camera:
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Three.js does include a CombinedCamera. Sadly this does not do what I hope—it just makes it easy to switch back and forth between a perspective camera and an orthographic camera.I might not be entirely out of luck though. Just because Three.js renders are restricted to a single camera does not necessarily mean that I am restricted to a single renderer.
So I add a "picture-in-picture" element to the screen:
var pip = document.createElement('div');
pip.style.width = 250;
pip.style.height = 250;
pip.style.position = 'absolute';
pip.style.backgroundColor = 'black';
pip.style.borderRadius = "5px";
pip.style.border = '2px solid white';
pip.style.padding = "0px 20px";
pip.style.left = "50px";
pip.style.top = "25px";
document.body.appendChild(pip);
Then I create a second renderer and add its domElement
to the picture-in-picture: var renderer2 = new THREE.WebGLRenderer();
renderer2.setSize(250, 250);
pip.appendChild(renderer2.domElement);
This is just like the regular renderer, except that I append the renderer's DOM element to a specific element instead of appending it to the document body. I also note that the aspect ratio that I will have is 1:1, so I redefine the "Earth Cam" to have a 1:1 aspect ratio: //var earth_cam = new THREE.PerspectiveCamera(45, aspect_ratio, 1, 1e6);
var earth_cam = new THREE.PerspectiveCamera(45, 1, 1, 1e6);
With that, I am ready to try double rendering in Three.js. I add the second renderer to my animate()
method: function animate() {
requestAnimationFrame(animate);
renderer2.render(scene, earth_cam);
renderer.render(scene, camera);
// ...
}
Unfortunately, that does not work. I only get the new camera, with the rest of the scene completely blank:In addition to the visual evidence, Three.js spits out a lot of warnings telling me that I am doing something very wrong:
THREE.WebGLRenderer 52 Three.js:15545 THREE.WebGLRenderer 52 Three.js:15545 WebGL: INVALID_OPERATION: useProgram: object not from this context Three.js:20282 WebGL: INVALID_OPERATION: uniformMatrix4fv: location is not from current program Three.js:20298 WebGL: INVALID_OPERATION: uniform3f: location not for current program Three.js:20743 WebGL: INVALID_OPERATION: uniform1f: location not for current program ...I try moving the second renderer out into its own
animate2()
function: function animate2() {
requestAnimationFrame(animate2);
renderer2.render(scene, earth_cam);
}
animate2();
But this has no effect. I still only see a single camera's output and get lots of warnings in the JavaScript console. I try rendering the second camera just a single time. I also try switching the renderer to a CanvasRendered
. All have no effect.It seems that I simply cannot render the same scene to two different renderers. If anyone has any thoughts, the non-worky code is up. In the meantime, I will sleep on it and perhaps revisit tomorrow.
Day #635
Is this what you were looking for? http://mrdoob.github.io/three.js/examples/webgl_multiple_views.html
ReplyDeleteYup, that would have really helped at the time :)
DeleteI did manage to hack together a more or less workable solution: http://japhr.blogspot.com/2013/01/multiple-renderers-in-threejs.html
But that example is better.