Sign in to follow this  
Nitrogenycs

Simulating cubemap lookup (6 2D textures)

Recommended Posts

Nitrogenycs    130
Hello, I am trying to implement shadowmapping for omnidirectional lights. I don't want to use cubemaps, but rather 6 single 2D textures. I wrote the following function:
float4 fakeCubeMapLookup(uniform sampler2D tex[6], float3 vec)
{
     float3 stf; 
     float3 absVec = abs(vec);
     float3 sgn = sign(vec);
     float3 sgnVec = -sign(vec) / 2 + 0.5;			// maps + to 0 and - to 1
     float absMa = max( max(absVec.x, absVec.y), absVec.z);
     float3 faceBaseVec = float3( 0, 2, 4);
     float3 faceVec = faceBaseVec + sgnVec;

     if ( abs(vec.x) == absMa ) { stf = float3(-vec.z * sgn.x, -vec.y, faceVec.x); }
     else if ( abs(vec.y) == absMa ) { stf = float3(+vec.x, vec.z * sgn.z, faceVec.y); }
     else if ( abs(vec.z) == absMa ) { stf = float3(vec.x * sgn.x, -vec.y, faceVec.z); }

     float2 st = (stf.xy/absMa + 1) / 2;
     int face = int(stf.z);
     float4 color = tex2D( tex[0], st) * float(face == 0) + tex2D( tex[1], st) * float(face == 1) + tex2D( tex[2], st) * float(face == 2) + 
				tex2D( tex[3], st) * float(face == 3) + tex2D( tex[4], st) * float(face == 4) + tex2D( tex[5], st) * float(face == 5) ;

     //return float4(st,0,1) * float(stf.z == 1);

     return color;    
}

When I substitute the tex[6] with a simple tex (no array), then the lookup into this textures works just fine and I get my shadow for one cube side. Now I want to address all cube sides (maps) with the function above. The compiler (I am using the cg one, but the code is more or less the same as HLSL) bitches about "stf might be accessed before initialized". Any idea why it should do so? I also tried to replace the line
     float4 color = tex2D( tex[0], st) * float(face == 0) + tex2D( tex[1], st) * float(face == 1) + tex2D( tex[2], st) * float(face == 2) + 
				tex2D( tex[3], st) * float(face == 3) + tex2D( tex[4], st) * float(face == 4) + tex2D( tex[5], st) * float(face == 5) ;

with
     float4 color = tex2D( tex[face], st);

but this doesn't compile (I guess because you can't decide which tex to look up in at runtime?!). What do I have to change to make this work/do you see a better way how to simulate a cubemap lookup (probably avoiding the expensive 6 texture reads when you only need 1)?

Share this post


Link to post
Share on other sites
klhurley    120
Try dual paraboloid maps.

http://www.nada.kth.se/~gustavt/dpm/ &

http://members.gamedev.net/JasonZ/Paraboloid/DualParaboloidMappingInTheVertexShader.pdf

single texture lookup.

Share this post


Link to post
Share on other sites
MikeWW    224
Hi,

Basically you get the error because the compiler does not have the same level of intuition that we do when we look at the code. As far as the compiler is concerned the if/else-if block that sets stf may not actually result in stf being set.

As an aside I would recommend an alternate way of doing this anyway:

* Use a single texture to hold all 6 faces packed together somehow.
* Create a static lookup cubemap that maps the incoming 3D vector to the UV coord of the point in the faces texture.

As long as you use point sampling for both lookups everything should work out OK.

This way not only do you only need to render to one rendertarget for the light instead of 6, but you also replace a whole load of ugly math and sampler array lookup with a texture read which can be a win in some cases.

Hope this helps,

Mike.

Share this post


Link to post
Share on other sites
Nitrogenycs    130
Thanks for your answers so far!

klhurley, I already read a lot on dual paraboloid maps, but they didn't really convince me. What are your experiences with them?

MikeWW, Now that you mention it, I see what the compiler means by "might be accessed before initialized". I'll set it to 0 at the beginning to stop the compiler from bitching.
The single texture approach looks fine to me. I'll create 2 textures for the whole cubemap then. I'll put the depth of the first 3 faces in the RGB of texture 1 and the depth of the last 3 faces into RGB of texture 2. That way I can even get away with 2 passes to render the whole cubemap if I transform the vertex 3 times in the shader, each time with a different world matrix (one for each face). Could probably even stack this into a single texture, but this one would have to be quite big then (if all faces are at least 1024x1024 then my map needs to be at least 2048x1024). Hmm, maybe I even take the 1 map approach.
The lookup cubemap sounds like a really good idea, should be much faster then calculating everything manually.
Finally, this will lead to 3 (2) lookups (one in the static cubemap to look up face + texture coordinates) and 2 (1) into each of the 2 textures (single texture). That's not too bad I think. I could probably even add texture filtering across cubemap faces with that.
Hmm, maybe need to add some scale params to account for differently sized faces somewhere in there.

Thanks again for your help and inspiration!

-Matthias

P.S.: Can somebody tell me why tex2D(tex[face], st); does not work?

Share this post


Link to post
Share on other sites
ET3D    810
Quote:
Original post by Nitrogenycs
P.S.: Can somebody tell me why tex2D(tex[face], st); does not work?


Because samplers aren't indexable (as are most things in shaders). So the compiler would either have to translate this to a series of 'if's or read all samplers and select between them. Either of them is far from efficient.

BTW, I'm curious why you don't want to use cube maps.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this