Reflections in Papervision3D


reflect3.png

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:

reflectui.png

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:

Actionscript:
  1. //CREATE A NEW PlaneReflection
  2. // parameters:
  3. // - id: string
  4. // - blendMode : string
  5. // - alpha : Number (0-1)
  6. // - filters : array
  7. var reflector:PlaneReflection = new PlaneReflection("reflex", "multiply", 1, [new BlurFilter()]);
  8.  
  9. //ADD A MODEL TO THE "REFLECTION LIST"
  10. reflector.addModel(sphere);
  11.  
  12. //RENDER THE REFLECTION
  13. // paramaters:
  14. // - camera  : CameraObject3D - camera you are currently using
  15. // - plane : Plane - a plane to draw into - must have a MovieMaterial applied to it (animated = true);
  16. 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

Get the source

[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!

Get the Updated Source

[/update]


67 Comments, Comment or Ping

  1. My god andy this is absolutely insane. I cannot believe you! Zowee!

    August 24th, 2008

  2. Very cool stuff, pretty smooth as well and clean simple implementation.

    August 24th, 2008

  3. Cary

    Awesome!

    Your papervision extensions rock!

    August 24th, 2008

  4. Now, that’s what I call real reflections! Awesome! :)

    August 25th, 2008

  5. William

    Can someone tell me how I should get this working in Flash CS3 – maybe even include the .fla with the source?

    August 25th, 2008

  6. 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

  7. F

    awesome!! Great work as always…

    August 25th, 2008

  8. mindblowing.

    August 25th, 2008

  9. bebensiganteng

    SHITT!!!

    August 25th, 2008

  10. 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

  11. werd! i love the displacement mapping on the plane! slick demo as usual!

    August 25th, 2008

  12. 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

  13. 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

  14. Wow! Really nice. John Grden will love it for sure ! :)

    August 25th, 2008

  15. looks great !

    August 25th, 2008

  16. Brilliant!

    August 25th, 2008

  17. plasmaflex

    An amazing evolution in reflection!

    August 30th, 2008

  18. hackmetal

    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

  19. This is really great!!!

    http://www.flashdevelopment.de

    September 7th, 2008

  20. This is such a sweet effect. Great work xD!

    September 11th, 2008

  21. @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

  22. Any chance of a pv3d 2 (White Shark) version, would be tip top, :-) nice work by the way..

    September 16th, 2008

  23. 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

  24. Saul

    @Steve: Try Mr. Doob too bro. He’s damn good. And Roxik, probably the best.

    September 25th, 2008

  25. 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

  26. 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

  27. Magnus Antonsson

    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

  28. 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

  29. 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

  30. posermobile89

    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

  31. ted

    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

  32. ted

    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

  33. Tom

    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

  34. Tom

    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

  35. Joe

    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

  36. Joe

    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

  37. Joe

    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

  38. Joe

    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

  39. Joe

    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

  40. Gutty

    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

  41. Joe

    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

  42. u re d dude. mindblowin.

    January 21st, 2009

  43. JOE

    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

  44. Dennis

    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

  45. 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

  46. erik

    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

  47. 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

  48. thx~~very cool

    June 22nd, 2009

  49. KUJON

    Hi there,

    Did anyone solve the problem with 1009 Error appearing when shade material (e.g. GouraudMaterial) is beeing used?

    August 23rd, 2009

  50. Andy you are some kind of genius when it comes to this stuff. Keep it coming its massively appreciated.

    September 3rd, 2009

  51. Scott

    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

  52. I love you. Can we be friends?

    March 16th, 2010

  53. Stanislav

    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

  1. I’m not dead yet · - August 27, 2008

Reply to “Reflections in Papervision3D”