Tuesday, June 30, 2015

xna - HLSL pixel inside a view (cascaded shadowmapping)



I'm figuring out shadowmapping in HLSL (see also this question). I understand that I need projection matrices for each cascading shadowmap.


I use this code to create the projections:


    Matrix CreateLightViewProjectionMatrix(LightProjectionDistance distance)
{
// Matrix with that will rotate in points the direction of the light
Matrix lightRotation = Matrix.CreateLookAt(Vector3.Zero,
-_lightDir,
Vector3.Up);

BoundingFrustum cameraFrustum = new BoundingFrustum(_view);

switch (distance)
{
case LightProjectionDistance.Close:
cameraFrustum = new BoundingFrustum(_view * _projectionClose);
break;
case LightProjectionDistance.Medium:
cameraFrustum = new BoundingFrustum(_view * _projectionMedium);
break;
case LightProjectionDistance.Far:
cameraFrustum = new BoundingFrustum(_view * _projectionFar);

break;
}

// Get the corners of the frustum
Vector3[] frustumCorners = cameraFrustum.GetCorners();

// Transform the positions of the corners into the direction of the light
for (int i = 0; i < frustumCorners.Length; i++)
{
frustumCorners[i] = Vector3.Transform(frustumCorners[i], lightRotation);

}

// Find the smallest box around the points
BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);

Vector3 boxSize = lightBox.Max - lightBox.Min;
Vector3 halfBoxSize = boxSize * 0.5f;

// The position of the light should be in the center of the back
// pannel of the box.

Vector3 lightPosition = lightBox.Min + halfBoxSize;
lightPosition.Z = lightBox.Min.Z;

// We need the position back in world coordinates so we transform
// the light position by the inverse of the lights rotation
lightPosition = Vector3.Transform(lightPosition,
Matrix.Invert(lightRotation));

// Create the view matrix for the light
Matrix lightView = Matrix.CreateLookAt(lightPosition,

lightPosition - _lightDir,
Vector3.Up);

// Create the projection matrix for the light
// The projection is orthographic since we are using a directional light
Matrix lightProjection = Matrix.CreateOrthographic(boxSize.X, boxSize.Y,
-boxSize.Z, boxSize.Z);

return lightView * lightProjection;
}


Where the view matrices are like this:


        float aspectRatio = (float)graphics.PreferredBackBufferWidth / (float)graphics.PreferredBackBufferHeight;
_projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
aspectRatio,
1f, 500.0f);
_projectionClose = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
aspectRatio,
1f, 20.0f);
_projectionMedium = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,

aspectRatio,
20.0f, 100.0f);
_projectionFar = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
aspectRatio,
100.0f, 500.0f);

In my Pixelshader I try this:


diffuse = input.Color;
float4 lightingPosition = mul(input.WorldPos, LightViewProjClose);
if (lightingPosition.x > -0.5 && lightingPosition.x<0.5 && lightingPosition.y>-0.5 && lightingPosition.y < 0.5)

{
diffuse = float4(1,0,0,1);
}

lightingPosition = mul(input.WorldPos, LightViewProjMedium);
if (lightingPosition.x > -0.5 && lightingPosition.x<0.5 && lightingPosition.y>-0.5 && lightingPosition.y < 0.5)
{
diffuse = float4(0,1,0,1);
}


lightingPosition = mul(input.WorldPos, LightViewProjFar);
if (lightingPosition.x > -0.5 && lightingPosition.x<0.5 && lightingPosition.y>-0.5 && lightingPosition.y < 0.5)
{
diffuse = float4(0,0,1,1);
}

return diffuse;

Now I expected to see the picture colored in red (close), green (medium) and blue (far) bands. However it seems only the close range is actually colored and the medium and far distances are not triggered. I did set the parameters like this:


_myEffect.Parameters["LightViewProjClose"].SetValue(CreateLightViewProjectionMatrix(LightProjectionDistance.Close));

_myEffect.Parameters["LightViewProjMedium"].SetValue(CreateLightViewProjectionMatrix(LightProjectionDistance.Medium));
_myEffect.Parameters["LightViewProjFar"].SetValue(CreateLightViewProjectionMatrix(LightProjectionDistance.Far));

