bool AUTORELOAD;
float4x4 matWorldViewProj;
float4x4 matWorld;
float4x4 matWorldInv;
float4x4 matWorldView;
float4x4 matView;
float4x4 matViewInv;
float4 vecSunDir;
float4 vecViewPos;
float4 vecTime;
float4 vecSkill41;
texture entSkin1;
//texture entSkin2;
texture mtlSkin1;
texture mtlSkin2;
texture mtlSkin3;
texture mtlSkin4;
sampler AmbOccMapSampler = sampler_state
{
Texture = <entSkin1>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = clamp;
AddressV = clamp;
};
sampler ColorMapSampler = sampler_state
{
Texture = <mtlSkin1>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = wrap;
AddressV = wrap;
};
sampler BumpMapSampler = sampler_state
{
Texture = <mtlSkin2>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = wrap;
AddressV = wrap;
};
sampler DepthMapSampler = sampler_state
{
Texture = <mtlSkin3>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = wrap;
AddressV = wrap;
};
sampler DetailMapSampler = sampler_state
{
Texture = <mtlSkin4>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = wrap;
AddressV = wrap;
};
void DiffuseVS
(
in float4 vPos : POSITION,
in float2 iTex : TEXCOORD0,
in float3 normal : NORMAL,
out float3 outnormal : TEXCOORD0,
out float3 oPos : TEXCOORD1,
out float3 View : TEXCOORD2,
out float3 OS_View : TEXCOORD5,
out float2 oTex : TEXCOORD3,
out float4 Pos : POSITION
)
{
normal=mul(normal,matWorld);
vPos=mul(vPos,matWorld);
oPos=vPos;
oTex=iTex;
outnormal=normal;
Pos = mul(vPos,matWorldViewProj);
float3 wPos=mul(vPos,matWorld);
View=normalize(vecViewPos-wPos);
OS_View=normalize(mul(vecViewPos,matWorldInv)-vPos);
}
///////////////////
float3 sample_ColorProj(sampler2D ColorSampler, float3 BlendF,
float2 Tex1, float2 Tex2, float2 Tex3)
{
float3 Col1=tex2D(ColorSampler,Tex1.xy);
float3 Col2=tex2D(ColorSampler,Tex2.xy);
float3 Col3=tex2D(ColorSampler,Tex3.xy);
return Col1*BlendF.x + Col2*BlendF.y + Col3*BlendF.z;
}
float3 sample_DepthProj(sampler2D DepthSampler, float3 BlendF,
float2 Tex1, float2 Tex2, float2 Tex3)
{
float3 D;
D.x=tex2Dlod(DepthSampler,float4(Tex1.xy,0,0)).x;
D.y=tex2Dlod(DepthSampler,float4(Tex2.xy,0,0)).x;
D.z=tex2Dlod(DepthSampler,float4(Tex3.xy,0,0)).x;
return dot(D,BlendF);
}
float3 sample_NormalProj(sampler2D NormalSampler, float3 BlendF,
float2 Tex1, float2 Tex2, float2 Tex3, float3x3 matTangent13, float3x3 matTangent2)
{
float3 NM1=tex2D(NormalSampler,Tex1.xy)*2.f-1.f;
float3 NM2=tex2D(NormalSampler,Tex2.xy)*2.f-1.f;
float3 NM3=tex2D(NormalSampler,Tex3.xy)*2.f-1.f;
NM1=mul(NM1,matTangent13);
NM2=mul(NM2,matTangent2);
NM3=mul(NM3,matTangent13);
return normalize(NM1*BlendF.x + NM2*BlendF.y + NM3*BlendF.z);
}
float3 sample_NormalProj_simple(sampler2D NormalSampler, float3 BlendF,
float2 Tex1, float2 Tex2, float2 Tex3, float3 Normal, float3 ds, float BumpWeight)
{
float3 NM1=tex2D(NormalSampler,Tex1.xy)*2.f-1.f;
float3 NM2=tex2D(NormalSampler,Tex2.xy)*2.f-1.f;
float3 NM3=tex2D(NormalSampler,Tex3.xy)*2.f-1.f;
NM1=float3(0,-NM1.y,NM1.x*ds.x);
NM2=float3(NM2.x,0,-NM2.y*ds.y);
NM3=float3(-NM3.x*ds.z,-NM3.y,0);
return normalize(Normal+(NM1*BlendF.x + NM2*BlendF.y + NM3*BlendF.z)*BumpWeight);
}
float IntersectionTest(
in float3 BlendF,
in float2 Tex1, in float2 Off1,
in float2 Tex2, in float2 Off2,
in float2 Tex3, in float2 Off3,
in float Bias)
{
const int linear_search_steps=15;
float depth_step=1.0/linear_search_steps;
float size=depth_step; // current size of search window
float depth=-Bias; // current depth position
float lastHeight=0;
float height=0;
// search from front to back for first point inside the object
for(int i=0;i<linear_search_steps-1;i++)
{
height=sample_DepthProj(DepthMapSampler, BlendF, Tex1+Off1*depth, Tex2+Off2*depth, Tex3+Off3*depth);
if (depth < height-Bias)
{
depth+=size;
lastHeight = height;
}
}
// #define USE_BINARY_SEARCH
#ifdef USE_BINARY_SEARCH
const int binary_search_steps=7;
//search around first point (depth) for closest match
for ( int i=0; i<binary_search_steps;i++)
{
size*=0.5f;
height=sample_DepthProj(DepthMapSampler, BlendF, Tex1+Off1*depth, Tex2+Off2*depth, Tex3+Off3*depth);
if (depth<height-Bias)
depth += (2*size);
depth -= size;
}
#else
depth+=Bias;
depth = ( depth - size * ( 1 - ( (depth-size-lastHeight) / (height-size-lastHeight) ) ) );
depth-=Bias;
#endif
return depth;
}
float4 DiffusePS
(
in float3 normal : TEXCOORD0,
in float3 Pos : TEXCOORD1,
in float3 View : TEXCOORD2,
in float3 OS_View : TEXCOORD5,
in float2 Tex : TEXCOORD3
) : COLOR
{
float4 c;
normal=normalize(normal);
View=normalize(View);
OS_View=normalize(OS_View);
float s=80;
Pos.xyz/=s;
///////////////////////////////////////////////////////
//===================================================//
float3 ds=sign(normal);
float2 Tex1=Pos.zy*float2(ds.x,-1.f);
float2 Tex2=Pos.xz*float2(1.f,-ds.y);
float2 Tex3=Pos.xy*float2(-ds.z,-1.f);
#define USE_REALTANGENTBASE //usually not required, but if you project on a sphere you can see the difference clearly
#ifdef USE_REALTANGENTBASE
float3x3 matTangent13;
matTangent13[0]=cross(normal,float3(0.f,1.f,0.f));
matTangent13[1]=cross(normal,matTangent13[0]);
matTangent13[2]=normal;
float3x3 matTangent2;
matTangent2[0]=cross(normal,float3(0.f,0.f,1.f));
matTangent2[1]=cross(normal,matTangent2[0]);
matTangent2[2]=normal;
matTangent2[0]*=ds.y;
matTangent2[1]*=ds.y;
#endif
//===================================================//
///////////////////////////////////////////////////////
float3 BlendF=pow(abs(normal), 60.f);
BlendF/=dot(BlendF.xyz,1.f);
///////////////////////////////////////////////////////
//===================================================//
const float off_scale=0.08f;
float3 ProjView=cross(cross(OS_View,normal),normal)*off_scale;
float2 offset_vec1=ProjView.zy*float2(ds.x,-1.f);
float2 offset_vec2=ProjView.xz*float2(1,-ds.y);
float2 offset_vec3=ProjView.xy*float2(-ds.z,-1.f);
//-----//dont use the following to create the offset_vecs, it´s slower and less consistent:
// offset_vec1 =-mul(matTangent13,OS_View).xy*off_scale;
// offset_vec2 =-mul(matTangent2 ,OS_View).xy*off_scale;
// offset_vec3=offset_vec1;
//-----//
float offset_length = IntersectionTest(BlendF,
Tex1.xy, offset_vec1,
Tex2.xy, offset_vec2,
Tex3.xy, offset_vec3,1.f);
Tex1.xy+=offset_vec1*offset_length;
Tex2.xy+=offset_vec2*offset_length;
Tex3.xy+=offset_vec3*offset_length;
//===================================================//
///////////////////////////////////////////////////////
float3 Albedo=sample_ColorProj(ColorMapSampler,BlendF,Tex1,Tex2,Tex3);
#ifdef USE_REALTANGENTBASE
float3 Bump=sample_NormalProj(BumpMapSampler,BlendF,Tex1,Tex2,Tex3,matTangent13,matTangent2);
#else
float3 Bump=sample_NormalProj_simple(BumpMapSampler,BlendF,Tex1,Tex2,Tex3,normal,ds,1.f);
#endif
Bump=mul(Bump,matWorld);
normal=mul(normal,matWorld);
///////////////////////////////////////////////////////add some interesting lighting for visualisation:
//===================================================//
float AmbOcc=tex2D(AmbOccMapSampler,Tex).r;
float SunLight_Bump=dot(vecSunDir,Bump);
float SunLight_Smooth=dot(vecSunDir,normal);
float SunLight_Bump_BackBleed=SunLight_Bump*0.5f+0.5f;
float SunLight_Bump_BackBleed2=SunLight_Bump*0.2f+0.8f;
float SunLight_Smooth_BackBleed=SunLight_Smooth*0.5f+0.5f;
SunLight_Bump=saturate(SunLight_Bump);
SunLight_Smooth=saturate(SunLight_Smooth);
float SunLight_Amount=min(1.f, SunLight_Bump+SunLight_Smooth);
float SunLight_Back=SunLight_Bump_BackBleed*SunLight_Smooth_BackBleed;
SunLight_Back=lerp(SunLight_Bump_BackBleed2*0.05f,1.f,SunLight_Back);
c.rgb=Albedo*AmbOcc*lerp(SunLight_Back,SunLight_Bump,SunLight_Amount);
c.a=1;
//===================================================//
///////////////////////////////////////////////////////
// c.rg=offset_vec1*BlendF.x+offset_vec2*BlendF.y+offset_vec3*BlendF.z;
// c.rg=normalize(c.rg)*0.5+0.5;
// c.b=0;
// c.rgb=Bump;
return c;
}
technique DiffuseTechnique
{
pass P0
{
VertexShader = compile vs_3_0 DiffuseVS();
PixelShader = compile ps_3_0 DiffusePS();
}
}
As you can see the shader also shows how parallax-occlusion mapping can work together with triplanar-projection.
If anything is unclear, just ask.