How to implement bilinear filtering on DX11 hardware?

51mon

Newcomer
Hey
I’m currently porting a shadow system from Xbox 360 to DirectX 11. As a reference we want code with the same functionality to run on DirectX. The problem is that I can’t get the bilinear pcf interpolation to work properly. I tried many variants of the code but didn’t reach a satisfying result. This is how the code stands atm:

Code:
float4 vFrac; 

// Clamp the lookup coord so they will be in complete sync with the bilinear weights
vecFrac.xy = modf((vShadowCoord.xy) * float2(768.0f, 768.0f), vShadowCoord.xy);
vShadowCoord.xy /= float2(768.0f, 768.0f);

// Compute the bilinear weights
vecFrac.zw = float2(1.0f, 1.0f) - vecFrac.xy;		 
float4 vBilinearWeights = vecFrac.zxzx * vecFrac.wwyy;

float4 vSamples;

// Read the 4 neighbours
vSamples.x = shadowMap.Sample(pointSampler, offsetCoord.xy, int2( 0.0, 0.0 )).x;
vSamples.y = shadowMap.Sample(pointSampler, offsetCoord.xy, int2( 1.0, 0.0 )).x;
vSamples.z = shadowMap.Sample(pointSampler, offsetCoord.xy, int2( 0.0, 1.0 )).x;
vSamples.w = shadowMap.Sample(pointSampler, offsetCoord.xy, int2( 1.0, 1.0 )).x;

// Compute the depth comparision for each tap
vShadowCoord.z -= 0.001f;
vSamples = step(vShadowCoord.zzzz, vSamples);

// The result
float shadow = dot(vSamples, vecBilinearWeights);

If I can get this to work I can increase the number of taps and implement other filters as well. Hardware accelerated pcf(SampleCmpLevelZero) works fine and I don’t think there’s any wrong with the texture resource.

Does anybody know how I can implement proper bilinear texture filtering on DirectX 11 without using SampleCmpLevelZero? The artefacts I experience are sharp edges where the “interpolation” seems to start sudden. As the camera moves around the penumbra flickers like the sampling was dependent on the camera position.

jaggededge.jpg



Thanks a lot
 
From memory (no guarentee it will work!):

You need to take into account half-a-texel in your texel-space texture coordinate calculations - this is because D3D11 sampling rules are at pixel centre. Thus:

float2 vTexelTexcoords = vNormalizedTexcoord * vTextureSize.xy - float2(0.5, 0.5);

For example if your texture size is (8, 8) and your texcoords are (0.5, 0.5) then your texel coordinates would become:
vTexelTexcoords = (0.5, 0.5) * (8, 8) - (0.5, 0.5) = (3.5, 3.5)

Then from those texel coordinates you derive the texels to fetch from ( (3,3), (4,3), (3,4) and (4,4) ), and the fractional part is your weight for the bilinear calculation ( (0.5, 0.5) ).

As I said - it's all from memory so it may not be 100% correct. Hopefully it will help you find the correct solution.
 
Back
Top