I'm getting frustrated as I'm trying to figure this out for the past couple of days with almost no progress. What am I missing? How can I get the pixel shader switch between the correct light projections so it can pick the right cascaded shadowmap?


Edit, after tweaking this is my shader code:


float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 LightViewProjClose;
float4x4 LightViewProjMedium;

float4x4 LightViewProjFar;


float3 LightDirection1 = float3(-1.5, 0.45, 0);
float4 LightColor1 = float4(1, 1, 1, 1);
float3 LightDirection2 =float3(1,1,0.2);
float4 LightColor2 = float4(0.2, 0.2, 0.25, 1);


float4 AmbientColor = float4(0.15, 0.15, 0.15, 0.15);

float DepthBias = 0.001f;

texture ShadowMap;
sampler ShadowMapSampler = sampler_state
{
Texture = ;
};

struct VertexShaderInput
{

float4 Position : SV_POSITION;
float4 Normal : NORMAL0;
float4 Color : COLOR0;
};

struct ShadowVertexShaderInput
{
float4 Position : SV_POSITION;
float4 Normal : NORMAL0;
float4 Color : COLOR0;

};

struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Normal : TEXCOORD0;
float4 Color : COLOR0;
float4 WorldPos : TEXCOORD2;
};


struct CreateShadowMap_VSOut
{
float4 Position : POSITION;
float4 Color : COLOR0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;


float4x4 WorldViewProj = mul(mul(World, View), Projection);

// Transform the models verticies and normal
output.Position = mul(input.Position, WorldViewProj);
output.Normal = input.Normal;
output.Color = input.Color;

// Save the vertices postion in world space
output.WorldPos = mul(input.Position, World);


return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// Color of the model
float4 diffuseColor = input.Color;

// Intensity based on the direction of the light
float diffuseIntensity1 = clamp(dot(input.Normal.xyz, LightDirection1.xyz), 0, 1);

float diffuseIntensity2 = clamp(dot(input.Normal.xyz, LightDirection2.xyz), 0, 1);

// Final diffuse color with ambient color added
float4 diffuse = saturate((diffuseIntensity1 * LightColor1 + diffuseIntensity2 * LightColor2) * diffuseColor);

// Find the position of this pixel in light space in the close projection
float4 lightingPosition = mul(input.WorldPos, LightViewProjClose);
lightingPosition.xyz = 0.5 * lightingPosition.xyz / lightingPosition.w;
if (lightingPosition.x > -0.5 && lightingPosition.x<0.5 && lightingPosition.y>-0.5 && lightingPosition.y < 0.5)
{

lightingPosition = mul(input.WorldPos, LightViewProjClose);
// Find the position in the shadow map for this pixel
float2 ShadowTexCoord = 0.5 * lightingPosition.xy /
lightingPosition.w + float2(0.5, 0.5);
ShadowTexCoord.y = 1.0f - ShadowTexCoord.y;

// Get the current depth stored in the shadow map (red component for close)
float shadowdepth = tex2D(ShadowMapSampler, ShadowTexCoord).r;

// Calculate the current pixel depth

// The bias is used to prevent floating point errors that occur when
// the pixel of the occluder is being drawn
float ourdepth = (lightingPosition.z / lightingPosition.w) - DepthBias;

// Check to see if this pixel is in front or behind the value in the shadow map
if (shadowdepth < ourdepth)
{
// Shadow the pixel by lowering the intensity
diffuse *= float4(0.5, 0.5, 0.5, 0);


};
}

lightingPosition = mul(input.WorldPos, LightViewProjMedium);
lightingPosition.xyz = 0.5 * lightingPosition.xyz / lightingPosition.w;
if (lightingPosition.x > -0.5 && lightingPosition.x<0.5 && lightingPosition.y>-0.5 && lightingPosition.y < 0.5)
{

lightingPosition = mul(input.WorldPos, LightViewProjMedium);
// Find the position in the shadow map for this pixel

float2 ShadowTexCoord = 0.5 * lightingPosition.xy /
lightingPosition.w + float2(0.5, 0.5);
ShadowTexCoord.y = 1.0f - ShadowTexCoord.y;

// Get the current depth stored in the shadow map (green component for medium)
float shadowdepth = tex2D(ShadowMapSampler, ShadowTexCoord).g;

// Calculate the current pixel depth
// The bias is used to prevent floating point errors that occur when
// the pixel of the occluder is being drawn

float ourdepth = (lightingPosition.z / lightingPosition.w) - DepthBias;

// Check to see if this pixel is in front or behind the value in the shadow map
if (shadowdepth < ourdepth)
{
// Shadow the pixel by lowering the intensity
diffuse *= float4(0.5, 0.5, 0.5, 0);
};
}


//do the same trick using the 'far' matrix.
lightingPosition = mul(input.WorldPos, LightViewProjFar);
lightingPosition.xyz = 0.5 * lightingPosition.xyz / lightingPosition.w;
if (lightingPosition.x > -0.5 && lightingPosition.x<0.5 && lightingPosition.y>-0.5 && lightingPosition.y < 0.5)
{
lightingPosition = mul(input.WorldPos, LightViewProjFar);

// Find the position in the shadow map for this pixel
float2 ShadowTexCoord = 0.5 * lightingPosition.xy /
lightingPosition.w + float2(0.5, 0.5);

ShadowTexCoord.y = 1.0f - ShadowTexCoord.y;

// Get the current depth stored in the shadow map (blue component for far)
float shadowdepth = tex2D(ShadowMapSampler, ShadowTexCoord).b;

// Calculate the current pixel depth
// The bias is used to prevent floating point errors that occur when
// the pixel of the occluder is being drawn
float ourdepth = (lightingPosition.z / lightingPosition.w) - DepthBias;


// Check to see if this pixel is in front or behind the value in the shadow map
if (shadowdepth < ourdepth)
{
// Shadow the pixel by lowering the intensity
diffuse *= float4(0.5, 0.5, 0.5, 0);
};
//diffuse = float4(0, 0, 1, 1);
}
return diffuse;
}



