A couple of weeks ago I gave a talk at FSOSS on XB PointStream. For my presentation I wanted to experiment and see what interesting demos I could put together using point clouds. I managed to get a few decent demos complete, but I didn’t have a chance to blog about them at the time. So I’ll be blogging about them piecemeal for the rest of the month.
The first demo I have is an anaglyph rendering. Anaglyphs are one way to give 2D images a depth component. The same object is rendered at two slightly different perspectives using two different colors. Typically red and cyan (blue+green) are used.
The user wears anaglyph glasses, which have filters for both colours. A common standard is to use a red filter for the left eye and a blue filter for the right eye. These filters ensure each eye only sees one of the superimposed perspectives. The mind them merges these two images into a single 3D object.
There are many ways to achieve this effect. One method which involves creating two asymmetric frustums can be found here. However, you can also create the effect by simply rotating or translating the object. It isn’t as accurate, but it’s very easy to implement:
// ps is the instance of XB PointStream // ctx is the WebGL context ps.pushMatrix(); // Yaw camera slightly for a different perspective cam.yaw(0.005); // Create a lookAt matrix. Apply it to our model view matrix. ps.multMatrix(M4x4.makeLookAt(cam.pos, V3.add(cam.pos, cam.dir), cam.up)); // Render the object as cyan by using a colour mask. ctx.colorMask(0,1,1,1); ps.render(pointCloud); ps.popMatrix(); // Preserve the colour buffer but clear the depth buffer // so subsequent points are drawn over the previous points. ctx.clear(ctx.DEPTH_BUFFER_BIT); ps.pushMatrix(); // Restore the camera's position for the other perspective. cam.yaw(-0.005); ps.multMatrix(M4x4.makeLookAt(cam.pos, V3.add(cam.pos, cam.dir), cam.up)); // Render the object as red by using a colour mask. ctx.colorMask(1,0,0,1); ps.render(pointCloud); ps.popMatrix();
I hacked together the demo just in time for my talk at FSOSS, but I was left wondering how much better the effect would look if I had created two separate frustums instead. For this I would need to expose a frustum() method for the library. I can’t see a reason not to add it considering this is a perfect use case, so filed!