Tuesday, July 10, 2012

Triplanar Texture Mapping, Part 2

Well, I wasn't completely happy with the triplanar mapping I had done earlier, so I decided to revisit it briefly.  I've redone after reading bits of GPU Gems 3 again, in what is a simpler manner.  The terrain drawing pixel shader now is:


PixelShaderOutput PixelShaderFunction(MTVertexToPixel PSIn) 
 PixelShaderOutput output;

 // Texture planar projection calculations
 float3 blend_weights  = abs(PSIn.Normal); // Start with normal passed in.
 blend_weights = (blend_weights - 0.2); // Tighten up the blending zone. Original GPU Gems muls by 7 arbitrarily.
 blend_weights = max(blend_weights, 0);  //Eliminate any negatives.
 blend_weights /= (blend_weights.x + blend_weights.y + blend_weights.z ).xxx;
 // original planar texture mapping way.
 // output.Color = tex2D(TextureSampler0, PSIn.TextureCoords.xz)*PSIn.TextureWeights.x;
 // output.Color += tex2D(TextureSampler1, PSIn.TextureCoords.xz)*PSIn.TextureWeights.y;
 // output.Color += tex2D(TextureSampler2, PSIn.TextureCoords.xz)*PSIn.TextureWeights.z;
 // output.Color += tex2D(TextureSampler3, PSIn.TextureCoords.xz)*PSIn.TextureWeights.w;  

   float4 cXY;
   float4 cXZ;
   float4 cYZ;

 cXY = tex2D(TextureSampler0, PSIn.TextureCoords.xy);
 cXZ = tex2D(TextureSampler0, PSIn.TextureCoords.xz);
 cYZ = tex2D(TextureSampler0, PSIn.TextureCoords.yz); 
 output.Color = (cXY*blend_weights.z + cXZ*blend_weights.y + cYZ*blend_weights.x) * PSIn.TextureWeights.x; 

 cXY = tex2D(TextureSampler1, PSIn.TextureCoords.xy);
 cXZ = tex2D(TextureSampler1, PSIn.TextureCoords.xz);
 cYZ = tex2D(TextureSampler1, PSIn.TextureCoords.yz); 
 output.Color += (cXY*blend_weights.z + cXZ*blend_weights.y + cYZ*blend_weights.x) * PSIn.TextureWeights.y; 

 cXY = tex2D(TextureSampler2, PSIn.TextureCoords.xy);
 cXZ = tex2D(TextureSampler2, PSIn.TextureCoords.xz);
 cYZ = tex2D(TextureSampler2, PSIn.TextureCoords.yz); 
 output.Color += (cXY*blend_weights.z + cXZ*blend_weights.y + cYZ*blend_weights.x) * PSIn.TextureWeights.z; 

 cXY = tex2D(TextureSampler3, PSIn.TextureCoords.xy);
 cXZ = tex2D(TextureSampler3, PSIn.TextureCoords.xz);
 cYZ = tex2D(TextureSampler3, PSIn.TextureCoords.yz); 
 output.Color += (cXY*blend_weights.z + cXZ*blend_weights.y + cYZ*blend_weights.x)*PSIn.TextureWeights.w; 


This is definitely simpler, but there are some interesting bits.  In the original bit that tightens up the blend zone

blend_weights = (blend_weights - 0.2) * 7;

Ryan Geiss of Nvidia adds the arbitrary multiplication by 7.  Removing that, or changing it to 1000... doesn't seem to make a difference, so I removed it.  In any case I can't see any visual difference (and there shouldn't be any, I should think, as you basically normalize the blend values shortly thereafter).

One other thing I am curious about was the color multiplication.  There he did:

blended_color = col1.xyzw * blend_weights.xxxx +
                col2.xyzw * blend_weights.yyyy +
                col3.xyzw * blend_weights.zzzz;

I'm curious why he did 'col1.xyzw * blend_weights.xxxx' rather than simply 'col1 * blend_weights.x'.  Possibly this is quicker somehow (avoiding any type of casting or type checking)?  In any case I simply did the latter and it seems to work fine.

I decided to test my changes this with a worst-case texture, so I grabbed a brick texture and replaced the basic grass with it.  Looks to be working pretty well so far:


Back to the normal textures looks good, too:

No comments:

Post a Comment