Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DynamicLightShadowProcessor.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 
4 using System;
5 using System.Collections.Generic;
6 using System.Text;
7 
8 using SiliconStudio.Core;
9 using SiliconStudio.Paradox.DataModel;
10 using SiliconStudio.Paradox.Engine;
11 using SiliconStudio.Paradox.EntityModel;
12 using SiliconStudio.Paradox.Games;
13 using SiliconStudio.Paradox.Graphics;
14 
15 namespace SiliconStudio.Paradox.Effects.Modules.Processors
16 {
17  /// <summary>
18  /// A class allocating as many shadow map as possible without any predefined memory budget.
19  /// </summary>
21  {
22  #region Private members
23 
24  private readonly Dictionary<ShadowMapTexture, List<ShadowMap>> texturesDefault;
25 
26  private readonly Dictionary<ShadowMapTexture, List<ShadowMap>> texturesVsm;
27 
28  #endregion
29 
30  #region Constructor
31 
32  public DynamicLightShadowProcessor(GraphicsDevice device, bool manageShadows)
33  : base(device, manageShadows)
34  {
35  texturesDefault = new Dictionary<ShadowMapTexture, List<ShadowMap>>();
36  texturesVsm = new Dictionary<ShadowMapTexture, List<ShadowMap>>();
37  }
38 
39  #endregion
40 
41  #region Public methods
42 
43  /// <inheritdoc/>
44  public override void Update(GameTime time)
45  {
46  base.Update(time);
47  if (ManageShadows)
48  {
49  InternalActiveShadowMaps.Clear();
50  InternalActiveShadowMapTextures.Clear();
51 
52  foreach (var light in Lights)
53  {
54  // create new shadow maps
55  if (light.Value.Light.ShadowMap && light.Value.ShadowMap == null)
56  CreateShadowMap(light.Value);
57 
58  // TODO: handle shadow maps that does no require to be updated like static shadow maps.
59  // update shadow maps info
60  if (light.Value.Light.Enabled && light.Value.Light.ShadowMap && light.Value.ShadowMap != null && light.Value.ShadowMap.Update)
61  {
62  UpdateEntityLightShadow(light.Value);
63  InternalActiveShadowMaps.Add(light.Value.ShadowMap);
64  InternalActiveShadowMapTextures.Add(light.Value.ShadowMap.Texture);
65  }
66  }
67  }
68  }
69 
70  #endregion
71 
72  #region Protected methods
73 
74  /// <inheritdoc/>
75  protected override void OnEntityRemoved(Entity entity, EntityLightShadow data)
76  {
77  if (ManageShadows && data.ShadowMap != null)
78  {
79  InternalShadowMaps.Remove(data.ShadowMap);
80 
81  List<ShadowMap> shadowMaps = null;
82  if (!texturesDefault.TryGetValue(data.ShadowMap.Texture, out shadowMaps))
83  texturesVsm.TryGetValue(data.ShadowMap.Texture, out shadowMaps);
84 
85  if (shadowMaps == null)
86  throw new Exception("Untracked shadow map texture");
87 
88  shadowMaps.Remove(data.ShadowMap);
89 
90  // if no more shadow maps on this texture, delete it.
91  if (shadowMaps.Count == 0)
92  {
93  InternalShadowMapTextures.Remove(data.ShadowMap.Texture);
94  Utilities.Dispose(ref data.ShadowMap.Texture.ShadowMapDepthBuffer);
95  Utilities.Dispose(ref data.ShadowMap.Texture.ShadowMapDepthTexture);
96  Utilities.Dispose(ref data.ShadowMap.Texture.ShadowMapRenderTarget);
97  Utilities.Dispose(ref data.ShadowMap.Texture.ShadowMapTargetTexture);
98  Utilities.Dispose(ref data.ShadowMap.Texture.IntermediateBlurRenderTarget);
99  Utilities.Dispose(ref data.ShadowMap.Texture.IntermediateBlurTexture);
100 
101  if (!texturesDefault.Remove(data.ShadowMap.Texture))
102  texturesVsm.Remove(data.ShadowMap.Texture);
103  }
104  }
105  base.OnEntityRemoved(entity, data);
106  }
107 
108  protected override void CreateShadowMap(EntityLightShadow light)
109  {
110  // create the shadow map
111  var shadowMap = new ShadowMap
112  {
113  LightDirection = light.Light.LightDirection,
114  LightPosition = light.Entity.Transformation.Translation,
115  ShadowMapSize = light.Light.ShadowMapMaxSize,
116  ShadowNearDistance = light.Light.ShadowNearDistance,
117  ShadowFarDistance = light.Light.ShadowFarDistance,
118  CascadeCount = light.Light.Type == LightType.Directional ? light.Light.ShadowMapCascadeCount : 1, // cascades are only supported for directional shadow maps
119  LightType = light.Light.Type,
120  Fov = light.Light.SpotFieldAngle,
122  Layers = light.Light.Layers
123  };
124 
125  // find or create the shadow map texture
126  ShadowMapTexture chosenTexture = null;
127  chosenTexture = AllocateOrChooseTexture(shadowMap, light.Light.ShadowMapFilterType == ShadowMapFilterType.Variance ? texturesVsm : texturesDefault);
128 
129  shadowMap.Texture = chosenTexture;
130  InternalShadowMaps.Add(shadowMap);
131  light.ShadowMap = shadowMap;
132  }
133 
134  #endregion
135 
136  #region Private methods
137 
138  private ShadowMapTexture AllocateOrChooseTexture(ShadowMap newShadowMap, Dictionary<ShadowMapTexture, List<ShadowMap>> shadowMapTextures)
139  {
140  ShadowMapTexture chosenTexture = null;
141 
142  // find best texture
143  foreach (var shadowMapTexture in shadowMapTextures)
144  {
145  var shadowTexture = shadowMapTexture.Key;
146  var shadowMaps = shadowMapTexture.Value;
147 
148  shadowTexture.GuillotinePacker.Clear(shadowTexture.ShadowMapDepthTexture.Width, shadowTexture.ShadowMapDepthTexture.Height);
149 
150  var useShadowTexture = true;
151  for (var i = 0; i < shadowMaps.Count && useShadowTexture; ++i)
152  useShadowTexture = shadowTexture.GuillotinePacker.TryInsert(shadowMaps[i].ShadowMapSize, shadowMaps[i].ShadowMapSize, shadowMaps[i].CascadeCount);
153 
154  useShadowTexture = useShadowTexture && shadowTexture.GuillotinePacker.TryInsert(newShadowMap.ShadowMapSize, newShadowMap.ShadowMapSize, newShadowMap.CascadeCount);
155 
156  shadowTexture.GuillotinePacker.Clear();
157 
158  if (useShadowTexture)
159  {
160  chosenTexture = shadowMapTexture.Key;
161  break;
162  }
163  }
164 
165  if (chosenTexture == null)
166  {
167  // allocate a new texture
168  chosenTexture = new ShadowMapTexture(GraphicsDevice, newShadowMap.Filter, 2048);
169  chosenTexture.GuillotinePacker.Clear(chosenTexture.ShadowMapDepthTexture.Width, chosenTexture.ShadowMapDepthTexture.Height);
170 
171  // TODO: choose texture size based on the shadow map. For now throw exception
172  if (!chosenTexture.GuillotinePacker.TryInsert(newShadowMap.ShadowMapSize, newShadowMap.ShadowMapSize, newShadowMap.CascadeCount))
173  {
174  var message = new StringBuilder();
175  message.AppendFormat("Unable to allocate shadow map texture. The default size (2048 x 2048) is too small for the shadow map ({0} cascade(s) with size {1}).", newShadowMap.CascadeCount, newShadowMap.ShadowMapSize);
176  throw new Exception(message.ToString());
177  }
178 
179  chosenTexture.GuillotinePacker.Clear();
180 
181  InternalShadowMapTextures.Add(chosenTexture);
182  var shadowMaps = new List<ShadowMap> { newShadowMap };
183  shadowMapTextures.Add(chosenTexture, shadowMaps);
184  }
185  else
186  {
187  shadowMapTextures[chosenTexture].Add(newShadowMap);
188  }
189 
190  return chosenTexture;
191  }
192 
193  #endregion
194  }
195 }
ShadowMapTexture Texture
The shadow map texture.
Definition: ShadowMap.cs:80
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
Represents a shadow map for the ShadowMapRenderer.
Definition: ShadowMap.cs:15
ShadowMapFilterType Filter
The shadow map filter.
Definition: ShadowMap.cs:75
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
Current timing used for variable-step (real time) or fixed-step (game time) games.
Definition: GameTime.cs:31
int CascadeCount
The number of shadow map cascades.
Definition: ShadowMap.cs:65
ShadowMapFilterType ShadowMapFilterType
Gets or sets the shadow map filtering.
Represents a texture to use with ShadowMapRenderer.
A class allocating as many shadow map as possible without any predefined memory budget.