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
Help! I doesn’t work with a sphere because the camera makes it disproportionately larger!
Changing the FoV doesn’t work either :(
Hi Bartek,
thanks for that article, but somehow it just wont work with my project. Im reading this for the fifth time, but the result is always the same – my plane gets mutch too close to the camera. Tried every formula, found in the comments, but it doesnt help – its always the same result.
So i ask concretly: Have a plane that measures 300×300 and im using the same measurement for the mc, thats beeing used as the MovieMaterial parameter. The plane is beeing tweened to:
var newZ:Number = (camera.zoom * camera.focus) - Math.abs(camera.z)Newest 2.1 GW, also tried with 2.0. It becomes to large/close, anyway. Am i doing something wrong?
Ok, got it!
Sorry for bothering you, the formula works perfectly. Great article, thanks a lot!
Considering it is a cube, and the property of the Camera3D class are set manual (f.e. like in this example), the correct formula would be:
-((camera.zoom * camera.focus) – Math.abs(camera.z)) – (baseSize/2)
If you do not set the Camera properties, use this formula:
((camera.zoom * camera.focus) – Math.abs(camera.z)) + (baseSize/2)
After doing so, I managed to get this example to work!
Thanks for this great post.
When I try to compile the source with flashdevelop I get this:
Error: a target file must be specified
Use ‘mxmlc -help’ for information about using the command line.
Build halted with errors (fcsh).
any ideas?
btw. I read about a deploy folder in the source, but its missing in the source i got from the link on this page.
Thanks.
OMG thx man, thx thx thx many times over. I’m in my very first papervision3d project and it is really giving me head aches. your tutorial is very user-friendly and helped me out quite a bit. THX!
Hello.
Does anyone can provide me a similar formula to use with Away3D ?
And does anyone can tell me how to do this in 3D Studio Max?
I want to combine 3D and HTML.
Thanks already!
@Erik Hm, I am not sure if I understand what you want to do.
Well, i have a texture (256 x 256) with a pixel pattern.
I want to make a 1:1 render of a plane (with that texture, also 256 x 256) in 3D Studio, so i have a pixel match on Z = 0
I don’t know how to setup a scene like this. Is it possible?
I see! Unfortunately I don’t know 3DSMax good enough to help you on that.
[...] 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 [...]
Bartek – great article – I find myself coming back and referring to it over and over… but this time your magic formula didn’t quite work? A little trial and error, and I hit on this:
view.camera.z = 1000;
view.camera.focus = 200;
view.camera.zoom = 5;
That seems to do the trick… my cubes’ front faces are at z = 0, so the camera z is the only thing I changed. Is it possible the projection math in PV has changed???
I’m using the latest (rev 934) PV3d from svn:
http://papervision3d.googlecode.com/svn/trunk/as3/trunk/
Thanks for the great article!
hello there,
so do you have any idea how to get camera.z if I know do3d.z?
the solve given by daddfristy doesnt work
( camera.z = ((camera.zoom – 1) * camera.focus) + 3dobj.z; )