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:
1. A material should be rendered as in 1:1 scale of the original texture
2. 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.


[...] Everyday Flash / » Pixel precision in Papervision3D / by Bartek Drozdz [...]
very helpful. Thanks!
You should add onStageResize listener to change pixel-background position when changing window size :)
Very cool!:)
@garrymatteson Actually I did, but there was a bug. Now it’s fixed. Thanks for finding that one!
That’s a clever demo! :D
nice, I always wondered what the 2d pixel perfect equivalent was.
hi bartek,
this is a great example and i can see the binary you supplied in the deloy folder working, but when i compile i get a slightly different result.
when compiling, the cube material bitmap seem larger then the background.
im using Papervision3D Public Alpha 2.0 – Great White (24.03.08) and i know theres work being done in the camera classes so just wondering if this could be causing the problem.
which means that the equation,
3dobj.z = ((camera.zoom – 1) * camera.focus) – Math.abs(camera.z);
no longer holds true, for some reason…
anyhoo, if you have any information on this i would be interested to hear it.
thx
Lukasz
how do you reverse the equation to solve for camera.z? i came up with
camera.z = ((camera.zoom – 1) * camera.focus) – 3dobj.z or
camera.z = ((camera.zoom – 1) * camera.focus) – Math.abs(3dobj.z) and best but still did not work right
camera.z = ((camera.zoom – 1) * camera.focus) + 3dobj.z;
but it did not look right. I’m guessing I’m doing something wrong with the Math.abs
algebraically challenged
-df
@lukasz you are right. the all camera classes have been changed after I did that demo. I was able to make it work again with the lates revision of GW. It seems like the ‘zoom – 1′ is not necesarry anymore… just use ‘zoom’ in the equation. I’ll post an updated ZIP with the sources later.
Anyway, since the camera classes have been reworked I will need to check the formula again. Hopefuly I will post something on that soon. I will also see the reversing of the equation that daddfristy is mentionning.
thanks bartek
thats do the trick
hello, i was able to get the results I wanted with:
distance between camera and object = camera.focus * camera.zoom
thanks for a real helpful tutorial
-df
Wait, daddyfristy, how did you calculate the camera movement?
– TK
Bartek,
I’m trying to solve something similar to this. I have a camera and a plane and I need to make sure that the top edge of the plane is always at the top edge of the viewport/camera’s viewing area. I need to do this with the camera, not the plane, for display purposes. How would I do the math to figure this out?
– TK
[...] Pixel precision in Papervision3D [...]
great! thanks.
You forgot to mention on thing, if you are using a cube, that cube is centered. This equation will work fine with planes but for anything with depth you must use the following equation:
cube.z = (camera.zoom * camera.focus) – (Math.abs(camera.z) – cubeDepth/2)
Wonderful! Saved me a couple of hours :)
I use this one in your demo to get it working right:
cube.z = -((camera.zoom * camera.focus) – (Math.abs(camera.z) – baseSize / 2));
Basicly the same as Max’s solution, but with the minus in front of the whole equation.
Hi bartek
i’m not shure but maybe i found a bug. when camera.z > 0 your formula does strange things. I change it to
var targetZ1 : Number = (camera.zoom * camera.focus) – (camera.z*-1);
works fine for me.
thank you anyway. you saved me a lot of time ;)
greets
alex
[...] wrote a great article here about showing e.g. an 400×300 px image in the same size in [...]
@alex thanks for the fix. Indeed it makes more sense the way you did it in case the camera.z value is not negative.
can you provide the fla of this file, I am having difficulty making the src file operate
@Xavier All of my examples on this blog are built with the Flex SDK which doesn’t use FLA files. To compile it you will need an Actionscript editor. If you haven’t used any, the best choice for the beginning is FlashDevelop – it is free and offers a decent functionality. Here’s some more details and links:
http://www.everydayflash.com/blog/index.php/2008/07/01/flash-on-free-software-flashdevelop-flex-sdk/
[...] Everyday Flash – Pixel precision in Papervision 3D [...]
PV3D pixel precision and calculatin screen coords http://tinyurl.com/65v76b
[...] por la red he encontrado este interesante post en Everyday Flash en el que explica como ajustar un objeto 3D para que su textura se vea en relacción [...]
[...] This tutorial offers some magic formula for solving these problems. Useful tips, comments, demo and the source code are at your service as well. [...]
Very well explained and your demo shows this perfectly, I thought Mr Doob would like that, its right up his street.
[...] Full Article [...]
miru109의 생각…
pv3d 1:1 뷰를 위한 셋팅 계산…
hi bravooooo very nive work!
but how can i do like this fabulous work?
thank’s a lot
[...] Pixel precision in Papervision3D [...]
Hi, this formula helps a lot, I was testing the code with flash but I cannot get to match the block picture with the background, maybe because my images are to big, maybe you could tell which are the requierements for teh pictures used, I’ll keep playing with the code. Thanks