After posting my shadow experiment, Patrick Matte posed a question wondering if I would be able to do real-time reflections in a similar manner. The next day I had it done, along with some nice iterations along the way: orthographic and perspective projection (I can release those later if anyone really wants them). I've been sitting on it every since and finally decided I would take the time to write a little description into how its done and give the code to those who are interested (and I fixed up some code for backface culling in the reflection this morning).
So, the concept of shooting a ray onto a plane still holds true with the reflection stuff, but we handle the rays a little differently than we do shadows. With shadows we simply project the vertices directly onto the plane. This works because we don't care about the perspective distortion we will see on the plane face, since the shadow is black. A reflection is more than a projection. The reflected object is actually cast "inside" the material - so it maintains its own perspective despite the perspective of the plane you are projecting into. So, the problem was, how can i negate the perspective of the plane to make a real reflection?
The answer was pretty cool, and I am very happy with the result. Instead of projecting a vertex directly onto the plane, I multiply the vertex by a reflection matrix. The reflection matrix allows me to flip any object over any plane. Once i get the vertex in "reflected" space, I then cast a ray from my camera to the reflected vertex. Once I have this ray, I can find where it intersects the plane i want to show the reflection on - and then determine where on that material the ray hits. Since the material will be drawn from the camera's perspective, I can draw my reflected space from the camera's perspective as well - directly into the material. It's a little confusing, but it works awesome. Here is a little graphic I made to try and help explain:

The red square is the object we want to reflect. The blue cube is the object in "reflected" space. The blue cube doesn't actually exist, mind you, all the vertices are flipped there via matrices. The thin red lines shooting from the camera are the rays, and the faint red box is the reflection drawn into the plane. Sorry its not a better graphic - I don't use Illustrator that much...
Anyways - thats about all there is to say about the theory behind it. Here is a brief rundown of the class:
-
//CREATE A NEW PlaneReflection
-
// parameters:
-
// - id: string
-
// - blendMode : string
-
// - alpha : Number (0-1)
-
// - filters : array
-
var reflector:PlaneReflection = new PlaneReflection("reflex", "multiply", 1, [new BlurFilter()]);
-
-
//ADD A MODEL TO THE "REFLECTION LIST"
-
reflector.addModel(sphere);
-
-
//RENDER THE REFLECTION
-
// paramaters:
-
// - camera : CameraObject3D - camera you are currently using
-
// - plane : Plane - a plane to draw into - must have a MovieMaterial applied to it (animated = true);
-
reflector.render(camera, plane);
That should be enough to get you started! Check out the demo, have fun with it. You will notice I used the planes own material as a displacement map for the reflection - that gives it the nice bumpmap feeling. Planes are still backwards (sorry) - so there is a special case to flip culling if you have a plane object.
View the demo (click and drag to orbit)
and
[update]
Here is the updated source to work with the new core changes after Revision 754 (QuadTree support). This also includes Refraction support - I didn't build it out terribly though since i'm too busy, but look at lines 94 and 95 to set what the refraction should look like. Feel free to update the class to use member variables.
enjoy!
[/update]

