#define WorldToTextureScale 128.0f // number of quants per texture repeat / tile
#define ProjectionPower 2.0f // Power for the projection, compensates brightnes differences; 2 gives perfect results (makes the blending gradient spherical)
//#define UseWorldSpace // calculate pixel position in world-space instead of entity-space; only for static entities, scale and angle must be default! moving/scaling/rotating looks UGLY!
// Debugging:
// #define DebugProjections
//
float4x4 matWorld;
float4x4 matView;
float4x4 matProj;
texture entSkin1; // Texture
sampler smpTex = sampler_state
{
Texture = <entSkin1>;
MipFilter = Anisotropic;
MagFilter = Anisotropic;
MinFilter = Anisotropic;
AddressU = Wrap;
AddressV = Wrap;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 Tex : TEXCOORD0;
float3 Normal : NORMAL;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
// float2 Tex : TEXCOORD0; // Not needed - triplanar texture mapping only needs the pixel's position and normal
float3 Normal : TEXCOORD1;
float4 Pos : TEXCOORD2;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, matWorld);
float4 viewPosition = mul(worldPosition, matView);
output.Position = mul(viewPosition, matProj);
// output.Tex = input.Tex; // Not needed - triplanar texture mapping only needs the pixel's position and normal
#ifdef UseWorldSpace
output.Pos = worldPosition; // position in world-space
#else
output.Pos = input.Position; // position in entity-space
#endif
output.Normal = input.Normal;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float3 PixelPos = -input.Pos.xyz / WorldToTextureScale;
/*
coords:
xz - Top & Bottom (Z-Axis)
yz - Front & Back (X-Axis)
xy - Left & Right (Y-Axis)
*/
// calculate intensity for every projection dir \\
// projection intensity - Top & Bottom:
// float zProj = pow(abs(dot(input.Normal, float3(0.f, 1.f, 0.f))), ProjectionPower); // pow to correct the blending gradient
// float zProj = pow(abs(input.Normal.y), ProjectionPower); // same as above
float zProj = input.Normal.y*input.Normal.y; // if ProjectionPower is = 2 it is the same
// projection intensity - Front & Back:
// float xProj = pow(abs(dot(input.Normal, float3(1.f, 0.f, 0.f))), ProjectionPower); // pow to correct the blending gradient
float xProj = input.Normal.x*input.Normal.x;
// projection intensity - Left & Right:
// float yProj = pow(abs(dot(input.Normal, float3(0.f, 0.f, 1.f))), ProjectionPower); // pow to correct the blending gradient
float yProj = input.Normal.z*input.Normal.z;
// project the texture from x, y and z direction \\
float4 Color = float4(0, 0, 0, 1); // set Base-RGBA (0,0,0,1)
Color.rgb += tex2D(smpTex, PixelPos.xz).rgb * zProj; // Z - Top, Bottom
Color.rgb += tex2D(smpTex, PixelPos.zy + 0.33333f).rgb * xProj; // X - Front, Back; move to prevent visible seams (otherwise the result looks like mirrored at specific angles)
Color.rgb += tex2D(smpTex, PixelPos.xy + 0.66666f).rgb * yProj; // Y - Left, Right; move to prevent visible seams (otherwise the result looks like mirrored at specific angles)
#ifdef DebugProjections
Color.rgb = float3(xProj, yProj, zProj);
#endif
return Color;
}
technique Technique1
{
pass Pass1
{
AlphaBlendEnable = TRUE;
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}