Optimal Mult-Sampling in Pixel Shader ?

Started by
2 comments, last by PhillipHamlyn 11 years, 3 months ago

Hi,

I have a pixel shader for a terrain tile which samples a texture atlas for various ground cover.

I have around 8 different ground cover types which I pass to the PS via a Texture Blend Map using Texture2D NormalizedByte4 with one channel per texture weight.

Most pixels will blend perhaps 3 of the 8 possible textures, exceptionally 4.

What is the optimal way to sample the textures ?

I followed the standard "linear" "add them all up" approach, shown below;


textureColor += tex2D(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(0,0))) * textureWeights1.a;
textureColor += tex2D(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(1,0))) * textureWeights1.r ;
textureColor += tex2D(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(0,1))) * textureWeights1.g ;
textureColor += tex2D(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(1,1))) * textureWeights1.b ;
textureColor += tex2D(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(0,0))) * textureWeights2.a;
textureColor += tex2D(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(1,0))) * textureWeights2.r;
textureColor += tex2D(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(0,1))) * textureWeights2.g;
textureColor += tex2D(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(1,1))) * textureWeights2.b;

However I could have bypassed the many lookups by checking the texture weight prior to sampling. Like this


if(textureWeights1.r > 0) textureColor += tex2D(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(1,0))) * textureWeights1.r ;

Which is the recommended approach for performance in a pixel shader ? I understand that the PS can bypass texture lookups sometimes, but I dont know whether doing this manually by checking the texture weight myself is a better solution, especially because I expect only 50% maximum of the texture lookups to actually achieve anything.

Phillip


Advertisement

Yes, that's the way you'd do it. Use the [branch] attribute in front of your if statements to indicate you want dynamic branching.

Unfortunately, in order to successfully bypass the texture lookups, you'll need to use tex2Dlod, as gradient-based instructions don't work inside a dynamic branch (so you'll never see any benefit from your if statements if you keep using tex2D). This means you'll need to calculate the mipmap level manually outside the branch (assuming you're using mipmaps).

Thanks phil_t.

Unfortunately I'm using SM2 so cannot use tex2DLod. Fortunately it seems I can use text2DGrad to get the same outcome, in combination with ddx() and ddy() helpfully discussed here http://www.gamedev.net/topic/470659-anyone-tell-me-the-difference-of-tex2dgrad--and-tex2d/

Even more unfortunately although text2DGrad is supported in SM2 (and therefore Reach Profile) ddx() and ddy() are not supported until SM2.1.

It seems I need to abandon Reach profile in order to get optimal performance in branched texture lookups. Ah well, its only a hobby game, so moving to HiDef wont be an issue.

Phillip

Hmm,

I followed my nose and have the following now; which works nicely enough.


if(textureWeights1.a > 0) textureColor += tex2Dgrad(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(0,0)), texDdx, texDdy) * textureWeights1.a;
if(textureWeights1.r > 0) textureColor += tex2Dgrad(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(1,0)), texDdx, texDdy) * textureWeights1.r;
if(textureWeights1.g > 0) textureColor += tex2Dgrad(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(0,1)), texDdx, texDdy) * textureWeights1.g;
if(textureWeights1.b > 0) textureColor += tex2Dgrad(TextureSamplerAtlas1,getAtlasTextureCoords(textureCoords, float2(1,1)), texDdx, texDdy) * textureWeights1.b;

if(textureWeights2.a > 0) textureColor += tex2Dgrad(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(0,0)), texDdx, texDdy) * textureWeights2.a;
if(textureWeights2.r > 0) textureColor += tex2Dgrad(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(1,0)), texDdx, texDdy) * textureWeights2.r;
if(textureWeights2.g > 0) textureColor += tex2Dgrad(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(0,1)), texDdx, texDdy) * textureWeights2.g;
if(textureWeights2.b > 0) textureColor += tex2Dgrad(TextureSamplerAtlas2,getAtlasTextureCoords(textureCoords, float2(1,1)), texDdx, texDdy) * textureWeights2.b;

Phillip

This topic is closed to new replies.

Advertisement