Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
LightShadowProcessorWithBudget.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 
7 using SiliconStudio.Paradox.DataModel;
8 using SiliconStudio.Paradox.Engine;
9 using SiliconStudio.Paradox.EntityModel;
10 using SiliconStudio.Paradox.Games;
11 using SiliconStudio.Paradox.Graphics;
12 
13 namespace SiliconStudio.Paradox.Effects.Modules.Processors
14 {
15  /// <summary>
16  /// A class handling the allocation of shadow maps with a fixed budget of shadow map textures. This class is meant to be inherited with the desired budget since it has no texture at all.
17  /// </summary>
19  {
20  #region Private members
21 
22  private readonly List<ShadowMapTexture> shadowMapDefaultTextures;
23 
24  private readonly List<ShadowMapTexture> shadowMapVsmTextures;
25 
26  private readonly Dictionary<ShadowMapTexture, int> texturesDefault;
27 
28  private readonly Dictionary<ShadowMapTexture, int> texturesVsm;
29 
30  private readonly List<EntityLightShadow> activeLightShadowMaps;
31 
32  private bool shadowMapFullWarningDone = false;
33 
34  #endregion
35 
36  #region Constructor
37 
38  public LightShadowProcessorWithBudget(GraphicsDevice device, bool manageShadows)
39  : base(device, manageShadows)
40  {
41  shadowMapDefaultTextures = new List<ShadowMapTexture>();
42  shadowMapVsmTextures = new List<ShadowMapTexture>();
43  texturesDefault = new Dictionary<ShadowMapTexture, int>();
44  texturesVsm = new Dictionary<ShadowMapTexture, int>();
45 
46  activeLightShadowMaps = new List<EntityLightShadow>();
47  }
48 
49  #endregion
50 
51  #region Public methods
52 
53  /// <inheritdoc/>
54  public override void Update(GameTime time)
55  {
56  base.Update(time);
57  if (ManageShadows)
58  {
59  // clear the virtual allocation
60  foreach (var texture in shadowMapDefaultTextures)
61  {
62  texture.GuillotinePacker.Clear(texture.ShadowMapDepthBuffer.Texture.Width, texture.ShadowMapDepthBuffer.Texture.Height);
63  texturesDefault[texture] = texture.ShadowMapDepthBuffer.Texture.Width * texture.ShadowMapDepthBuffer.Texture.Height;
64  }
65  foreach (var texture in shadowMapVsmTextures)
66  {
67  texture.GuillotinePacker.Clear(texture.ShadowMapDepthBuffer.Texture.Width, texture.ShadowMapDepthBuffer.Texture.Height);
68  texturesVsm[texture] = texture.ShadowMapDepthBuffer.Texture.Width * texture.ShadowMapDepthBuffer.Texture.Height;
69  }
70 
71  // sort the textures based on the available size.
72  shadowMapDefaultTextures.Sort(ShadowMapTextureComparerDefault);
73  shadowMapVsmTextures.Sort(ShadowMapTextureComparerVsm);
74 
75  // create shadow maps for new lights
76  foreach (var light in Lights)
77  {
78  // create new shadow maps
79  if (light.Value.Light.ShadowMap && light.Value.ShadowMap == null)
80  CreateShadowMap(light.Value);
81 
82  // remove shadow maps
83  if (!light.Value.Light.ShadowMap && light.Value.ShadowMap != null)
84  RemoveShadowMap(light.Value);
85  }
86 
87  FillActiveLightShadowMaps();
88 
89  InternalActiveShadowMaps.Clear();
90  InternalActiveShadowMapTextures.Clear();
91 
92  foreach (var light in activeLightShadowMaps)
93  {
94  if (light.Light.ShadowMapFilterType == ShadowMapFilterType.Variance)
95  {
96  // if it was inserted, sort the shadow maps
97  if (ChooseShadowMapTexture(light, shadowMapVsmTextures, texturesVsm))
98  {
99  shadowMapVsmTextures.Sort(ShadowMapTextureComparerVsm);
100  InternalActiveShadowMaps.Add(light.ShadowMap);
101  InternalActiveShadowMapTextures.Add(light.ShadowMap.Texture);
102  }
103  }
104  else
105  {
106  // if it was inserted, sort the shadow maps
107  if (ChooseShadowMapTexture(light, shadowMapDefaultTextures, texturesDefault))
108  {
109  shadowMapDefaultTextures.Sort(ShadowMapTextureComparerDefault);
110  InternalActiveShadowMaps.Add(light.ShadowMap);
111  InternalActiveShadowMapTextures.Add(light.ShadowMap.Texture);
112  }
113  }
114  }
115 
116  // update shadow map infos
117  foreach (var light in activeLightShadowMaps)
118  UpdateEntityLightShadow(light);
119 
120  activeLightShadowMaps.Clear();
121 
122  // clear the virtual allocation again
123  foreach (var texture in shadowMapDefaultTextures)
124  texture.GuillotinePacker.Clear(texture.ShadowMapDepthBuffer.Texture.Width, texture.ShadowMapDepthBuffer.Texture.Height);
125  foreach (var texture in shadowMapVsmTextures)
126  texture.GuillotinePacker.Clear(texture.ShadowMapDepthBuffer.Texture.Width, texture.ShadowMapDepthBuffer.Texture.Height);
127  }
128  }
129 
130  #endregion
131 
132  #region Protected methods
133 
134  /// <summary>
135  /// Adds the shadow map texture to the budget of textures.
136  /// </summary>
137  /// <param name="shadowMapTexture">The shadow map texture.</param>
138  /// <param name="filterType">The filtering that will be applied to this shadow.</param>
139  protected void AddShadowMapTexture(ShadowMapTexture shadowMapTexture, ShadowMapFilterType filterType)
140  {
141  if (filterType == ShadowMapFilterType.Variance)
142  {
143  texturesVsm.Add(shadowMapTexture, shadowMapTexture.ShadowMapDepthTexture.Width * shadowMapTexture.ShadowMapDepthTexture.Height);
144  shadowMapVsmTextures.Add(shadowMapTexture);
145  }
146  else
147  {
148  texturesDefault.Add(shadowMapTexture, shadowMapTexture.ShadowMapDepthTexture.Width * shadowMapTexture.ShadowMapDepthTexture.Height);
149  shadowMapDefaultTextures.Add(shadowMapTexture);
150  }
151 
152  InternalShadowMapTextures.Add(shadowMapTexture);
153  }
154 
155  /// <inheritdoc/>
156  protected override void OnSystemRemove()
157  {
158  texturesDefault.Clear();
159  texturesVsm.Clear();
160  shadowMapDefaultTextures.Clear();
161  shadowMapVsmTextures.Clear();
162  activeLightShadowMaps.Clear();
163 
164  base.OnSystemRemove();
165  }
166 
167  /// <inheritdoc/>
168  protected override void OnEntityRemoved(Entity entity, EntityLightShadow data)
169  {
170  if (ManageShadows && data.ShadowMap != null)
171  RemoveShadowMap(data);
172  base.OnEntityRemoved(entity, data);
173  }
174 
175  protected override void CreateShadowMap(EntityLightShadow light)
176  {
177  // create the shadow map
178  var shadowMap = new ShadowMap
179  {
180  LightDirection = light.Light.LightDirection,
181  ShadowMapSize = light.Light.ShadowMapMinSize,
182  ShadowNearDistance = light.Light.ShadowNearDistance,
183  ShadowFarDistance = light.Light.ShadowFarDistance,
184  CascadeCount = light.Light.ShadowMapCascadeCount,
186  Layers = light.Light.Layers
187  };
188 
189  InternalShadowMaps.Add(shadowMap);
190  light.ShadowMap = shadowMap;
191  }
192 
193  #endregion
194 
195  #region Private methods
196 
197  private void FillActiveLightShadowMaps()
198  {
199  foreach (var light in Lights)
200  {
201  // TODO: handle shadow maps that does no require to be updated like static shadow maps.
202  if (light.Value.Light.Enabled && light.Value.Light.ShadowMap && light.Value.ShadowMap != null && light.Value.ShadowMap.Update)
203  activeLightShadowMaps.Add(light.Value);
204  }
205 
206  // sort the maps
207  activeLightShadowMaps.Sort(CompareShadows);
208  }
209 
210  private void RemoveShadowMap(EntityLightShadow data)
211  {
212  InternalShadowMaps.Remove(data.ShadowMap);
213  InternalActiveShadowMaps.Remove(data.ShadowMap);
214  data.ShadowMap = null;
215  }
216 
217  private bool ChooseShadowMapTexture(EntityLightShadow light, List<ShadowMapTexture> shadowMapTextures, Dictionary<ShadowMapTexture, int> shadowMapRemainingSize)
218  {
219  var shadowMap = light.ShadowMap;
220  var shadowMapSize = light.Light.ShadowMapMaxSize;
221  // find best texture
222  while (shadowMapSize > 0)
223  {
224  if (shadowMapSize < light.Light.ShadowMapMinSize)
225  shadowMapSize = light.Light.ShadowMapMinSize;
226 
227  foreach (var shadowMapTexture in shadowMapTextures)
228  {
229  if (shadowMapTexture.GuillotinePacker.TryInsert(shadowMapSize, shadowMapSize, shadowMap.CascadeCount))
230  {
231  shadowMap.Texture = shadowMapTexture;
232  shadowMapRemainingSize[shadowMapTexture] = shadowMapRemainingSize[shadowMapTexture] - (shadowMap.CascadeCount * shadowMapSize * shadowMapSize);
233  shadowMap.ShadowMapSize = shadowMapSize;
234  return true;
235  }
236  }
237 
238  if (shadowMapSize == light.Light.ShadowMapMinSize)
239  break;
240  shadowMapSize /= 2;
241  }
242 
243  // Issue a warning only once
244  if (!shadowMapFullWarningDone)
245  {
246  shadowMapFullWarningDone = true;
247  Logger.Warning("Unable to find a texture to create the shadow map.");
248  }
249 
250  shadowMap.Texture = null;
251  return false;
252  }
253 
254  private int ShadowMapTextureComparerDefault(ShadowMapTexture texture0, ShadowMapTexture texture1)
255  {
256  return texturesDefault[texture0] - texturesDefault[texture1];
257  }
258 
259  private int ShadowMapTextureComparerVsm(ShadowMapTexture texture0, ShadowMapTexture texture1)
260  {
261  return texturesVsm[texture0] - texturesVsm[texture1];
262  }
263 
264  #endregion
265 
266  #region Private static methods
267 
268  // returns shadow0 - shadow1
269  private static int CompareShadows(EntityLightShadow shadow0, EntityLightShadow shadow1)
270  {
271  var lightTypeComparaison = GetLightTypeValue(shadow0.Light.Type) - GetLightTypeValue(shadow1.Light.Type);
272  if (lightTypeComparaison != 0)
273  return lightTypeComparaison;
274 
275  var shadowMapSizeDiff = shadow0.Light.ShadowMapMaxSize - shadow1.Light.ShadowMapMaxSize;
276  if (shadowMapSizeDiff > 0)
277  return -1;
278  if (shadowMapSizeDiff < 0)
279  return 1;
280 
281  // TODO: more comparisons
282 
283  return 0;
284  }
285 
286  private static int GetLightTypeValue(LightType lightType)
287  {
288  switch (lightType)
289  {
290  case LightType.Point:
291  return 3;
292  case LightType.Spherical:
293  return 4;
294  case LightType.Directional:
295  return 0;
296  case LightType.Spot:
297  return 1;
298  default:
299  throw new ArgumentOutOfRangeException("lightType");
300  }
301  }
302 
303  #endregion
304  }
305 }
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
A class handling the allocation of shadow maps with a fixed budget of shadow map textures. This class is meant to be inherited with the desired budget since it has no texture at all.
Represents a shadow map for the ShadowMapRenderer.
Definition: ShadowMap.cs:15
void AddShadowMapTexture(ShadowMapTexture shadowMapTexture, ShadowMapFilterType filterType)
Adds the shadow map texture to the budget of textures.
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
Represents a texture to use with ShadowMapRenderer.