1
\$\begingroup\$

I recently added "Shadow Mapping" in my XNA games to include shadows. I followed the nice and famous tutorial from "Riemers" : http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series3/Shadow_map.php .

This code work nice and I can see my source of light and shadow. But the problem is that my light source does not match the field of view that I created. I want the light covers the entire map of my game. I don't know why , but the light only affect 2-3 cubes of my map.

ScreenShot: (the emission of light illuminates only 2-3 blocks and not the full map) enter image description here

Here is my code i create the fieldOfView for LightviewProjection Matrix:

Vector3 lightDir = new Vector3(10, 52, 10);
Vector3 lightPos = new Vector3(2, 52, 2);
Matrix lightsView = Matrix.CreateLookAt(lightPos, lightDir ,new Vector3(0, 1, 0));
Matrix lightsProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, 1f, 20f, 1000f);
lightsViewProjectionMatrix = lightsView * lightsProjection;

As you can see , my nearPlane and FarPlane are set to 20f and 100f . So i don't know why the light stop after 2 cubes. it's should be bigger

Here is set the value to my custom effect HLSL in the shader file

    /* SHADOW VALUE */

    effectWorld.Parameters["LightDirection"].SetValue(lightDir);
    effectWorld.Parameters["xLightsWorldViewProjection"].SetValue(Matrix.Identity * .lightsViewProjectionMatrix);
    effectWorld.Parameters["xWorldViewProjection"].SetValue(Matrix.Identity * arcadia.camera.View * arcadia.camera.Projection);
    effectWorld.Parameters["xLightPower"].SetValue(1f);
    effectWorld.Parameters["xAmbient"].SetValue(0.3f);

Here is my custom HLSL shader effect file "*.fx"

    // This sample uses a simple Lambert lighting model.
float3 LightDirection = normalize(float3(-1, -1, -1));
float3 DiffuseLight = 1.25;
float3 AmbientLight = 0.25;
uniform const float3    DiffuseColor = 1;
uniform const float     Alpha = 1;
uniform const float3    EmissiveColor  = 0;
uniform const float3    SpecularColor = 1;
uniform const float     SpecularPower = 16;
uniform const float3    EyePosition;
// FOG attribut
uniform const float     FogEnabled  ;
uniform const float     FogStart ;
uniform const float     FogEnd ;
uniform const float3    FogColor ;
float3 cameraPos : CAMERAPOS;

texture Texture;

sampler Sampler = sampler_state
{
    Texture = (Texture);
    magfilter = LINEAR; 
    minfilter = LINEAR; 
    mipfilter = LINEAR; 
    AddressU = mirror; 
    AddressV = mirror;

};
texture xShadowMap;
sampler ShadowMapSampler = sampler_state 
{ 
    Texture = <xShadowMap>; 
    magfilter = LINEAR; 
    minfilter = LINEAR; 
    mipfilter = LINEAR; 
    AddressU = clamp; 
    AddressV = clamp; 
};

/* *************** */
/* SHADOW MAP CODE */
/* *************** */
struct SMapVertexToPixel
{
    float4 Position     : POSITION;
    float4 Position2D    : TEXCOORD0;
};

struct SMapPixelToFrame
{
    float4 Color : COLOR0;
};
struct SSceneVertexToPixel
{
    float4 Position             : POSITION;
    float4 Pos2DAsSeenByLight    : TEXCOORD0;

    float2 TexCoords            : TEXCOORD1;
    float3 Normal                : TEXCOORD2;
    float4 Position3D            : TEXCOORD3;

};

struct SScenePixelToFrame
{
    float4 Color : COLOR0;
};
float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
{
    float3 lightDir = normalize(pos3D - lightPos);
        return dot(-lightDir, normal);
}

SSceneVertexToPixel ShadowedSceneVertexShader(float4 inPos : POSITION, float2 inTexCoords : TEXCOORD0, float3 inNormal : NORMAL)
{
    SSceneVertexToPixel Output = (SSceneVertexToPixel)0;

    Output.Position = mul(inPos, xWorldViewProjection);
    Output.Pos2DAsSeenByLight = mul(inPos, xLightsWorldViewProjection);
    Output.Normal = normalize(mul(inNormal, (float3x3)World));
    Output.Position3D = mul(inPos, World);
    Output.TexCoords = inTexCoords;

    return Output;
}

