I put some more time into doing Dual-Paraboloid maps in a single scene pass under DirectX 9. This is built on the work of Jason Zink (http://www.gamedev.net/columns/hardcore/dualparaboloid/)
Here is the idea:
Use the vertex shader to transform verts into paraboloid space, and then assign the vertex to the 'front' or 'back' area of the map. Both sides of the map are in the same texture, side-by-side.
Vertex shader:
float L = length(OUT.hpos.xyz);
// Flip the z in the back case
bool isBack = (OUT.hpos.z < 0.0);
OUT.isBack = (isBack ? -1.0 : 1.0);
if(isBack)
OUT.hpos.z = -OUT.hpos.z;
OUT.hpos /= L;
The vertex will be assigned to the 'back' map if it is behind the camera. The value 'OUT.isBack' is a float value. It is assigned '-1.0' if it is a vertex assigned to the back map, and '1.0' if it a vertex assigned to the front map.
// Pass unmodified to pixel shader to allow it to clip properly
OUT.pos = OUT.hpos.xyz;
// Scale and offset so it shows up in the atlas properly
OUT.hpos.xy = OUT.hpos.xy * atlasScale.xy;
OUT.hpos.x += (isBack ? 0.5 : -0.5);
return OUT;
The full xyz screen space position is passed to the pixel shader before the POSITION output is adjusted for atlasing. In this case 'atlasScale.xy' is (0.5, 1.0) because I am storing the maps side-by-side in the texture. The x co-ordinate is then shifted so that the triangle is drawn in the proper location in the atlas.
Now in the pixel shader:
Fragout OUT;
clip(abs(IN.isBack) - 0.999);
clip(1.0 - length(IN.pos.xy));
OUT.col = encodeShadowMap(IN.pos.z);
return OUT;
So, what's going on here? The value that was assigned in the vertex shader, 'OUT.isBack' is getting interpolated across all verts of the triangle. If all verts on the triangle are entirely on the front map, or entirely on the back map, the pixel will pass because abs(IN.isBack) will be 1.0, and subtracting 0.999 will still result in a positive value.
Here are some comparison shots of single scene draw vs 2x scene draws creating a Dual Paraboloid shadow map:
http://flickr.com/photos/killerbunny/sets/72157610684857219/
Two passes:
One pass:
You can see right away, that the single pass implementation exhibits the behavior that is described. If the triangle is *entirely* on the front, or back map, it will render properly, otherwise it is clipped. This behavior can actually be ok for shadow maps. It depends where the light is, and what kind of things are going to come into it's radius.
So those are the results so far. I have a few thoughts on improving the quality of the single pass maps.
1. The maps could be rotated so that the "floor" area on both maps pointed twords the middle of the map. The shader code could then be adjusted to allow the front and back to stretch triangles to each-other along that axis. This would eliminate or reduce the artifacts along one seam of the maps.
2. Hardware N-Patch. This feature seems to have gone the way of the dodo which is too bad because I think it would actually be useful for this case. IIRC the Xbox 360 has hardware support for N-Patch tessellation, that could actually work.