67 Comments, Comment or Ping
My god andy this is absolutely insane. I cannot believe you! Zowee!
August 24th, 2008
Very cool stuff, pretty smooth as well and clean simple implementation.
August 24th, 2008
Awesome!
Your papervision extensions rock!
August 24th, 2008
Now, that’s what I call real reflections! Awesome!
August 25th, 2008
Can someone tell me how I should get this working in Flash CS3 – maybe even include the .fla with the source?
August 25th, 2008
Hey Andy,
Great stuff as always. I see you’re using 100 and 11 as the zoom and focus for a 1 to 1 relationship. In my latest update of the svn, it changed to 100 and 10 for whatever reason, fyi.
Cheers
August 25th, 2008
awesome!! Great work as always…
August 25th, 2008
mindblowing.
August 25th, 2008
SHITT!!!
August 25th, 2008
And yet again he keeps amazing us
Wonder if you can give a online training about effects. I am sure people will love that, sign me up !
August 25th, 2008
werd! i love the displacement mapping on the plane! slick demo as usual!
August 25th, 2008
hey there. i´ve done an experiment using in pv3d that i´m having problems with it. its about reflections!
i got loaded 8 images, then with a matrix a devide the image in 9 different materials and get them into a movie clip. this works in terms of speed very good just for the 1st plane. the others slow down insanly my processor. the question is. can this be done with 8 images?
source: http://www.andrevenancio.com/source.zip
August 25th, 2008
Just Amazing.
I little bit difficult to figure it out how to configure to Flash IDE. The “embed” problem. I changed the embeds to Lybrary classes and it works fine, fine, fine. Keep up the excelent work!
August 25th, 2008
Wow! Really nice. John Grden will love it for sure !
August 25th, 2008
looks great !
August 25th, 2008
Brilliant!
August 25th, 2008
An amazing evolution in reflection!
August 30th, 2008
Andy, do you know why my reflection isn’t right when camera is moving ?
http://tony.exoa.fr/v3/Sans%20nom-1.swf
Thank’s a lot =)
September 6th, 2008
This is really great!!!
http://www.flashdevelopment.de
September 7th, 2008
This is such a sweet effect. Great work xD!
September 11th, 2008
@Andy,
After Thought: In search of the holy grail:
This is all great but Papervision3d still requires pretty low polygon models to keep framerates practical. Whats the weakest point in this chain, is it the code (as in mine and yours), the flash player, the os, or the machine…asking the impossible!?! Lol. But look below.
I did some digging around and found that the pv3d code has to do a massive trip round (meta algorithm) to process the render. Is this correct or am i taking jibberish
I’ve seen some of Roxiks stuff and the speed is mind blowing.
I’m using 2.4 core duo processor, 2gb ram, 1gb GForce 8800 card, bus @533, Windows Xp.
I want to create true 3d apps (3 cameras) but find that it is hard to get many objects let alone scenes to process above 10 fps. Any general tips or pointers Andy to improve framerate for full scale flash applications.
PS: Can’t wait till the next installment. hey d!
September 11th, 2008
Any chance of a pv3d 2 (White Shark) version, would be tip top,
nice work by the way..
September 16th, 2008
Hey Andy,
Just want to say a big thankyou for this blog.
Its always good when you find one person who is just nailing it… and for PV3D, you are that person. Its inspiring stuff, and for someone like me just getting started with PV3D, the source is excellent for getting to grips with the quirks and odd bits. The reflections are just stunning!
Thanks again,
SJ
September 17th, 2008
@Steve: Try Mr. Doob too bro. He’s damn good. And Roxik, probably the best.
September 25th, 2008
Hi Andy,
I have this sphere:
var gouraudMaterial:MaterialObject3D = new GouraudMaterial(light, 0×6654FF, 0×060433);
var sphere1:Sphere = new Sphere(gouraudMaterial, 50, 10, 10);
when reflector.addModel(sphere1); the flash player throws exception
TypeError: Error #1009: Cannot access a property or method of a null object reference.
the bug is at line 95 from the PlaneReflection.as
Is this some limitation (not using shaders) ?
October 3rd, 2008
Hi Andy,
I’m getting the following error:
C:\Users\davpas\Desktop\actionscript_libraries\zupko\pv3dfx\planereflection\PlaneReflection.as:95: 1067: Implicit coercion of a value of type org.papervision3d.core.geom.renderables:Triangle3D to an unrelated type org.papervision3d.core.render.command:RenderTriangle.
I’m using the latest version of pv3d 2.0. Any thoughts on this?
October 19th, 2008
I’m experiencing the same problems as David. Seems like the support was broken in revision 754 when the render pipeline in pv3d was changed. But luckily it was Andy himself who submitted those changed so I bet he knows exactly what to change
I tried to change the drawTriangle line in PlaneReflection.as to this:
“tmp.material.drawTriangle(new RenderTriangle(tmp), castClip.graphics, r);”
And the code compiles now, but generates the following error:
——
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at org.papervision3d.materials::BitmapMaterial/drawTriangle()
at PlaneReflection/render()
at MethodInfo-1150()
——
Anyone got any smart fix for this?
October 22nd, 2008
Hello Sir,
I can’t implement this code to my cube. If you send me your email id I can send you my raw file. I know your are very busy person, still I want that you check my file. There are so many functionality on my file, thats why I can’t paste it here. Actually I want to create a cube rotator like this example. I almost done the job, but can’t make the reflection part. I am new to papervision3d platform. Kindly help me plz..
Waiting for your reply……….
November 19th, 2008
Hello Sir,
I can’t implement this code to my cube. If you send me your email id I can send you my raw file. I know your are very busy person, still I want that you check my file. There are so many functionality on my file, thats why I can’t paste it here. Actually I want to create a cube rotator like this example [ http://www.mutabor.de/#/de/black/l/1/0/ . I almost done the job, but can’t make the reflection part. I am new to papervision3d platform. Kindly help me plz..
Waiting for your reply……….
November 19th, 2008
First off let me say, amazing work. This reflection is amazing.
But im having troubles figuring out how to implement it. I am very new to papervision, as I just started messign with about a week ago. I have a cube set up that uses 6 movie clips with pictures in them, and it rotates according to where you move the mouse. I am planning on putting this on my site, and the reflection would be the perfect thing to it. Would you, or anyone mind hosting a fla that shows how to correctly implenet
btw im using cs4 and the newest papervision
November 23rd, 2008
andy – i get the same problem as andy and magnus (“Implicit coercion of a value of type org.papervision3d.core.render.command:RenderTriangle to an unrelated type org.papervision3d.core.geom.renderables:Triangle3D”).
any chance you could address this, or point us at a solution?
November 29th, 2008
i figured it out. in the “render” function in , change this:
—-snip—-
for(var i:int=0;i<tris.length;i++){
var tmp:Triangle3D = tris[i];
var rt:RenderTriangle = tmp.renderCommand;
rt.v0 = tmp.v0.vertex3DInstance;
rt.v1 = tmp.v1.vertex3DInstance;
rt.v2 = tmp.v2.vertex3DInstance;
rt.uv0 = tmp.uv0;
rt.uv1 = tmp.uv1;
rt.uv2 = tmp.uv2;
tmp.material.drawTriangle(rt, castClip.graphics, r);
}
—-snip—-
to this:
—-snip—-
for(var i:int=0;i<tris.length;i++){
var tmp:Triangle3D = tris[i];
var rt:RenderTriangle = tmp.renderCommand;
rt.triangle.v0 = tmp.v0;
rt.triangle.v1 = tmp.v1;
rt.triangle.v2 = tmp.v2;
rt.triangle.uv0 = tmp.uv0;
rt.triangle.uv1 = tmp.uv1;
rt.triangle.uv2 = tmp.uv2;
tmp.material.drawTriangle(rt.triangle, castClip.graphics, r);
}
—-snip—-
November 29th, 2008
Hmm, Ted’s fix doesn’t fix the problem for me, and actually causes one:
1067: Implicit coercion of a value of type org.papervision3d.core.geom.renderables:Triangle3D to an unrelated type org.papervision3d.core.render.command:RenderTriangle
this is with pv3d rev 846, the latest as of right now.
If I don’t make that change (working with Andy’s source — the updated one he posted to work with rev 754) the code does compile OK but then I get the 1009 error that Magnus and Ted were having, it’s a 1009 (Can’t access a null method or prop…) triggered by the PlaneReflection class’s render method when it calls BitmapMaterial’s drawTriangle method.
The error is thrown when it hits line 158 in the BitmapMaterial class which reads like this:
focus = renderSessionData.camera.focus;
If I stick a trace in ahead of that line I can successfully trace renderSessionData but trying to trace renderSessionData.camera yields null, so renderSessionData.camera.focus throws the 1009 error.
Any ideas?
December 13th, 2008
Ah — just noticed that it says:
“Planes are still backwards (sorry) – so there is a special case to flip culling if you have a plane object.”
which I suspect might be at least part of my problem since indeed I am using Planes, but I don’t see anything in the PaperReflection source about that, is that something I have to do?
If I view my project in the non-debug player and “Dismiss All” when the error comes up I do get a reflection on one object but only when viewed at odd angles and it’s not an accurate reflection, it’s skewed somehow.
December 14th, 2008
Hi there, great work!
Problem with the #1009 Error seems to be missing camera & viewport in RenderSessionData r. But after modifying your code i still can’t get a reflection to work.
I’m also using only planes and no solid models.
I also tried “fixing” the #1009 error with not using precise materials, but that does not pose an option for me as well as it did not yield any result in terms of obtaining a reflection.
Still, somthing seems to work, as the render for loop containing the drawTriangle command runs 68 times… strange to say at least.
Another issue i encountered are those nasty culling problems (most people refer to them as clipping problems, but to me they seem culling problems as complete triangles just vanish while they are still in my viewport) – but i think that doesn’t concern you? (Think you are part of the core pv3d team?)
Thx
December 27th, 2008
Just found another (i think nicer) way to fix the error which in my oppinion should work (though i still can’t get the reflection to work):
on line 106 insert
var materialIsPrecise:Boolean = false;
Line 116 – 125 becomes:
[code]
if (tmp.material is BitmapMaterial) { // excludes ColorMaterial
if (materialIsPrecise = BitmapMaterial(tmp.material).precise) {
BitmapMaterial(tmp.material).precise = false;
}
}
tmp.material.drawTria.... <--- this line remains as is
if (materialIsPrecise) {
BitmapMaterial(tmp.material).precise = true;
}
[/code]
hope this helps someone, as soon as i figure out how to get reflections, i will post it here as well.
December 27th, 2008
I just found the reason why I was getting no reflections: My reflectionplane was positioned wrong, in fact it was behind my displayobject instead of in front of it…
talkin ’bout strange problems…
On a side note: I fixed most of my culling problems by using FrustumClipping – it’s interesting that the reflectionplane now has culling problems, but i hope i will be able to fix that as well..
Also I’m playing around with getting a drop off effect to work on the reflection, but for some reason applying a gradient mask on the castClip doesn’t yield the right result…
January 5th, 2009
Hi again!
I’ve been successfull with achieving a drop off effect by using a gradient mask on the castclip – just had to set cacheAsBitmap to true on the mask as well as on the castclip and add the mask as a child of the parent of the castclip.
For the reflection stuff: I now got problems with z sorting and am trying to implement a new z sorting algorithm into the reflection class – I don’t know yet if i will be reinventing the quadtree algorithm, but I already got an idea using some simple plane equations – if anyone is interested in the code I’ll post it here, otherwise i hope this will be my last post to this blog entry
Again, Thx for the great work!
January 13th, 2009
Hi again,
I’ve successfully implemented the quadTree + quadrantZFilter into your PlaneReflections class, but as well as it becomes more and more obvious that the whole approach is rather cheap (think about it: how would you do something which is reflected 2 times?), I’ve just discovered 2 additional problems:
1. When moving reflected objects, the reflection seems to distort into the direction of the movement – some time ago i was able to circumvent that, but then the reflection was lagging behind for about 4 or 5 frames – any clue to what might cause that?
2. I still need to find a way to reduce the triangles which will be rendered, because at the moment every triangle is rendered and no clipping or even culling is done which is a horrible situation – using 70 triangles in the whole scene the quadtree sorting could in the worst case come down to (70 – 1) / 2 * 70 = 2415 comparisons, which is not nice at all…
I’d really appreciate it if you could give me some input or have a quick look at the stuff and tell me what you’re thinking, i just put the newest version online here:
http://t3.codeon.eu/test/video/public/videoweb.html
(disabled the drop off effect and made the reflecting plane white, so that the distortion when moving is easily visible)
Help would be greatly appreciated,
Thx
January 14th, 2009
Just one side note:
If you use a plane with 10 segments or any, instead of 1 then it doesn’t work. I figured it out after a few hours trying to reproduce the example.
Otherwise nice work, very useful.
January 17th, 2009
I finally solved the problem of the reflection being late – eventually it was only one frame.
these are the 2 parts needed for solving the problem:
public function updateReflection(event:Event):void {
if (reflectionIsDirty) {
reflector.invalidateTargets();
reflector.render(camera, reflectionPlane);
reflectionIsDirty = false;
}
}
renderer.addEventListener(RendererEvent.PROJECTION_DONE, updateReflection);
initially i solved it by calling
singleRender
reflector.render
singleRender
but rendering 2 times made the performance fall bottomless – but with this way of using the RenderEvent.PROJECTION_DONE no performance penalty occurs and i can use my modified reflector with vorrect quadtree sorting with 30fps.
Only thing left now is to get the frustumculler working…
January 20th, 2009
u re d dude. mindblowin.
January 21st, 2009
Hi Andy,
Do you think it would be possible to write a ReflectionMaterial based on your code? After working with it for some time now and modifying / enhancing it in most of the parts, i realized that it would be way greater if it were to be used as a material, because that would solve several problems.
The first one is, it would be rendered after projection, which automatically would make it be in synch with the rest of the frame.
Also it would be possible to use a plane with more than 1 segment and thus partially take advantage of clipping and culling.
The third thing you could get from that approach is the one i like the most: It would not be limited to the resolution of the material but rather always be 100% sharp as mapping onto triangles – wouldn’t that be cool? I must say i haven’t worked with multiple materials in papervision yet, but as i take it it would be possible to have the normal material applied to a plane and afterwards have the ReflectionMaterial be drawn afterwards?
Cheers
February 3rd, 2009
The example looks great, I tried it out with a cube using both a bitmap material and flatShaderMaterial but none of them worked, I get an 1009 error in both drawTriangle functions.
Does anyone know how to solve this, any advice would be welcome. =)
May 12th, 2009
This is very very nice, but i have some dificulty to understand the entire code, you have [or anyone] a more simple example only with a basic reflect ?
Thanks in advance
June 5th, 2009
It looks like the class is failing because of this line (probably got to do with an update on PV3D, I’ve got REV915 here):
private var r:RenderSessionData = new RenderSessionData();
The RenderSessionData instance is called once but contains only undefined/null values on all its members. Therefor BitmapMaterial.drawTriangle() fails.
June 8th, 2009
this is a very cool piece of kit, however I’m having the same 1009 error in the drawTriangle() functions, was this ever resolved?
Any help would be amazing. =)
June 19th, 2009
thx~~very cool
June 22nd, 2009
Hi there,
Did anyone solve the problem with 1009 Error appearing when shade material (e.g. GouraudMaterial) is beeing used?
August 23rd, 2009
Andy you are some kind of genius when it comes to this stuff. Keep it coming its massively appreciated.
September 3rd, 2009
Hi there,
I also have the problem with 1009 Error appearing when shade material (e.g. GouraudMaterial) is being used.
Has anyone fixed this yet???
February 1st, 2010
I love you. Can we be friends?
March 16th, 2010
The example looks great. But I didn’t understand how to use MovieMaterial
Could you give me a piece of code with properties if MovieMaterial?
August 24th, 2010
Reply to “Reflections in Papervision3D”