First up the video:
This was actually pretty easy to achieve, it basically involves rendering the scene 6 times with a wide angle lens each time rendering to a side of a cube map.
This cube map can then be used as a basis for a reflection shader.
Noteworthy observations:
this will be slow for complex scenes as there could potentially be 7 times more draw calls!!
forgetting to convert degrees to radians can be a pain in the but (doh)
frustum cull with each face render to reduce the number of draw calls
to get it to reflect another reflective object will really start to complicate things..so avoid like hell
could probably get away with rendering to really small textures, as perfect reflections can look less realistic anyway.
there is something wrong with my reflection math as those of you with keen eyes will have noticed the reflected cubes are moving backwards – will fix this soon I hope.
All this was achieved in a very short space of time, about 30 mins of coding and about 2 hours to realise I forgot to convert degrees to radians.
example code:
public function rendertoCubeMap(cubeTexture:CubeTexture, exclude:Object3D = null):void { this.exclude = exclude; var cameraPositionCache:Vector3D = camera.position.clone(); var cameraTargetCache:Vector3D = camera.target.clone(); var fovCache:Number = camera.fov; var aspectCache:Number = _aspect; camera.fov = cubeFov; _aspect = 1; camera.position.setTo(0,0,0); context3D.setRenderToTexture(cubeTexture, true, 0, 0); camera.target.setTo(camera.position.x - 1, camera.position.y, camera.position.z); update(); renderAll(); context3D.setRenderToTexture(cubeTexture, true, 0, 1); camera.target.setTo(camera.position.x + 1, camera.position.y, camera.position.z); update(); renderAll(); context3D.setRenderToTexture(cubeTexture, true, 0, 2); camera.target.setTo(camera.position.x, camera.position.y + 1, camera.position.z+0.001); //get some NaNs if z = 0 here update(); renderAll(); context3D.setRenderToTexture(cubeTexture, true, 0, 3); camera.target.setTo(camera.position.x, camera.position.y - 1, camera.position.z-0.001); //get some NaNs if z = 0 here update(); renderAll(); context3D.setRenderToTexture(cubeTexture, true, 0, 4); camera.target.setTo(camera.position.x, camera.position.y, camera.position.z + 1); update(); renderAll(); context3D.setRenderToTexture(cubeTexture, true, 0, 5); camera.target.setTo(camera.position.x, camera.position.y, camera.position.z - 1); update(); renderAll(); context3D.setRenderToBackBuffer(); _aspect = aspectCache; camera.fov = fovCache; camera.target.setTo(cameraTargetCache.x, cameraTargetCache.y, cameraTargetCache.z); camera.position.setTo(cameraPositionCache.x, cameraPositionCache.y, cameraPositionCache.z); this.exclude = null; } |
and that’s it!
🙂
5 replies on “Dynamic Reflections with Stage3D”
[…] Ben Whiting posted a demo with code snippets provided on creating dynamic reflections with Stage3D. […]
Hello there, I love your Molehill scripting!
But I’m having a slight problem, I am trying to apply your method, this is what I’ve got:
An texture (refTex) with an empty black BitmapData (512×512)
Do you know why the texture isn’t drawn?
context.clear(1,0.8,0.6);
context.setProgram(terProgram);
context.drawTriangles(terIdxBuf);
context.setRenderToTexture(refTex);
context.setRenderToBackBuffer();
context.present();
How to render to a texture:
1. tell the context to render to your texture
i.e. context3D.setRenderToTexture(refTex);
2. draw your geometry using whatever program you wish
3. now you have your texture with something drawn on it, you can then use it as a texture for another render, but to see anything you need to tell the context to render to the back buffer again.
for example, render a one scene to a texture, then render another scene to the backbuffer using the previous texture as a texture to sample from on a plane for example, then that plane will look like a screen showing the 1st scene.
What does renderAll do? I assume present. I’m getting lag by rendering to a texture of one frame.
renderAll is a function that just loops through all visible objects in a scene and renders each one with drawTriangles. Updating programs, constants etc for each object when needed.
No presenting, just the calls to drawTriangles.
There are a large number of things that can cause lag when dealing with stage3d, ensure you are not creating textures every frame and ensure you create your programs only once if possible to reduce any overhead.
I hope you resolve the issue, you should be able to render a simple scene to a number of different targets without too much of a performance hit so really check the code around it to ensure only the minimum changes necessary are taking place.