Pixel precision in Papervision3D
I used to work for a company that made of the concept of pixel perfection one of the pillars of their success. Today most of the top clients and agencies demand high quality, and pixel perfection became one of the important components of a great website. Obviously, it concerns 3D as well.
To achieve it, sooner or later in your 3D adventures you will come across one of these problems:
- A material should be rendered as in 1:1 scale of the original texture
- A precise, pixel level match between 2d and 3d content is necessary
In order to check how to solve these problems, I created a very simple demo.
First, I had to make sure my textures are not scaled. I started to browse the Papervision3D forum and it wasn't long before I found the magic formula:
3dobj.z = ((camera.zoom – 1) * camera.focus) – Math.abs(camera.z);
Many thanks to unnormaJH and kjangsa3 for this tip. I would add that it works just as it is only with planes. In my example I worked with a cube, and a cubes Z position is defined by the point in the center of it – which means that the face facing the camera will be closer half the cubes width, so remember that this needs to be adjusted.
UPDATE - With the new Camera classes (GW rev. 639 an higher) the formula changes a bit. The "-1" in "zoom-1" is no longer needed. So it looks like this:
3dobj.z = (camera.zoom * camera.focus) – Math.abs(camera.z);
The second problem – a pixel perfect match between 2D and 3D – is mainly about being able to figure out the screen X and Y coordinates of the 3D object. They can be obtained that way:
screenPosX = 3dobj.screen.x + viewport.viewportWidth / 2; screenPosY = 3dobj.screen.y + viewport.viewportHeight / 2;
That, I found in an article on PV3D.org which shows how to do this. There is also an example of how to get the X and Y coordinates of a single vertex.
In the demo above, knowing the screen coordinates of the cube, I use the BitmapData.draw method to take a snapshot of the 2D background at this position for use as the texture. If you scale the browser window you can see how the texture on the cube is being updated to exactly match the background tile.
In the real world, what you'll need much more often is to do the opposite, that is drawing 2d content exactly on top of a 3d object. An example would be replacing a texture with a Sprite containing some interactive elements. By knowing the screen coordinates of your 3d object, and by making sure it is scaled 1:1 it is a quite easy task to make that look seamless & perfect!
Source code - get it here.
Credits - The tile graphics come from Squidfingers.