Advertisement
Guest User

Untitled

a guest
May 5th, 2012
3,096
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.41 KB | None | 0 0
  1. [CODE]
  2. using System;
  3. using Microsoft.Xna.Framework;
  4. using Microsoft.Xna.Framework.Content;
  5. using Microsoft.Xna.Framework.Graphics;
  6. using Microsoft.Xna.Framework.Input;
  7. namespace Craft
  8. {
  9. public class CascadedShadowMap
  10. {
  11.   static SpriteBatch spriteBatch = Engine.SpriteBatch;
  12.   static int width = Engine.BackBufferWidth;
  13.   static int height = Engine.BackBufferHeight;
  14.   const int SHADOW_RESOLUTION = 1024;
  15.   const int SPLITS = 4;
  16.   static Effect depthEffect = Engine.Game.Content.Load<Effect>("Effects\\Shadows\\Depth");
  17.   static Effect depthLightEffect = Engine.Game.Content.Load<Effect>("Effects\\Shadows\\DepthLight");
  18.   static Effect shadowMapEffect = Engine.Game.Content.Load<Effect>("Effects\\Shadows\\ShadowMap");
  19.   static RenderTarget2D depthTexture = new RenderTarget2D(Engine.Graphics.GraphicsDevice, width, height, false, SurfaceFormat.Rg32, DepthFormat.Depth24);
  20.   static RenderTarget2D shadowMap = new RenderTarget2D(Engine.Graphics.GraphicsDevice, SHADOW_RESOLUTION * SPLITS, SHADOW_RESOLUTION, false, SurfaceFormat.Rg32, DepthFormat.Depth24);
  21.   static RenderTarget2D shadowOcclusion = new RenderTarget2D(Engine.Graphics.GraphicsDevice, width, height, false, SurfaceFormat.Color, DepthFormat.Depth24);
  22.   static Viewport splitViewport = new Viewport();
  23.   static Vector3[] frustumCornersVS = new Vector3[8];
  24.   static Vector3[] frustumCornersWS = new Vector3[8];
  25.   static Vector3[] frustumCornersLS = new Vector3[8];
  26.   static Vector3[] farFrustumCornersVS = new Vector3[4];
  27.   static Vector3[] splitFrustumCornersVS = new Vector3[8];
  28.   static OrthographicCamera[] lightCameras = new OrthographicCamera[SPLITS];
  29.   static Matrix[] lightViewProjectionMatrices = new Matrix[SPLITS];
  30.   static Vector2[] lightClipPlanes = new Vector2[SPLITS];
  31.   static float[] splitDepths = new float[SPLITS + 1];
  32.   const float nearClipOffset = 175.0f;
  33.   static bool showCascadeSplits = false;
  34.   static bool toggleJitter = true;
  35.   static Vector3 lightDirection = new Vector3(-1, -1, -1);
  36.   #region Properties
  37.   public static RenderTarget2D ShadowOcclusion
  38.   {
  39.    get { return shadowOcclusion; }
  40.    set { shadowOcclusion = value; }
  41.   }
  42.   public static bool ShowCascadeSplits
  43.   {
  44.    get { return showCascadeSplits; }
  45.    set { showCascadeSplits = value; }
  46.   }
  47.   public static Vector3 LightDirection
  48.   {
  49.    get { return lightDirection; }
  50.    set { lightDirection = value; }
  51.   }
  52.   #endregion
  53.   public static void Initialize()
  54.   {
  55.    shadowMapEffect.Parameters["ScreenResolutionSize"].SetValue(new Vector2(width, height));
  56.    shadowMapEffect.Parameters["ShadowMapSize"].SetValue(new Vector2(shadowMap.Width, shadowMap.Height));
  57.    depthEffect.Parameters["FarPlane"].SetValue(Camera.FarPlaneDistance);
  58.    splitViewport.MinDepth = 0;
  59.    splitViewport.MaxDepth = 1;
  60.    splitViewport.Width = SHADOW_RESOLUTION;
  61.    splitViewport.Height = SHADOW_RESOLUTION;
  62.    splitViewport.Y = 0;
  63.   }
  64.   private static void Render()
  65.   {
  66.    // Set our targets
  67.    Engine.Graphics.GraphicsDevice.SetRenderTarget(shadowMap);
  68.    Engine.Graphics.GraphicsDevice.Clear(ClearOptions.Target, Color.White, 1.0f, 0);
  69.    // Get corners of the main camera's bounding frustum
  70.    Matrix viewMatrix = Camera.View;
  71.    Camera.BoundingFrustum.GetCorners(frustumCornersWS);
  72.    Vector3.Transform(frustumCornersWS, ref viewMatrix, frustumCornersVS);
  73.    for (int i = 0; i < 4; i++)
  74.    {
  75.     farFrustumCornersVS[i] = frustumCornersVS[i + 4];
  76.    }
  77.    // Calculate the cascade splits.  We calculate these so that each successive
  78.    // split is larger than the previous, giving the closest split the most amount
  79.    // of shadow detail.
  80.    float N = SPLITS;
  81.    float near = 1, far = Camera.FarPlaneDistance;
  82.    splitDepths[0] = near;
  83.    splitDepths[SPLITS] = far;
  84.    const float splitConstant = 0.95f; //0.95f
  85.    for (int i = 1; i < splitDepths.Length - 1; i++)
  86.    {
  87.     splitDepths[i] = splitConstant * near * (float)Math.Pow(far / near, i / N) + (1.0f - splitConstant) * ((near + (i / N)) * (far - near));
  88.    }
  89.    // Render our scene geometry to each split of the cascade
  90.    for (int i = 0; i < SPLITS; i++)
  91.    {
  92.     float minZ = splitDepths[i];
  93.     float maxZ = splitDepths[i + 1];
  94.     lightCameras[i] = CalculateFrustum(minZ, maxZ);
  95.     RenderShadowMap(i);
  96.    }
  97.    RenderShadowOcclusion();
  98.   }
  99.   protected static OrthographicCamera CalculateFrustum(float minZ, float maxZ)
  100.   {
  101.    // Shorten the view frustum according to the shadow view distance
  102.    Matrix cameraMatrix = Camera.InverseView;
  103.    for (int i = 0; i < 4; i++)
  104.     splitFrustumCornersVS[i] = frustumCornersVS[i + 4] * (minZ / Camera.FarPlaneDistance);
  105.    for (int i = 4; i < 8; i++)
  106.     splitFrustumCornersVS[i] = frustumCornersVS[i] * (maxZ / Camera.FarPlaneDistance);
  107.    Vector3.Transform(splitFrustumCornersVS, ref cameraMatrix, frustumCornersWS);
  108.    // Position the shadow-caster camera so that it's looking at the centroid,
  109.    // and backed up in the direction of the sunlight
  110.    Matrix viewMatrix = Matrix.CreateLookAt(Vector3.Zero - (lightDirection), Vector3.Zero, new Vector3(0, 1, 0));
  111.    // Determine the position of the frustum corners in light space
  112.    Vector3.Transform(frustumCornersWS, ref viewMatrix, frustumCornersLS);
  113.    // Calculate an orthographic projection by sizing a bounding box
  114.    // to the frustum coordinates in light space
  115.    Vector3 mins = frustumCornersLS[0];
  116.    Vector3 maxes = frustumCornersLS[0];
  117.    for (int i = 0; i < 8; i++)
  118.    {
  119.     if (frustumCornersLS[i].X > maxes.X)
  120.      maxes.X = frustumCornersLS[i].X;
  121.     else if (frustumCornersLS[i].X < mins.X)
  122.      mins.X = frustumCornersLS[i].X;
  123.     if (frustumCornersLS[i].Y > maxes.Y)
  124.      maxes.Y = frustumCornersLS[i].Y;
  125.     else if (frustumCornersLS[i].Y < mins.Y)
  126.      mins.Y = frustumCornersLS[i].Y;
  127.     if (frustumCornersLS[i].Z > maxes.Z)
  128.      maxes.Z = frustumCornersLS[i].Z;
  129.     else if (frustumCornersLS[i].Z < mins.Z)
  130.      mins.Z = frustumCornersLS[i].Z;
  131.    }
  132.    if (toggleJitter)
  133.    {
  134.     // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter.
  135.     // This is a matter of integer dividing by the world space size of a texel
  136.     float diagonalLength = (frustumCornersWS[0] - frustumCornersWS[6]).Length();
  137.     diagonalLength += 2;    //Without this, the shadow map isn't big enough in the world.
  138.     float worldsUnitsPerTexel = diagonalLength / (float)SHADOW_RESOLUTION;
  139.     Vector3 borderOffset = (new Vector3(diagonalLength, diagonalLength, diagonalLength) - (maxes - mins)) * 0.5f;
  140.     maxes += borderOffset;
  141.     mins -= borderOffset;
  142.     mins /= worldsUnitsPerTexel;
  143.     mins.X = (float)Math.Floor(mins.X);
  144.     mins.Y = (float)Math.Floor(mins.Y);
  145.     mins.Z = (float)Math.Floor(mins.Z);
  146.     mins *= worldsUnitsPerTexel;
  147.     maxes /= worldsUnitsPerTexel;
  148.     maxes.X = (float)Math.Floor(maxes.X);
  149.     maxes.Y = (float)Math.Floor(maxes.Y);
  150.     maxes.Z = (float)Math.Floor(maxes.Z);
  151.     maxes *= worldsUnitsPerTexel;
  152.    }
  153.    OrthographicCamera lightCamera = new OrthographicCamera(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - nearClipOffset, -mins.Z);
  154.    lightCamera.SetViewMatrix(ref viewMatrix);
  155.    return lightCamera;
  156.   }
  157.   private static void RenderShadowMap(int splitIndex)
  158.   {
  159.    splitViewport.X = splitIndex * SHADOW_RESOLUTION;
  160.    Engine.Graphics.GraphicsDevice.Viewport = splitViewport;
  161.    depthLightEffect.CurrentTechnique = depthLightEffect.Techniques["Depth"];
  162.    depthLightEffect.Parameters["ViewProjection"].SetValue(lightCameras[splitIndex].ViewProjectionMatrix);
  163.    BlockRender.Draw(depthLightEffect, lightCameras[splitIndex].BoundingFrustum);
  164.   }
  165.   /// <summary>
  166.   /// Renders a texture containing the final shadow occlusion
  167.   /// </summary>
  168.   private static void RenderShadowOcclusion()
  169.   {
  170.    Engine.Graphics.GraphicsDevice.SetRenderTarget(shadowOcclusion);
  171.    Engine.Graphics.GraphicsDevice.Clear(ClearOptions.Target, Color.White, 1.0f, 0);
  172.    // We'll use these clip planes to determine which split a pixel belongs to
  173.    for (int i = 0; i < SPLITS; i++)
  174.    {
  175.     lightClipPlanes[i].X = -splitDepths[i];
  176.     lightClipPlanes[i].Y = -splitDepths[i + 1];
  177.     lightCameras[i].GetViewProjMatrix(out lightViewProjectionMatrices[i]);
  178.    }
  179.    shadowMapEffect.Parameters["ViewProjection"].SetValue(Camera.ViewProjection);
  180.    shadowMapEffect.Parameters["InverseView"].SetValue(Camera.InverseView);
  181.    shadowMapEffect.Parameters["LightViewProjection"].SetValue(lightViewProjectionMatrices);
  182.    shadowMapEffect.Parameters["FrustumCornersVS"].SetValue(farFrustumCornersVS);
  183.    shadowMapEffect.Parameters["ClipPlanes"].SetValue(lightClipPlanes);
  184.    shadowMapEffect.Parameters["ShadowMap"].SetValue(shadowMap);
  185.    shadowMapEffect.Parameters["DepthTexture"].SetValue(depthTexture);
  186.    shadowMapEffect.Parameters["ShowSplitColors"].SetValue(showCascadeSplits);
  187.    shadowMapEffect.CurrentTechnique.Passes[0].Apply();
  188.    DeferredRenderer.FullScreenQuad.Draw();
  189.   }
  190.   private static void CreateDepthTexture()
  191.   {
  192.    Engine.Graphics.GraphicsDevice.SetRenderTarget(depthTexture);
  193.    Engine.Graphics.GraphicsDevice.Clear(ClearOptions.Target, Color.White, 1.0f, 0);
  194.    depthEffect.Parameters["ViewProjection"].SetValue(Camera.ViewProjection);
  195.    BlockRender.Draw(depthEffect);
  196.    Engine.Graphics.GraphicsDevice.SetRenderTarget(null);
  197.   }
  198.   public static void Draw()
  199.   {
  200.    CreateDepthTexture();
  201.    Render();
  202.    //Blur.BlurShadow(Blur.shadowBlurTarg, shadowOcclusion, 0);
  203.    //Blur.BlurShadow(shadowOcclusion, Blur.shadowBlurTarg, 1);
  204.   }
  205.   /// <summary>
  206.   /// Draw the render targets to screen
  207.   /// </summary>
  208.   public static void DrawRenderTargets()
  209.   {
  210.    spriteBatch.Begin(0, BlendState.Opaque, SamplerState.PointClamp, null, null);
  211.    {
  212.     spriteBatch.Draw(shadowMap, new Rectangle(0, 0, 256, 256), Color.White);
  213.     spriteBatch.Draw(depthTexture, new Rectangle(0, 256, 256, 256), Color.White);
  214.     spriteBatch.Draw(shadowOcclusion, new Rectangle(0, 512, 256, 256), Color.White);
  215.    }
  216.    spriteBatch.End();
  217.   }
  218.   public static void HandleInput(GameTime gameTime, InputState inputState)
  219.   {
  220.    if (inputState.IsTriggered(Action.ToggleCascadeSplits)) //F7
  221.    {
  222.     showCascadeSplits = !showCascadeSplits;
  223.    }
  224.    if (inputState.IsTriggered(Action.ToggleJitter)) //J
  225.    {
  226.     toggleJitter = !toggleJitter;
  227.    }
  228.   }
  229. }
  230. }
  231. [/CODE]
  232.  
  233. [CODE]
  234. float4x4 World;
  235. float4x4 ViewProjection;
  236. float4x4 InverseView;
  237. static const int SPLITS = 4;
  238. float4x4 LightViewProjection [SPLITS];
  239. float2 ClipPlanes[SPLITS];
  240. float2 ShadowMapSize;
  241. float2 ScreenResolutionSize;
  242. float3 FrustumCornersVS [4];
  243. bool  ShowSplitColors = false;
  244. static const float SHADOW_BIAS = 0.01f;
  245. static const float DARKEN_FACTOR = 100.0f;
  246. texture DepthTexture;
  247. sampler DepthTextureSampler = sampler_state
  248. {
  249. Texture = <DepthTexture>;
  250. MinFilter = Point;
  251. MagFilter = Point;
  252. MipFilter = None;
  253. };
  254. texture ShadowMap;
  255. sampler ShadowMapSampler = sampler_state
  256. {
  257. Texture = <ShadowMap>;
  258. MinFilter = Point;
  259. MagFilter = Point;
  260. MipFilter = None;
  261. };
  262. float2 sampleShadowMap(float2 UV)
  263. {
  264. if (UV.x < 0 || UV.x > 1 || UV.y < 0 || UV.y > 1)
  265. {
  266.   return float2(1, 1);
  267. }
  268. return tex2D(ShadowMapSampler, UV).rg;
  269. }
  270. struct VertexShaderInput
  271. {
  272. float4 Position : POSITION;
  273. float3 TexCoordAndCornerIndex : TEXCOORD0;
  274. };
  275. struct VertexShaderOutput
  276. {
  277. float4 Position : POSITION;
  278. float2 TexCoord : TEXCOORD0;
  279. float3 FrustumCornerVS : TEXCOORD1;
  280. };
  281. // Vertex shader for rendering the full-screen quad used for calculating
  282. // the shadow occlusion factor.
  283. VertexShaderOutput VertexShaderFunction (VertexShaderInput input)
  284. {
  285. VertexShaderOutput output;
  286. // Offset the position by half a pixel to correctly align texels to pixels
  287. output.Position.x = input.Position.x - (1.0f / ScreenResolutionSize.x);
  288. output.Position.y = input.Position.y + (1.0f / ScreenResolutionSize.y);
  289. output.Position.z = input.Position.z;
  290. output.Position.w = 1.0f;
  291.  
  292. // Pass along the texture coordiante and the position of the frustum corner
  293. output.TexCoord = input.TexCoordAndCornerIndex.xy;
  294. output.FrustumCornerVS = FrustumCornersVS[input.TexCoordAndCornerIndex.z];
  295. return output;
  296. }
  297. // Pixel shader for computing the shadow occlusion factor
  298. float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
  299. {
  300. // Reconstruct view-space position from the depth buffer
  301. float pixelDepth = tex2D(DepthTextureSampler, input.TexCoord).r;
  302. float4 position = float4(pixelDepth * input.FrustumCornerVS, 1.0f);
  303. // Figure out which split this pixel belongs to, based on view-space depth.
  304. float4x4 lightViewProjection = LightViewProjection[0];
  305. float offset = 0;
  306.  
  307. float3 splitColors [4];
  308. splitColors[0] = float3(1, 0, 0);
  309. splitColors[1] = float3(0, 1, 0);
  310. splitColors[2] = float3(0, 0, 1);
  311. splitColors[3] = float3(1, 1, 0);
  312. float3 color = splitColors[0];
  313. int currentSplit = 0;
  314. for (int i = 1; i < SPLITS; i++)
  315. {
  316.   if (position.z <= ClipPlanes[i].x && position.z > ClipPlanes[i].y)
  317.   {
  318.    lightViewProjection = LightViewProjection[i];
  319.    offset = i / (float)SPLITS;
  320.    color = splitColors[i];
  321.    currentSplit = i;
  322.   }
  323. }
  324.  
  325. // Determine the depth of the pixel with respect to the light
  326. float4x4 inverseLVP = mul(InverseView, lightViewProjection);
  327. float4 positionLight = mul(position, inverseLVP);
  328.  
  329. float lightDepth = (positionLight.z / positionLight.w) - SHADOW_BIAS;
  330.  
  331. // Transform from light space to shadow map texture space.
  332. float2 shadowTexCoord = 0.5 * positionLight.xy / positionLight.w + float2(0.5f, 0.5f);
  333. shadowTexCoord.x = shadowTexCoord.x / SPLITS + offset;
  334. shadowTexCoord.y = 1.0f - shadowTexCoord.y;
  335.      
  336. // Offset the coordinate by half a texel so we sample it correctly
  337. shadowTexCoord += (0.5f / ShadowMapSize);
  338. float shadow = 1;
  339. lightDepth += 0.01f;
  340.  
  341. if (lightDepth < 1)
  342. {
  343.   float2 shadowMap = sampleShadowMap(shadowTexCoord);
  344.   //// Check if we're in shadow
  345.   //float lit_factor = (lightDepth < shadowMap.x);
  346.   //// Variance shadow mapping
  347.   //float E_x2 = shadowMap.y;
  348.   //float Ex_2 = shadowMap.x * shadowMap.x;
  349.   //float variance = min(max(E_x2 - Ex_2, 0.0) + 1.0f / 2000, 1);
  350.   //float m_d = (shadowMap.x - lightDepth);
  351.   //float p = variance / (variance + m_d * m_d);
  352.   //shadow = clamp(max(lit_factor, p), 0.1, 1.0f);
  353.   //Calculate the Shadow Factor
  354.   float shadowFactor = exp((DARKEN_FACTOR * 0.5f) * (shadowMap - lightDepth));
  355.   shadowFactor = clamp(shadowFactor, 0.45, 1.0);
  356.   shadow = shadowFactor;
  357. }
  358. if (!ShowSplitColors)
  359.   return shadow;
  360. else
  361.   return float4(shadow + color, 1);
  362. }
  363. technique Shadow
  364. {
  365.     pass p0
  366.     {
  367.         VertexShader = compile vs_3_0 VertexShaderFunction();
  368.         PixelShader = compile ps_3_0 PixelShaderFunction();
  369.     }
  370. }
  371.  
  372. [/CODE]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement