|
[SUB] Omnidirectional shadows
#403440
06/20/12 11:32
06/20/12 11:32
|
Joined: Jun 2007
Posts: 1,337 Hiporope and its pain
txesmi
OP
Serious User
|
OP
Serious User
Joined: Jun 2007
Posts: 1,337
Hiporope and its pain
|
Hi, since i received many requests about the shadows I shown on the what are you working on topic, i decided to explain how they are computed. I have to say that this shader is not a solution for any game. It is just a hobbyist workaround looking for a dynamic point shadow projection. In fact, it only works with models and sprites and it has not native lights support. The light properties are passed through the material skills. The shadows are computed with a depth cubemap that is rendered over a 32bit floating point bitmap, very similar to the 3dgs shadows example but with six cameras instead of one. somewhere in the code:
MATERIAL *mtlOmniShadow = { effect = "omnishadows.fx"; }
MATERIAL *mtlDepth = { effect = "depth.fx"; }
...
// lightening settings
mtlOmniShadow.skill1 = floatv ( 0 ); // Light position
mtlOmniShadow.skill2 = floatv ( 0 ); // swapped axes!
mtlOmniShadow.skill3 = floatv ( 0 );
mtlOmniShadow.skill4 = floatv ( 1000 ); // Light range in quants
mtlOmniShadow.skill5 = floatv ( 1 ); // Light color RGB 0<->1
mtlOmniShadow.skill6 = floatv ( 1 );
mtlOmniShadow.skill7 = floatv ( 1 );
// depth cubemap
BMAP *cubemap = bmap_create ( "#3072x512x14" );
bmap_to_cubemap ( cubemap );
mtlOmniShadow.skin1 = cubemap;
// cubemap render views
VIEW *DepthView[6];
for ( i=0; i<6; i++ )
{
DepthView[i] = view_create ( 1 );
DepthView[i].arc = 90;
DepthView[i].size_x = 512;
DepthView[i].size_y = 512;
DepthView[i].pos_x = i * 512;
DepthView[i].pos_y = 0;
DepthView[i].clip_near = 1;
DepthView[i].clip_far = 1500;
DepthView[i].bmap = cubemap;
DepthView[i].material = mtlDepth;
DepthView[i].flags = SHOW;
}
DepthView[0].pan = 180;
DepthView[0].tilt = 0;
DepthView[1].pan = 90;
DepthView[1].tilt = 0;
DepthView[2].pan = 0;
DepthView[2].tilt = 0;
DepthView[3].pan = 270;
DepthView[3].tilt = 0;
DepthView[4].pan = 90;
DepthView[4].tilt = -90;
DepthView[5].pan = 90;
DepthView[5].tilt = 90;
Continuing with the differences to the 3dgs shadows example, the depth shader computes the distance between the light and the lighted surface in world space instead of the z axis (depth) in view space, so the returned red channel value is the real distance to the light point. depth.fx:
float4x4 matWorldViewProj;
float4x4 matWorld;
float4 vecViewPos;
texture entSkin1;
sampler TexSampler = sampler_state { Texture = <entSkin1>; Mipfilter = Linear; };
void DepthVS (
in float4 InPos : POSITION,
in float2 InTex : TEXCOORD0,
out float4 OutPos : POSITION,
out float3 OutWorld : TEXCOORD0,
out float2 OutTex : TEXCOORD1 )
{
OutPos = mul ( InPos, matWorldViewProj );
OutWorld = mul ( InPos.xyz, matWorld );
OutTex = InTex.xy;
}
float4 DepthPS(
in float3 InWorld : TEXCOORD0,
in float2 InTex : TEXCOORD1 ) : COLOR0
{
float4 Tex = tex2D ( TexSampler, InTex );
return float4( distance( InWorld.xyz, vecViewPos.xyz ), 0.0, 0.0, Tex.a );
}
technique Depth
{
pass p0
{
ZWriteEnable = True;
AlphaBlendEnable = True;
AlphaTestEnable = True;
AlphaFunc = Greater;
Lighting = False;
VertexShader = compile vs_2_0 DepthVS();
PixelShader = compile ps_2_0 DepthPS();
}
}
Diffuse, specular and light range maths are directly taken from the shader programming tutorials omnishadows.fx
static const float fDark = 0.1f; // shadow
static const float fBright = 1.0f; // light
static const float fDepthOffset = 0.97f;
float4x4 matWorldViewProj;
float4x4 matWorld;
float4 vecViewPos;
float3x3 matTangent; // tangent space matrix
float4 vecSkill1; // light position (xyz), light range (w)
float4 vecSkill5; // light color (xyz)
texture mtlSkin1; // depth cubemap
texture entSkin1; // texture
texture entSkin2; // normals (rgb) + specularity (a)
samplerCUBE CubeSampler = sampler_state { Texture = <mtlSkin1>; MipFilter = Linear; MinFilter = Linear; MagFilter = Linear; };
sampler TexSampler = sampler_state { Texture = <entSkin1>; Mipfilter = Linear; };
sampler NormalSampler = sampler_state { Texture = <entSkin2>; Mipfilter = Linear; };
void OmniShadowVS (
in float4 inPos: POSITION,
in float3 inNormal: NORMAL,
in float2 inTex: TEXCOORD0,
in float4 inTangent: TEXCOORD2,
out float4 outPos: POSITION,
out float2 outTex: TEXCOORD0,
out float3 outNormal: TEXCOORD1,
out float4 outWorld: TEXCOORD2,
out float3 outViewDir: TEXCOORD3,
out float3 outLightDir: TEXCOORD4 )
{
outPos = mul( inPos, matWorldViewProj );
outTex = inTex;
outNormal = normalize( mul( inNormal, matWorld ) );
outWorld = mul( inPos, matWorld );
matTangent[0] = mul(inTangent.xyz, matWorld);
matTangent[1] = mul(cross(inTangent.xyz, inNormal)*inTangent.w, matWorld);
matTangent[2] = mul(inNormal, matWorld);
outViewDir = normalize ( mul ( matTangent, vecViewPos.xyz - outWorld.xyz ) );
outLightDir = normalize ( mul ( matTangent, vecSkill1.xyz - outWorld.xyz ) );
}
float4 OmniShadowPS (
in float4 inPos: POSITION,
in float2 inTex: TEXCOORD0,
in float3 inNormal: TEXCOORD1,
in float4 inWorld: TEXCOORD2,
in float3 inViewDir : TEXCOORD3,
in float3 inLightDir: TEXCOORD4 ) : COLOR0
{
// shadows
float fDistance = distance ( inWorld.xyz, vecSkill1.xyz );
float3 inDir = inWorld.xyz - vecSkill1.xyz;
float Depth = texCUBE ( CubeSampler, inDir ).r;
float fShadow = Depth < fDistance * fDepthOffset ? fDark : fBright;
// light influence
float fRadiance = max ( vecSkill1.w - fDistance, 0 ) / vecSkill1.w;
// specular term
float4 NormalTex = tex2D(NormalSampler, inTex);
float3 bumpNormal = NormalTex.rgb * 2 - 1;
float3 fReflect = normalize ( 2 * dot ( bumpNormal, inLightDir ) * bumpNormal - inLightDir );
float3 fSpecular = saturate ( dot ( fReflect, inViewDir ) ) * NormalTex.a;
// simple diffuse
float fDiffuse = saturate ( dot ( normalize ( -inDir ), inNormal ) );
// final color
float4 Color = tex2D ( TexSampler, inTex );
Color.rgb *= vecSkill5.xyz * ( ( fDiffuse * fShadow ) + fSpecular ) * fRadiance;
return Color;
}
technique OmniShadow
{
pass p0
{
ZWriteEnable = True;
AlphaBlendEnable = True;
AlphaTestEnable = True;
AlphaFunc = Greater;
VertexShader = compile vs_2_0 OmniShadowVS();
PixelShader = compile ps_2_0 OmniShadowPS();
}
}
Hope it helps, salud! EDITED____________ ominishadows.zip
Last edited by txesmi; 06/22/12 06:56. Reason: link added
|
|
|
|