319 lines
8.3 KiB
HLSL
319 lines
8.3 KiB
HLSL
#define NOVERTEX 0xfffffffe
|
|
|
|
struct VSSceneIn
|
|
{
|
|
float4 Pos : POSITION;
|
|
float3 Norm : NORMAL;
|
|
float2 Tex : TEXCOORD;
|
|
};
|
|
|
|
struct PSSceneIn
|
|
{
|
|
float4 Pos : SV_Position;
|
|
float4 Color : COLOR0;
|
|
};
|
|
|
|
struct GSShadowIn
|
|
{
|
|
float3 Pos : POS;
|
|
float3 Norm : NORMAL;
|
|
};
|
|
|
|
struct PSShadowIn
|
|
{
|
|
float4 Pos : SV_Position;
|
|
};
|
|
|
|
|
|
matrix WorldMatrix : WorldMatrix;
|
|
matrix ViewMatrix : ViewMatrix;
|
|
matrix ProjectionMatrix : ProjectionMatrix;
|
|
|
|
float3 LightPos : LightPosition;
|
|
float ExtrudeAmt = 10.0f;
|
|
float ExtrudeBias = 0.0f;
|
|
float4 ShadowColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
DepthStencilState DisableDepth
|
|
{
|
|
DepthEnable = FALSE;
|
|
DepthWriteMask = ZERO;
|
|
};
|
|
|
|
DepthStencilState EnableDepth
|
|
{
|
|
DepthEnable = TRUE;
|
|
DepthWriteMask = ALL;
|
|
};
|
|
|
|
DepthStencilState TwoSidedStencil
|
|
{
|
|
DepthEnable = true;
|
|
DepthWriteMask = ZERO;
|
|
DepthFunc = Less;
|
|
|
|
// Setup stencil states
|
|
StencilEnable = true;
|
|
StencilReadMask = 0xFFFFFFFF;
|
|
StencilWriteMask = 0xFFFFFFFF;
|
|
|
|
BackFaceStencilFunc = Always;
|
|
BackFaceStencilDepthFail = Incr;
|
|
BackFaceStencilPass = Keep;
|
|
BackFaceStencilFail = Keep;
|
|
|
|
FrontFaceStencilFunc = Always;
|
|
FrontFaceStencilDepthFail = Decr;
|
|
FrontFaceStencilPass = Keep;
|
|
FrontFaceStencilFail = Keep;
|
|
};
|
|
|
|
|
|
DepthStencilState RenderNonShadows
|
|
{
|
|
DepthEnable = true;
|
|
DepthWriteMask = ZERO;
|
|
DepthFunc = Less_Equal;
|
|
|
|
StencilEnable = true;
|
|
StencilReadMask = 0xFFFFFFFF;
|
|
StencilWriteMask = 0x0;
|
|
|
|
FrontFaceStencilFunc = NOT_EQUAL;
|
|
FrontFaceStencilPass = Keep;
|
|
FrontFaceStencilFail = ZERO;
|
|
|
|
BackFaceStencilFunc = Never;
|
|
BackFaceStencilPass = ZERO;
|
|
BackFaceStencilFail = ZERO;
|
|
};
|
|
|
|
BlendState DisableFrameBuffer
|
|
{
|
|
BlendEnable[0] = FALSE;
|
|
RenderTargetWriteMask[0] = 0x0;
|
|
};
|
|
|
|
BlendState EnableFrameBuffer
|
|
{
|
|
BlendEnable[0] = FALSE;
|
|
RenderTargetWriteMask[0] = 0x0F;
|
|
};
|
|
|
|
BlendState SrcAlphaBlending
|
|
{
|
|
AlphaToCoverageEnable = FALSE;
|
|
BlendEnable[0] = TRUE;
|
|
SrcBlend = SRC_ALPHA;
|
|
DestBlend = INV_SRC_ALPHA;
|
|
BlendOp = ADD;
|
|
SrcBlendAlpha = ZERO;
|
|
DestBlendAlpha = ZERO;
|
|
BlendOpAlpha = ADD;
|
|
RenderTargetWriteMask[0] = 0x0F;
|
|
};
|
|
|
|
|
|
BlendState AdditiveBlending
|
|
{
|
|
AlphaToCoverageEnable = FALSE;
|
|
BlendEnable[0] = TRUE;
|
|
SrcBlend = ONE;
|
|
DestBlend = ONE;
|
|
BlendOp = SUBTRACT;
|
|
SrcBlendAlpha = ZERO;
|
|
DestBlendAlpha = ZERO;
|
|
BlendOpAlpha = ADD;
|
|
RenderTargetWriteMask[0] = 0x0F;
|
|
};
|
|
|
|
RasterizerState DisableCulling
|
|
{
|
|
CullMode = NONE;
|
|
};
|
|
|
|
RasterizerState EnableCulling
|
|
{
|
|
CullMode = BACK;
|
|
};
|
|
|
|
|
|
//
|
|
// VS for sending information to the shadow GS
|
|
//
|
|
GSShadowIn VSShadowmain( VSSceneIn input )
|
|
{
|
|
GSShadowIn output = (GSShadowIn)0.0;
|
|
|
|
//output our position in world space
|
|
float4 pos = mul( float4(input.Pos.xyz,1), WorldMatrix );
|
|
output.Pos = pos.xyz;
|
|
|
|
//world space normal
|
|
output.Norm = mul( input.Norm, (float3x3)WorldMatrix );
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
PSSceneIn VSScenemain( VSSceneIn input )
|
|
{
|
|
PSSceneIn output = (PSSceneIn)0.0;
|
|
|
|
//output our final position in clipspace
|
|
output.Pos = mul(input.Pos, WorldMatrix);
|
|
output.Pos = mul(output.Pos, ViewMatrix);
|
|
output.Pos = mul(output.Pos, ProjectionMatrix);
|
|
|
|
//world space normal
|
|
float3 norm = mul( input.Norm, (float3x3)WorldMatrix );
|
|
|
|
//find the light dir
|
|
float3 wpos = mul( input.Pos, (float3x3)WorldMatrix );
|
|
|
|
float3 lightDir = normalize( LightPos - wpos );
|
|
float lightLenSq = length(LightPos - wpos);
|
|
|
|
output.Color = saturate(dot(lightDir,norm)) * ShadowColor * 8.0f/lightLenSq;
|
|
|
|
return output;
|
|
}
|
|
|
|
// PS for rendering lit and textured triangles
|
|
float4 PSScenemain(PSSceneIn input) : SV_Target
|
|
{
|
|
return input.Color;
|
|
}
|
|
|
|
// Helper to detect a silhouette edge and extrude a volume from it
|
|
void DetectAndProcessSilhouette(float3 N, // Un-normalized triangle normal
|
|
GSShadowIn v1, // Shared vertex
|
|
GSShadowIn v2, // Shared vertex
|
|
GSShadowIn vAdj, // Adjacent triangle vertex
|
|
inout TriangleStream<PSShadowIn> ShadowTriangleStream // triangle stream
|
|
)
|
|
{
|
|
float3 NAdj = cross(v2.Pos - vAdj.Pos, v1.Pos - vAdj.Pos);
|
|
|
|
float fDot = dot(normalize(N), normalize(NAdj));
|
|
if (fDot < 0.0)
|
|
{
|
|
float3 outpos[4];
|
|
float3 extrude1 = normalize(v1.Pos - LightPos);
|
|
float3 extrude2 = normalize(v2.Pos - LightPos);
|
|
|
|
outpos[0] = v1.Pos + ExtrudeBias * extrude1;
|
|
outpos[1] = v1.Pos + ExtrudeAmt * extrude1;
|
|
outpos[2] = v2.Pos + ExtrudeBias * extrude2;
|
|
outpos[3] = v2.Pos + ExtrudeAmt * extrude2;
|
|
|
|
// Extrude silhouette to create two new triangles
|
|
PSShadowIn Out;
|
|
for(int v = 0; v < 4; v++)
|
|
{
|
|
Out.Pos = mul(float4(outpos[v], 1.0f), ViewMatrix);
|
|
Out.Pos = mul(Out.Pos, ProjectionMatrix);
|
|
|
|
ShadowTriangleStream.Append(Out);
|
|
}
|
|
ShadowTriangleStream.RestartStrip();
|
|
}
|
|
}
|
|
|
|
// GS for generating shadow volumes
|
|
[maxvertexcount(18)]
|
|
void GSShadowmain(triangleadj GSShadowIn In[6], inout TriangleStream<PSShadowIn> ShadowTriangleStream)
|
|
{
|
|
// Compute un-normalized triangle normal
|
|
float3 N = normalize(cross(In[2].Pos - In[0].Pos, In[4].Pos - In[0].Pos));
|
|
|
|
// Compute direction from this triangle to the light
|
|
float3 lightDir[3];
|
|
lightDir[0] = normalize(LightPos - In[0].Pos);
|
|
lightDir[1] = normalize(LightPos - In[2].Pos);
|
|
lightDir[2] = normalize(LightPos - In[4].Pos);
|
|
|
|
//if we're facing the light
|
|
if(dot(N, lightDir[0]) > 0.0f || dot(N, lightDir[1]) > 0.0f || dot(N, lightDir[2]) > 0.0f)
|
|
{
|
|
// For each edge of the triangle, determine if it is a silhouette edge
|
|
DetectAndProcessSilhouette(lightDir[0], In[0], In[2], In[1], ShadowTriangleStream);
|
|
DetectAndProcessSilhouette(lightDir[1], In[2], In[4], In[3], ShadowTriangleStream);
|
|
DetectAndProcessSilhouette(lightDir[2], In[4], In[0], In[5], ShadowTriangleStream);
|
|
|
|
//near cap
|
|
PSShadowIn Out;
|
|
for(int v = 0; v < 6; v += 2)
|
|
{
|
|
float3 extrude = normalize(In[v].Pos - LightPos);
|
|
|
|
float3 Pos = In[v].Pos + ExtrudeBias * extrude;
|
|
Out.Pos = mul(float4(Pos, 1.0f), ViewMatrix);
|
|
Out.Pos = mul(Out.Pos, ProjectionMatrix);
|
|
ShadowTriangleStream.Append(Out);
|
|
}
|
|
ShadowTriangleStream.RestartStrip();
|
|
|
|
//far cap (reverse the order)
|
|
for(int v2 = 4; v2 >= 0; v2 -= 2)
|
|
{
|
|
float3 extrude = normalize(In[v2].Pos - LightPos);
|
|
|
|
float3 Pos = In[v2].Pos + ExtrudeAmt * extrude;
|
|
Out.Pos = mul(float4(Pos, 1.0f), ViewMatrix);
|
|
Out.Pos = mul(Out.Pos, ProjectionMatrix);
|
|
ShadowTriangleStream.Append( Out );
|
|
}
|
|
ShadowTriangleStream.RestartStrip();
|
|
}
|
|
}
|
|
|
|
// PS for rendering shadow scene
|
|
float4 PSShadowmain(PSShadowIn input) : SV_Target
|
|
{
|
|
return float4(0.3,0,0,0.25);
|
|
}
|
|
|
|
// RenderShadow - extrudes shadows from geometry
|
|
technique10 CastShadows
|
|
{
|
|
pass p0
|
|
{
|
|
SetVertexShader( CompileShader( vs_4_0, VSShadowmain() ) );
|
|
SetGeometryShader( CompileShader( gs_4_0, GSShadowmain() ) );
|
|
SetPixelShader( CompileShader( ps_4_0, PSShadowmain() ) );
|
|
|
|
SetBlendState( DisableFrameBuffer, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
|
SetDepthStencilState( TwoSidedStencil, 1 ); //state, stencilref
|
|
SetRasterizerState( DisableCulling );
|
|
}
|
|
}
|
|
|
|
|
|
technique10 ShowShadowVolume
|
|
{
|
|
pass p0
|
|
{
|
|
SetVertexShader( CompileShader( vs_4_0, VSShadowmain() ) );
|
|
SetGeometryShader( CompileShader( gs_4_0, GSShadowmain() ) );
|
|
SetPixelShader( CompileShader( ps_4_0, PSShadowmain() ) );
|
|
|
|
SetBlendState( SrcAlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
|
SetDepthStencilState( TwoSidedStencil, 1 ); //state, stencilref
|
|
SetRasterizerState( DisableCulling );
|
|
}
|
|
}
|
|
|
|
technique10 ReceiveShadows
|
|
{
|
|
pass p0
|
|
{
|
|
SetVertexShader( CompileShader( vs_4_0, VSScenemain() ) );
|
|
SetGeometryShader( NULL );
|
|
SetPixelShader( CompileShader( ps_4_0, PSScenemain() ) );
|
|
|
|
SetBlendState( SrcAlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
|
SetDepthStencilState( RenderNonShadows, 0 ); //state, stencilref
|
|
SetRasterizerState( EnableCulling );
|
|
}
|
|
} |