CreateShadowMap_VSOut ShadowCloseVertexShaderFunction(VertexShaderInput input)
{
CreateShadowMap_VSOut output;

output.Position = mul(input.Position, mul(World, LightViewProjClose));
output.Color = float4(output.Position.z / output.Position.w,0,0,1);

return output;

}
CreateShadowMap_VSOut ShadowMediumVertexShaderFunction(VertexShaderInput input)
{
CreateShadowMap_VSOut output;

output.Position = mul(input.Position, mul(World, LightViewProjMedium));
output.Color = float4(0,output.Position.z / output.Position.w, 0, 1);

return output;
}

CreateShadowMap_VSOut ShadowFarVertexShaderFunction(VertexShaderInput input)
{
CreateShadowMap_VSOut output;

output.Position = mul(input.Position, mul(World, LightViewProjFar));
output.Color = float4(0,0,output.Position.z / output.Position.w, 1);

return output;
}


float4 ShadowPixelShaderFunction(CreateShadowMap_VSOut input) : COLOR0
{
return input.Color;
}

technique MyTechnique
{
pass Pass1
{
VertexShader = compile vs_4_0_level_9_3 VertexShaderFunction();

PixelShader = compile ps_4_0_level_9_3 PixelShaderFunction();
}
}

technique ShadowTechniqueClose
{

pass Pass1
{
VertexShader = compile vs_4_0_level_9_3 ShadowCloseVertexShaderFunction();

PixelShader = compile ps_4_0_level_9_3 ShadowPixelShaderFunction();
}
}
technique ShadowTechniqueMedium
{

pass Pass1
{
VertexShader = compile vs_4_0_level_9_3 ShadowMediumVertexShaderFunction();
PixelShader = compile ps_4_0_level_9_3 ShadowPixelShaderFunction();

}
}
technique ShadowTechniqueFar
{

pass Pass1
{
VertexShader = compile vs_4_0_level_9_3 ShadowFarVertexShaderFunction();
PixelShader = compile ps_4_0_level_9_3 ShadowPixelShaderFunction();
}

}

The "close" shadows seem to work. However the 'medium' and 'far' shadows are still not working. The result looks like this:


Close shadows look nice though


What am I doing wrong here?




No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...