Jump to content
  • Advertisement
Sign in to follow this  
azzurro89

[XNA 4 & HLSL] Need help on manual Bilinear filtering on FP Cube maps

This topic is 2700 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

I'm currently working on my thesis in implementing real-time reflection and refractions with z-buffered environment maps. This is based on "[font="Arial"]Robust Multiple Specular Reflections and Refractions" [/font][font="Arial"]technique listed in GPU Gems 3 by[/font][font="Arial"] Gustavo Patow et al [ http://http.developer.nvidia.com/GPUGems3/gpugems3_ch17.html ]. My thesis focuses on implementing the technique into any arbitrary complex models compared to the single simple convex model as described in the original one. In my case, I have to implement depth-peeling technique to retrieve surface information at any level of visible surface interfaces (all the front and back faces of a model). I'm using Microsoft XNA 4 and SM3 HLSL as the platform.[/font]

[font="Arial"]However, I stumbled upon the fact that XNA 4 prevents the use of linear filtering on floating point cube textures as I'm currently using. The texture lookup with point sampling gives so much artifacts in reading the distance value of the cubemaps. I think I have to do manual bilinear filtering in this case. The question is, how can i implement that in HLSL? As far as I know, there's this texCUBEgrad function which takes partial derivatives dx and dy. Since I'm using a 3D texCoord for the cubemap lookup, how am I supposed to do with the dx and dy? Is this even a proper way to do manual bilinear filtering on FP cube map? Or is there any other method that I may use?[/font]

Share this post


Link to post
Share on other sites
Advertisement
texCUBEgrad isn't going to get you anywhere...that simply lets you manually specify the derivatives used for mipmap selection. Basic bilinear filtering isn't really that complicated...basically you grab 4 texels and lerp between them based on the texture coordinate. You should be able to easily find some resources on the google, like this one or this one. Graphics hardware doesn't do anything fancy for cube maps, it just converts the 3D vector to a face index + 2D UV coordinate with a simple formula (face index is taken from the largest component, U and V are taken from the other two components) and then does a regular bilinear fetch from that face. Consequently it doesn't properly filter across faces. You can implement this in a pixel shader, except in SM3.0 you have to use dynamic branching to select the cubemap face since you don't have texture arrays.

In light of that, you might want to go ahead and implement something better than bilinear.

Share this post


Link to post
Share on other sites

texCUBEgrad isn't going to get you anywhere...that simply lets you manually specify the derivatives used for mipmap selection. Basic bilinear filtering isn't really that complicated...basically you grab 4 texels and lerp between them based on the texture coordinate. You should be able to easily find some resources on the google, like this one or this one. Graphics hardware doesn't do anything fancy for cube maps, it just converts the 3D vector to a face index + 2D UV coordinate with a simple formula (face index is taken from the largest component, U and V are taken from the other two components) and then does a regular bilinear fetch from that face. Consequently it doesn't properly filter across faces. You can implement this in a pixel shader, except in SM3.0 you have to use dynamic branching to select the cubemap face since you don't have texture arrays.

In light of that, you might want to go ahead and implement something better than bilinear.


Thanks MJP, but I'm kinda confused on how to transform an (x, y, z) texcoord into a single cube face (x, y) texcoord. Can anyone give me a pseudocode on that? I guess the transformation would cause lots of additional instructions to be executed inside the shader. Would this be a great performance hit? I've tried to write it as:


// TextureCube size = 512

float4 texCUBEbilinear(samplerCUBE s, float4 t)
{
float4 color;
float3 absT = float3(abs(t.x), abs(t.y), abs(t.z));

[branch] if(absT.x > absT.y && absT.x > absT.z) // x is the biggest component
{
t.y = (0.5 * t.y / t.x + 0.5) * 512;
t.z = (0.5 * t.z / t.x + 0.5) * 512;

float u1 = (floor(t.y) / 512 - 0.5) * 2 * t.x;
float v1 = (floor(t.z) / 512 - 0.5) * 2 * t.x;
float u2 = (ceil(t.y) / 512 - 0.5) * 2 * t.x;
float v2 = (ceil(t.z) / 512 - 0.5) * 2 * t.x;

float fracU = frac(t.y);
float fracV = frac(t.z);

float ul = (1.0f - fracU) * (1.0f - fracV);
float ll = (1.0f - fracU) * fracV;
float ur = fracU * (1.0f - fracV);
float lr = fracU * fracV;

color = ul * texCUBElod(s, float4(t.x, u1, v1, 0)) +
ur * texCUBElod(s, float4(t.x, u2, v1, 0)) +
ll * texCUBElod(s, float4(t.x, u1, v2, 0)) +
lr * texCUBElod(s, float4(t.x, u2, v2, 0));
}
else if(absT.y > absT.x && absT.y > absT.z) // y is the biggest component
{
t.x = (0.5 * t.x / t.y + 0.5) * 512;
t.z = (0.5 * t.z / t.y + 0.5) * 512;

float u1 = (floor(t.x) / 512 - 0.5) * 2 * t.y;
float v1 = (floor(t.z) / 512 - 0.5) * 2 * t.y;
float u2 = (ceil(t.x) / 512 - 0.5) * 2 * t.y;
float v2 = (ceil(t.z) / 512 - 0.5) * 2 * t.y;

float fracU = frac(t.x);
float fracV = frac(t.z);

float ul = (1.0f - fracU) * (1.0f - fracV);
float ll = (1.0f - fracU) * fracV;
float ur = fracU * (1.0f - fracV);
float lr = fracU * fracV;

color = ul * texCUBElod(s, float4(u1, t.y, v1, 0)) +
ur * texCUBElod(s, float4(u2, t.y, v1, 0)) +
ll * texCUBElod(s, float4(u1, t.y, v2, 0)) +
lr * texCUBElod(s, float4(u2, t.y, v2, 0));
}
else // z is the biggest component
{
t.x = (0.5 * t.x / t.z + 0.5) * 512;
t.y = (0.5 * t.y / t.z + 0.5) * 512;

float u1 = (floor(t.x) / 512 - 0.5) * 2 * t.z;
float v1 = (floor(t.y) / 512 - 0.5) * 2 * t.z;
float u2 = (ceil(t.x) / 512 - 0.5) * 2 * t.z;
float v2 = (ceil(t.y) / 512 - 0.5) * 2 * t.z;

float fracU = frac(t.x);
float fracV = frac(t.y);

float ul = (1.0f - fracU) * (1.0f - fracV);
float ll = (1.0f - fracU) * fracV;
float ur = fracU * (1.0f - fracV);
float lr = fracU * fracV;

color = ul * texCUBElod(s, float4(u1, v1, t.z, 0)) +
ur * texCUBElod(s, float4(u2, v1, t.z, 0)) +
ll * texCUBElod(s, float4(u1, v2, t.z, 0)) +
lr * texCUBElod(s, float4(u2, v2, t.z, 0));
}
return color;
}

It turned out to exceed the instruction limit of SM 3 (as I've already used a lot of instructions in raytracing itself).. Any other options guys? :(

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!