SScenePixelToFrame ShadowedScenePixelShader(SSceneVertexToPixel PSIn)
{
    SScenePixelToFrame Output = (SScenePixelToFrame)0;

    float2 ProjectedTexCoords;
    ProjectedTexCoords[0] = PSIn.Pos2DAsSeenByLight.x / PSIn.Pos2DAsSeenByLight.w / 2.0f + 0.5f;
    ProjectedTexCoords[1] = -PSIn.Pos2DAsSeenByLight.y / PSIn.Pos2DAsSeenByLight.w / 2.0f + 0.5f;

    float diffuseLightingFactor = 0;
    if ((saturate(ProjectedTexCoords).x == ProjectedTexCoords.x) && (saturate(ProjectedTexCoords).y == ProjectedTexCoords.y))
    {
        float depthStoredInShadowMap = tex2D(ShadowMapSampler, ProjectedTexCoords).r;
        float realDistance = PSIn.Pos2DAsSeenByLight.z / PSIn.Pos2DAsSeenByLight.w;
        if ((realDistance - 1.0f / 100.0f) <= depthStoredInShadowMap)
        {
            diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, PSIn.Normal);
            diffuseLightingFactor = saturate(diffuseLightingFactor);
            diffuseLightingFactor *= xLightPower;
        }
    }

    float4 baseColor = tex2D(Sampler, PSIn.TexCoords);
        Output.Color = baseColor*(diffuseLightingFactor + xAmbient);

    return Output;
}

SMapVertexToPixel ShadowMapVertexShader(float4 inPos : POSITION)
{
    SMapVertexToPixel Output = (SMapVertexToPixel)0;

    Output.Position = mul(inPos, xLightsWorldViewProjection);
    Output.Position2D = Output.Position;

    return Output;
}

SMapPixelToFrame ShadowMapPixelShader(SMapVertexToPixel PSIn)
{
    SMapPixelToFrame Output = (SMapPixelToFrame)0;

    Output.Color = PSIn.Position2D.z / PSIn.Position2D.w;

    return Output;
}

/* ******************* */
/* END SHADOW MAP CODE */
/* ******************* */

/ For rendering without instancing.
technique ShadowMap
{

    pass Pass0
    {
        VertexShader = compile vs_2_0 ShadowMapVertexShader();
        PixelShader = compile ps_2_0 ShadowMapPixelShader();

    }
}

technique ShadowedScene
{
    /*
    pass Pass0
    {
        VertexShader = compile vs_2_0 VSBasicTx();
        PixelShader = compile ps_2_0 PSBasicTx();
    }
    */
    pass Pass1
    {
        VertexShader = compile vs_2_0 ShadowedSceneVertexShader();
        PixelShader = compile ps_2_0 ShadowedScenePixelShader();
    }

}
technique SimpleFog
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 VSBasicTx();
        PixelShader = compile ps_2_0 PSBasicTx();
    }
}

Draw Function:

public void Draw(GameTime gameTime)
    {


        GraphicsDevice.SetRenderTarget(shadowMapRender);
        GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Microsoft.Xna.Framework.Color.Black, 1.0f, 0);

        // "ShadowMap" as technique param
        DrawWorld("ShadowMap");

        GraphicsDevice.SetRenderTarget(null);
        shadowMap = (Texture2D)shadowMapRender;
        GraphicsDevice.SetRenderTarget(null);


        GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Microsoft.Xna.Framework.Color.Black, 1.0f, 0);

        // "ShadowedScene" as technique param
        DrawWorld("ShadowedScene");

        shadowMap = null;
    }

I edited my fx file , for show you only information and functions about the shadow ;-)

UPDATE : i tried with an orthagraphic matrix as we advice me, but still not work. i can no see the light and shadow

Vector3 lightDir = new Vector3(10, 52, 10);
Vector3 lightPos = new Vector3(2, 52, 2);

Matrix lightViewMatrix = Matrix.CreateLookAt(lightPos, lightDir, Vector3.Up); 

float minX = 0, maxX = 1000;
float minY = 50, maxY = 100;
float minZ = 0, maxZ = 1000;

Matrix lightProjectionMatrix = Matrix.CreateOrthographicOffCenter(minX, maxX, minY, maxY, minZ, maxZ);


lightsViewProjectionMatrix = lightViewMatrix * lightProjectionMatrix;
\$\endgroup\$
1
\$\begingroup\$

Perspective shadow maps like that are usually not used to shadow the whole scene, but for a single lamp or flashlight.
If you want to shadow the whole scene, You probably don't want to use perspestive shadow maps, but rather orthographic ones (I guess you want shadows from the sun?). When you are creating an othographic matrix (MSDN) you specify its dimensions, like a cube (because it will project everything in that cube). I guess it is easy from there to calculate its required size. It's even better for sunlight for an other reason, too, because shadows generated from that will look like they have been generated from a light source which is infinitely far away (or as far away as the sun).

If you shadow a whole scene like that, probably one shadow map will not be sufficient (or efficient), so when you got it working with one, you should look into cascaded shadow maps then.

\$\endgroup\$
  • \$\begingroup\$ Thank you so much for this quickly answer ! I tried as you advice me, to use an orthographic matrix. But still not work. Maybe i build this matrix wrong.. I added on the bottom of my description the code , how i make the orthographic matrix \$\endgroup\$ – Mehdi Bugnard Aug 22 '14 at 13:19
  • \$\begingroup\$ There could be all sorts of problems with it. You should check the rendered shadow map depth texture if it is correct first. And I think minZ should be a negative number so your projection is bigger. \$\endgroup\$ – János Turánszki Aug 22 '14 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.