Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
LightForwardModelRenderer.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.Core;
8 using SiliconStudio.Core.Mathematics;
9 using SiliconStudio.Paradox.DataModel;
10 using SiliconStudio.Paradox.Effects.Modules.Processors;
11 using SiliconStudio.Paradox.Effects.Modules.Shadowmap;
12 using SiliconStudio.Paradox.Engine;
13 using SiliconStudio.Paradox.EntityModel;
14 using SiliconStudio.Paradox.Graphics;
15 
16 namespace SiliconStudio.Paradox.Effects.Modules.Renderers
17 {
18  /// <summary>
19  /// TODO: Evaluate if it would be possible to split this class with support for different lights instead of a big fat class
20  /// TODO: Refactor this class
21  /// </summary>
22  internal class LightForwardModelRenderer
23  {
24  internal static Dictionary<ParameterKey, LightParamSemantic> LightParametersDict = new Dictionary<ParameterKey, LightParamSemantic>
25  {
26  { ShadingEyeNormalVSKeys.LightDirectionsVS, LightParamSemantic.DirectionVS },
27  { ShadingEyeNormalVSKeys.LightPositionsVS, LightParamSemantic.PositionVS },
28  { ShadingEyeNormalWSKeys.LightDirectionsWS, LightParamSemantic.DirectionWS },
29  { ShadingEyeNormalWSKeys.LightPositionsWS, LightParamSemantic.PositionWS },
30  { LightParametersKeys.LightColorsWithGamma, LightParamSemantic.ColorWithGamma },
31  { LightParametersKeys.LightIntensities, LightParamSemantic.Intensity },
32  { LightParametersKeys.LightDecayStarts, LightParamSemantic.Decay },
33  { LightParametersKeys.LightSpotBeamAngle, LightParamSemantic.SpotBeamAngle },
34  { LightParametersKeys.LightSpotFieldAngle, LightParamSemantic.SpotFieldAngle },
35  { LightParametersKeys.LightCount, LightParamSemantic.Count }
36  };
37 
38  #region Private members
39 
40  private int maximumSupportedLights;
41 
42  private readonly Dictionary<Entity, Vector3> lightDirectionViewSpace;
43 
44  private readonly Dictionary<Entity, Vector3> lightDirectionWorldSpace;
45 
46  private readonly Dictionary<Entity, Color3> lightGammaColor;
47 
48  private float[] arrayFloat;
49 
50  private Vector3[] arrayVector3;
51 
52  private Color3[] arrayColor3;
53 
54  private readonly ShadowMapReceiverInfo[] receiverInfos;
55 
56  private readonly ShadowMapReceiverVsmInfo[] receiverVsmInfos;
57 
58  private readonly ShadowMapCascadeReceiverInfo[] cascadeInfos;
59 
60  private readonly List<EntityLightShadow> validLights;
61 
62  private readonly List<EntityLightShadow> directionalLights;
63 
64  private readonly List<EntityLightShadow> directionalLightsWithShadows;
65 
66  private readonly List<EntityLightShadow> pointLights;
67 
68  private readonly List<EntityLightShadow> spotLights;
69 
70  private readonly List<EntityLightShadow> spotLightsWithShadows;
71 
72  private readonly List<EntityLightShadow> directionalLightsForMesh;
73 
74  private readonly List<EntityLightShadow> directionalLightsWithShadowForMesh;
75 
76  private readonly List<EntityLightShadow> pointLightsForMesh;
77 
78  private readonly List<EntityLightShadow> spotLightsForMesh;
79 
80  private readonly List<EntityLightShadow> spotLightsWithShadowForMesh;
81 
82  private readonly Dictionary<ParameterKey, LightParamSemantic> lightingParameterSemantics;
83 
84  private readonly List<List<EntityLightShadow>> directionalLightsWithShadowForMeshGroups;
85 
86  private readonly List<List<EntityLightShadow>> spotLightsWithShadowForMeshGroups;
87 
88  private readonly List<List<ShadowMap>> shadowMapGroups;
89 
90  private LightingConfiguration lastConfiguration;
91 
92  #endregion
93 
94  #region Constructor
95 
96  public LightForwardModelRenderer(IServiceRegistry services)
97  {
98  if (services == null) throw new ArgumentNullException("services");
99  Services = services;
100  maximumSupportedLights = 128;
101 
102  lightDirectionViewSpace = new Dictionary<Entity, Vector3>();
103  lightDirectionWorldSpace = new Dictionary<Entity, Vector3>();
104  lightGammaColor = new Dictionary<Entity, Color3>();
105 
106  arrayFloat = new float[4 * maximumSupportedLights];
107  arrayVector3 = new Vector3[2 * maximumSupportedLights];
108  arrayColor3 = new Color3[maximumSupportedLights];
109  //TODO: resize
110  receiverInfos = new ShadowMapReceiverInfo[16];
111  receiverVsmInfos = new ShadowMapReceiverVsmInfo[16];
112  cascadeInfos = new ShadowMapCascadeReceiverInfo[128];
113 
114  validLights = new List<EntityLightShadow>();
115  directionalLights = new List<EntityLightShadow>();
116  directionalLightsWithShadows = new List<EntityLightShadow>();
117  pointLights = new List<EntityLightShadow>();
118  spotLights = new List<EntityLightShadow>();
119  spotLightsWithShadows = new List<EntityLightShadow>();
120 
121  directionalLightsForMesh = new List<EntityLightShadow>();
122  directionalLightsWithShadowForMesh = new List<EntityLightShadow>();
123  directionalLightsWithShadowForMeshGroups = new List<List<EntityLightShadow>>();
124  spotLightsWithShadowForMeshGroups = new List<List<EntityLightShadow>>();
125  pointLightsForMesh = new List<EntityLightShadow>();
126  spotLightsForMesh = new List<EntityLightShadow>();
127  spotLightsWithShadowForMesh = new List<EntityLightShadow>();
128 
129  shadowMapGroups = new List<List<ShadowMap>>();
130 
131  lightingParameterSemantics = new Dictionary<ParameterKey, LightParamSemantic>();
132  }
133 
134  #endregion
135 
136  public IServiceRegistry Services { get; private set; }
137 
138  #region Protected methods
139 
140 
141  /// <summary>
142  /// Filter out the inactive lights.
143  /// </summary>
144  /// <param name="context">The render context.</param>
145  public void PreRender(RenderContext context)
146  {
147  // get the lightprocessor
148  var entitySystem = Services.GetServiceAs<EntitySystem>();
149  var lightProcessor = entitySystem.GetProcessor<LightShadowProcessor>();
150  if (lightProcessor == null)
151  return;
152 
153  foreach (var light in lightProcessor.Lights)
154  {
155  if (!light.Value.Light.Deferred && light.Value.Light.Enabled)
156  {
157  validLights.Add(light.Value);
158 
159  switch (light.Value.Light.Type)
160  {
161  case LightType.Point:
162  pointLights.Add(light.Value);
163  break;
164  case LightType.Spherical:
165  break;
166  case LightType.Directional:
167  if (light.Value.HasShadowMap && lightProcessor.ActiveShadowMaps.Contains(light.Value.ShadowMap))
168  directionalLightsWithShadows.Add(light.Value);
169  else
170  directionalLights.Add(light.Value);
171  break;
172  case LightType.Spot:
173  if (light.Value.HasShadowMap && lightProcessor.ActiveShadowMaps.Contains(light.Value.ShadowMap))
174  spotLightsWithShadows.Add(light.Value);
175  else
176  spotLights.Add(light.Value);
177  break;
178  }
179  }
180  }
181  }
182 
183  /// <summary>
184  /// Clear the light lists.
185  /// </summary>
186  /// <param name="context">The render context.</param>
187  public void PostRender(RenderContext context)
188  {
189  lightDirectionViewSpace.Clear();
190  lightDirectionWorldSpace.Clear();
191  lightGammaColor.Clear();
192  validLights.Clear();
193  directionalLights.Clear();
194  directionalLightsWithShadows.Clear();
195  pointLights.Clear();
196  spotLights.Clear();
197  spotLightsWithShadows.Clear();
198  directionalLightsForMesh.Clear();
199  directionalLightsWithShadowForMesh.Clear();
200  foreach (var group in directionalLightsWithShadowForMeshGroups)
201  group.Clear();
202  foreach (var group in spotLightsWithShadowForMeshGroups)
203  group.Clear();
204  foreach (var group in shadowMapGroups)
205  group.Clear();
206  pointLightsForMesh.Clear();
207  spotLightsForMesh.Clear();
208  spotLightsWithShadowForMesh.Clear();
209  }
210 
211  /// <summary>
212  /// Update light lists and choose the new light configuration.
213  /// </summary>
214  /// <param name="context">The render context.</param>
215  /// <param name="renderMesh">The current RenderMesh (the same as <seealso cref="PostEffectUpdate"/>)</param>
216  public void PreEffectUpdate(RenderContext context, RenderMesh renderMesh)
217  {
218  var mesh = renderMesh.Mesh;
219 
220  // TODO:
221  // light selection based on:
222  // - from the same entity?
223  // - spot & point lights distances
224  // rewrite shaders to handle all the cases?
225  // TODO: other criterion to choose the light (distance?)
226 
227  directionalLightsForMesh.Clear();
228  directionalLightsWithShadowForMesh.Clear();
229  foreach (var group in directionalLightsWithShadowForMeshGroups)
230  group.Clear();
231  foreach (var group in spotLightsWithShadowForMeshGroups)
232  group.Clear();
233  foreach (var group in shadowMapGroups)
234  group.Clear();
235  pointLightsForMesh.Clear();
236  spotLightsForMesh.Clear();
237  spotLightsWithShadowForMesh.Clear();
238 
239  var receiveShadows = renderMesh.Mesh.Parameters.Get(LightingKeys.ReceiveShadows);
240  var renderLayers = renderMesh.Mesh.Parameters.Get(RenderingParameters.RenderLayer);
241 
242  foreach (var light in directionalLights)
243  {
244  if ((light.Light.Layers & renderLayers) != 0)
245  directionalLightsForMesh.Add(light);
246  }
247  foreach (var light in directionalLightsWithShadows)
248  {
249  if ((light.Light.Layers & renderLayers) != 0)
250  {
251  if (receiveShadows)
252  directionalLightsWithShadowForMesh.Add(light);
253  else
254  directionalLightsForMesh.Add(light);
255  }
256  }
257  foreach (var light in pointLights)
258  {
259  if ((light.Light.Layers & renderLayers) != 0)
260  pointLightsForMesh.Add(light);
261  }
262  foreach (var light in spotLights)
263  {
264  if ((light.Light.Layers & renderLayers) != 0)
265  spotLightsForMesh.Add(light);
266  }
267  foreach (var light in spotLightsWithShadows)
268  {
269  if ((light.Light.Layers & renderLayers) != 0)
270  {
271  if (receiveShadows)
272  spotLightsWithShadowForMesh.Add(light);
273  else
274  spotLightsForMesh.Add(light);
275  }
276  }
277 
278  var numDirectionalLights = directionalLightsForMesh.Count;
279  var numPointLights = pointLightsForMesh.Count;
280  var numSpotLights = spotLightsForMesh.Count;
281 
282  // TODO: improve detection - better heuristics
283  // choose configuration
284  var configurations = renderMesh.Mesh.Parameters.Get(LightingKeys.LightingConfigurations);
285  var lastConfigWithoutShadow = -1;
286  if (configurations != null)
287  {
288  LightingConfiguration foundConfiguration;
289  foundConfiguration.MaxNumDirectionalLight = 0;
290  foundConfiguration.MaxNumPointLight = 0;
291  foundConfiguration.MaxNumSpotLight = 0;
292  foundConfiguration.UnrollDirectionalLightLoop = false;
293  foundConfiguration.UnrollPointLightLoop = false;
294  foundConfiguration.UnrollSpotLightLoop = false;
295  var configurationIndex = -1;
296  for (var i = 0; i < configurations.Configs.Length; ++i)
297  {
298  if (configurations.Configs[i].ShadowConfigurations == null || configurations.Configs[i].ShadowConfigurations.Groups.Count == 0)
299  lastConfigWithoutShadow = i;
300 
301  if (TestConfiguration(numDirectionalLights, numPointLights, numSpotLights, configurations.Configs[i]))
302  {
303  configurationIndex = i;
304  break;
305  }
306  }
307 
308  // no correct configuration found
309  if (configurationIndex < 0)
310  {
311  if (lastConfigWithoutShadow != -1)// take the biggest one without shadow
312  configurationIndex = lastConfigWithoutShadow;
313  else // take the latest
314  configurationIndex = configurations.Configs.Length - 1;
315  }
316 
317  foundConfiguration = configurations.Configs[configurationIndex];
318 
319  var maxNumDirectionalLights = foundConfiguration.MaxNumDirectionalLight;
320  var maxNumPointLights = foundConfiguration.MaxNumPointLight;
321  var maxNumSpotLights = foundConfiguration.MaxNumSpotLight;
322 
323  //create the parameters to get the correct shader
324  if (configurationIndex != mesh.Parameters.Get(LightKeys.ConfigurationIndex))
325  {
326  CreateParametersFromLightingConfiguration(foundConfiguration, mesh.Parameters);
327  mesh.Parameters.Set(LightKeys.ConfigurationIndex, configurationIndex);
328  }
329 
330  // assign the shadow ligths to a specific group
331  if (foundConfiguration.ShadowConfigurations != null)
332  AssignGroups(foundConfiguration);
333 
334  var finalDirectionalLightCount = Math.Min(numDirectionalLights, maxNumDirectionalLights);
335  var finalPointLightCount = Math.Min(numPointLights, maxNumPointLights);
336  var finalSpotLightCount = Math.Min(numSpotLights, maxNumSpotLights);
337 
338  var maxLights = finalDirectionalLightCount;
339  if (maxLights > finalPointLightCount)
340  maxLights = finalPointLightCount;
341  if (maxLights > finalSpotLightCount)
342  maxLights = finalSpotLightCount;
343 
344  if (maxLights > maximumSupportedLights)
345  {
346  maximumSupportedLights = maxLights;
347  arrayFloat = new float[4 * maxLights];
348  arrayVector3 = new Vector3[2 * maxLights];
349  arrayColor3 = new Color3[maxLights];
350  }
351 
352  lastConfiguration = foundConfiguration;
353  }
354  }
355 
356  /// <summary>
357  /// Update the light values of the shader.
358  /// </summary>
359  /// <param name="context">The render context.</param>
360  /// <param name="renderMesh">The current RenderMesh (the same as <seealso cref="PreEffectUpdate"/>)</param>
361  public void PostEffectUpdate(RenderContext context, RenderMesh renderMesh)
362  {
363  var lightingGroupInfo = LightingGroupInfo.GetOrCreate(renderMesh.Effect);
364 
365  var mesh = renderMesh.Mesh;
366 
367  // update the info if necessary
368  if (!lightingGroupInfo.IsLightingSetup)
369  {
370  lightingGroupInfo.LightingParameters = CreateLightingUpdateInfo(renderMesh);
371  if (lastConfiguration.ShadowConfigurations != null)
372  lightingGroupInfo.ShadowParameters = CreateEffectShadowParams(lastConfiguration);
373 
374  lightingGroupInfo.IsLightingSetup = true;
375  }
376 
377  if (lightingGroupInfo.LightingParameters.Count == 0)
378  return;
379 
380  // TODO: is it always available?
381  var viewMatrix = context.CurrentPass.Parameters.Get(TransformationKeys.View);
382 
383  if (lightingGroupInfo.ShadowParameters != null)
384  {
385  for (var i = 0; i < lightingGroupInfo.ShadowParameters.Count; ++i)
386  UpdateShadowParameters(mesh.Parameters, lightingGroupInfo.ShadowParameters[i], shadowMapGroups[i]);
387  }
388 
389  // Apply parameters
390  foreach (var info in lightingGroupInfo.LightingParameters)
391  {
392  switch (info.Type)
393  {
394  case LightingUpdateType.Point:
395  UpdateLightingParameters(info, ref renderMesh, ref viewMatrix, pointLightsForMesh);
396  break;
397  case LightingUpdateType.Directional:
398  UpdateLightingParameters(info, ref renderMesh, ref viewMatrix, directionalLightsForMesh);
399  break;
400  case LightingUpdateType.Spot:
401  UpdateLightingParameters(info, ref renderMesh, ref viewMatrix, spotLightsForMesh);
402  break;
403  case LightingUpdateType.DirectionalShadow:
404  UpdateLightingParameters(info, ref renderMesh, ref viewMatrix, directionalLightsWithShadowForMeshGroups[info.Index]);
405  break;
406  case LightingUpdateType.SpotShadow:
407  UpdateLightingParameters(info, ref renderMesh, ref viewMatrix, spotLightsWithShadowForMeshGroups[info.Index]);
408  break;
409  //TODO: implement later when shadow map are supported
410  case LightingUpdateType.PointShadow:
411  break;
412  default:
413  throw new ArgumentOutOfRangeException();
414  }
415  }
416  }
417 
418  #endregion
419 
420  #region Private methods
421 
422  private bool TestConfiguration(int numDirectionalLights, int numPointLights, int numSpotLights, LightingConfiguration config)
423  {
424  if (config.MaxNumDirectionalLight < numDirectionalLights || config.MaxNumPointLight < numPointLights || config.MaxNumSpotLight < numSpotLights)
425  return false;
426 
427  //TODO change hardcoded 16
428  var groupCounts = new int[16];
429  var groupTextures = new Texture2D[16];
430 
431  // TODO: optimize OR consider that this will always be relatively small
432  foreach (var light in directionalLightsWithShadowForMesh)
433  {
434  var notFound = true;
435  if (config.ShadowConfigurations != null)
436  {
437  for (var i = 0; i < config.ShadowConfigurations.Groups.Count; ++i)
438  {
439  if (BelongToGroup(light.Light, light.ShadowMap, config.ShadowConfigurations.Groups[i], groupCounts[i], groupTextures[i]))
440  {
441  groupCounts[i] += 1;
442  if (groupTextures[i] == null)
443  groupTextures[i] = light.ShadowMap.Texture.ShadowMapDepthTexture;
444  notFound = false;
445  break;
446  }
447  }
448  }
449  if (notFound)
450  return false;
451  }
452  foreach (var light in spotLightsWithShadowForMesh)
453  {
454  var notFound = true;
455  if (config.ShadowConfigurations != null)
456  {
457  for (var i = 0; i < config.ShadowConfigurations.Groups.Count; ++i)
458  {
459  if (BelongToGroup(light.Light, light.ShadowMap, config.ShadowConfigurations.Groups[i], groupCounts[i], groupTextures[i]))
460  {
461  groupCounts[i] += 1;
462  if (groupTextures[i] == null)
463  groupTextures[i] = light.ShadowMap.Texture.ShadowMapDepthTexture;
464  notFound = false;
465  break;
466  }
467  }
468  }
469  if (notFound)
470  return false;
471  }
472  return true;
473  }
474 
475  private void AssignGroups(LightingConfiguration config)
476  {
477  // TODO: optimize the groups based on the maximum number of shadow maps so that when there is a solution, it is chosen
478 
479  // TODO: add shadow group and directional light shadow group (list) if necessary
480  for (var i = shadowMapGroups.Count; i < config.ShadowConfigurations.Groups.Count; ++i)
481  shadowMapGroups.Add(new List<ShadowMap>());
482 
483  for (var i = directionalLightsWithShadowForMeshGroups.Count; i < config.ShadowConfigurations.Groups.Count; ++i)
484  directionalLightsWithShadowForMeshGroups.Add(new List<EntityLightShadow>());
485  foreach (var light in directionalLightsWithShadowForMesh)
486  {
487  for (var i = 0; i < config.ShadowConfigurations.Groups.Count; ++i)
488  {
489  if (BelongToGroup(light.Light, light.ShadowMap, config.ShadowConfigurations.Groups[i], shadowMapGroups[i].Count, shadowMapGroups[i].Count > 0 ? shadowMapGroups[i][0].Texture.ShadowMapDepthTexture : null))
490  {
491  shadowMapGroups[i].Add(light.ShadowMap);
492  directionalLightsWithShadowForMeshGroups[i].Add(light);
493  break;
494  }
495  }
496  }
497 
498  for (var i = spotLightsWithShadowForMeshGroups.Count; i < config.ShadowConfigurations.Groups.Count; ++i)
499  spotLightsWithShadowForMeshGroups.Add(new List<EntityLightShadow>());
500  foreach (var light in spotLightsWithShadowForMesh)
501  {
502  for (var i = 0; i < config.ShadowConfigurations.Groups.Count; ++i)
503  {
504  if (BelongToGroup(light.Light, light.ShadowMap, config.ShadowConfigurations.Groups[i], shadowMapGroups[i].Count, shadowMapGroups[i].Count > 0 ? shadowMapGroups[i][0].Texture.ShadowMapDepthTexture : null))
505  {
506  shadowMapGroups[i].Add(light.ShadowMap);
507  spotLightsWithShadowForMeshGroups[i].Add(light);
508  break;
509  }
510  }
511  }
512  }
513 
514  private void UpdateLightingParameters(LightingUpdateInfo info, ref RenderMesh renderMesh, ref Matrix viewMatrix, List<EntityLightShadow> lightsForMesh)
515  {
516  var mesh = renderMesh.Mesh;
517 
518  var maxLights = info.Count;
519  if (maxLights > 0)
520  {
521  Matrix worldView;
522  Vector3 lightDir;
523  Vector3 lightPos;
524  Vector3 direction;
525  Vector3 position;
526  var lightCount = 0;
527  foreach (var light in lightsForMesh)
528  {
529  if ((info.Semantic & LightParamSemantic.PositionDirectionVS) != 0)
530  {
531  if ((info.Semantic & LightParamSemantic.DirectionVS) != 0)
532  {
533  Matrix.Multiply(ref light.Entity.Transformation.WorldMatrix, ref viewMatrix, out worldView);
534  lightDir = light.Light.LightDirection;
535  Vector3.TransformNormal(ref lightDir, ref worldView, out direction);
536  arrayVector3[lightCount] = direction;
537  }
538  if ((info.Semantic & LightParamSemantic.PositionVS) != 0)
539  {
540  lightPos = light.Entity.Transformation.Translation;
541  Vector3.TransformCoordinate(ref lightPos, ref viewMatrix, out position);
542  arrayVector3[lightCount + maxLights] = position;
543  }
544  }
545  else if ((info.Semantic & LightParamSemantic.PositionDirectionWS) != 0)
546  {
547  if ((info.Semantic & LightParamSemantic.DirectionWS) != 0)
548  {
549  lightDir = light.Light.LightDirection;
550  Vector3.TransformNormal(ref lightDir, ref light.Entity.Transformation.WorldMatrix, out direction);
551  arrayVector3[lightCount] = direction;
552  }
553  if ((info.Semantic & LightParamSemantic.PositionWS) != 0)
554  {
555  lightPos = light.Entity.Transformation.Translation;
556  arrayVector3[lightCount + maxLights] = lightPos;
557  }
558  }
559  if ((info.Semantic & LightParamSemantic.ColorWithGamma) != 0)
560  {
561  //color.R = (float)Math.Pow(light.Light.Color.R, 2.2);
562  //color.G = (float)Math.Pow(light.Light.Color.G, 2.2);
563  //color.B = (float)Math.Pow(light.Light.Color.B, 2.2);
564  //arrayColor3[lightCount] = color;
565  arrayColor3[lightCount] = light.Light.Color;
566  }
567  if ((info.Semantic & LightParamSemantic.Intensity) != 0)
568  {
569  arrayFloat[lightCount] = light.Light.Intensity;
570  }
571  if ((info.Semantic & LightParamSemantic.Decay) != 0)
572  {
573  arrayFloat[lightCount + maxLights] = light.Light.DecayStart;
574  }
575  if ((info.Semantic & LightParamSemantic.SpotBeamAngle) != 0)
576  {
577  arrayFloat[lightCount + 2 * maxLights] = (float)Math.Cos(Math.PI * light.Light.SpotBeamAngle / 180);
578  }
579  if ((info.Semantic & LightParamSemantic.SpotFieldAngle) != 0)
580  {
581  arrayFloat[lightCount + 3 * maxLights] = (float)Math.Cos(Math.PI * light.Light.SpotFieldAngle / 180);
582  }
583 
584  ++lightCount;
585  if (lightCount >= maxLights)
586  break;
587  }
588 
589  if ((info.Semantic & LightParamSemantic.DirectionVS) != 0)
590  mesh.Parameters.Set(info.DirectionKey, arrayVector3, 0, lightCount);
591  if ((info.Semantic & LightParamSemantic.PositionVS) != 0)
592  mesh.Parameters.Set(info.PositionKey, arrayVector3, maxLights, 0, lightCount);
593  if ((info.Semantic & LightParamSemantic.DirectionWS) != 0)
594  mesh.Parameters.Set(info.DirectionKey, arrayVector3, 0, lightCount);
595  if ((info.Semantic & LightParamSemantic.PositionWS) != 0)
596  mesh.Parameters.Set(info.PositionKey, arrayVector3, maxLights, 0, lightCount);
597  if ((info.Semantic & LightParamSemantic.ColorWithGamma) != 0)
598  mesh.Parameters.Set(info.ColorKey, arrayColor3, 0, lightCount);
599  if ((info.Semantic & LightParamSemantic.Intensity) != 0)
600  mesh.Parameters.Set(info.IntensityKey, arrayFloat, 0, lightCount);
601  if ((info.Semantic & LightParamSemantic.Decay) != 0)
602  mesh.Parameters.Set(info.DecayKey, arrayFloat, maxLights, 0, lightCount);
603  if ((info.Semantic & LightParamSemantic.SpotBeamAngle) != 0)
604  mesh.Parameters.Set(info.SpotBeamAngleKey, arrayFloat, 2 * maxLights, 0, lightCount);
605  if ((info.Semantic & LightParamSemantic.SpotFieldAngle) != 0)
606  mesh.Parameters.Set(info.SpotFieldAngleKey, arrayFloat, 3 * maxLights, 0, lightCount);
607  if ((info.Semantic & LightParamSemantic.Count) != 0)
608  mesh.Parameters.Set(info.LightCountKey, lightCount);
609  }
610  else
611  {
612  if ((info.Semantic & LightParamSemantic.Count) != 0)
613  mesh.Parameters.Set(info.LightCountKey, 0);
614  }
615  }
616 
617  private void UpdateShadowParameters(ParameterCollection parameters, ShadowUpdateInfo shadowUpdateInfo, List<ShadowMap> shadows)
618  {
619  if (shadows != null && shadows.Count > 0)
620  {
621  var count = 0;
622  var cascadeCount = 0;
623  foreach (var shadow in shadows)
624  {
625  receiverInfos[count] = shadow.ReceiverInfo;
626  receiverVsmInfos[count] = shadow.ReceiverVsmInfo;
627  for (var i = 0; i < shadowUpdateInfo.CascadeCount; ++i)
628  cascadeInfos[cascadeCount + i] = shadow.Cascades[i].ReceiverInfo;
629  ++count;
630  cascadeCount += shadowUpdateInfo.CascadeCount;
631  }
632 
633  parameters.Set((ParameterKey<ShadowMapReceiverInfo[]>)shadowUpdateInfo.ShadowMapReceiverInfoKey, receiverInfos, 0, count);
634  parameters.Set((ParameterKey<ShadowMapCascadeReceiverInfo[]>)shadowUpdateInfo.ShadowMapLevelReceiverInfoKey, cascadeInfos, 0, cascadeCount);
635  if (shadows[0].Filter == ShadowMapFilterType.Variance)
636  {
637  parameters.Set((ParameterKey<ShadowMapReceiverVsmInfo[]>)shadowUpdateInfo.ShadowMapReceiverVsmInfoKey, receiverVsmInfos, 0, count);
638  parameters.Set(shadowUpdateInfo.ShadowMapTextureKey, shadows[0].Texture.ShadowMapTargetTexture);
639  }
640  else
641  parameters.Set(shadowUpdateInfo.ShadowMapTextureKey, shadows[0].Texture.ShadowMapDepthTexture);
642  parameters.Set(shadowUpdateInfo.ShadowMapLightCountKey, count);
643  }
644  else
645  parameters.Set(shadowUpdateInfo.ShadowMapLightCountKey, 0);
646  }
647 
648  private List<LightingUpdateInfo> CreateLightingUpdateInfo(RenderMesh renderMesh)
649  {
650  var finalList = new List<LightingUpdateInfo>();
651  var continueSearch = true;
652  var index = 0;
653  while (continueSearch)
654  {
655  continueSearch = SearchShadingGroup(renderMesh, index, "ShadingGroups", 0, finalList);
656  ++index;
657  }
658 
659  continueSearch = true;
660  index = 0;
661  while (continueSearch)
662  {
663  continueSearch = SearchShadingGroup(renderMesh, index, "shadows", 3, finalList);
664  ++index;
665  }
666 
667  return finalList;
668  }
669 
670  private bool SearchShadingGroup(RenderMesh renderMesh, int index, string groupName, int typeOffset, List<LightingUpdateInfo> finalList)
671  {
672  var mesh = renderMesh.Mesh;
673  var constantBuffers = renderMesh.Effect.ConstantBuffers;
674  var info = new LightingUpdateInfo();
675 
676  LightParamSemantic foundParameterSemantic;
677  var foundParam = false;
678  var lightTypeGuess = LightTypeGuess.None;
679 
680  UpdateLightingParameterSemantics(index, groupName);
681 
682  foreach (var constantBuffer in constantBuffers)
683  {
684  foreach (var member in constantBuffer.Members)
685  {
686  if (lightingParameterSemantics.TryGetValue(member.Param.Key, out foundParameterSemantic))
687  {
688  info.Semantic = info.Semantic | foundParameterSemantic;
689  foundParam = true;
690  switch (foundParameterSemantic)
691  {
692  case LightParamSemantic.PositionVS:
693  info.PositionKey = (ParameterKey<Vector3[]>)member.Param.Key;
694  mesh.Parameters.Set(info.PositionKey, new Vector3[member.Count]);
695  info.Count = member.Count;
696  lightTypeGuess = lightTypeGuess | LightTypeGuess.Point;
697  break;
698  case LightParamSemantic.DirectionVS:
699  info.DirectionKey = (ParameterKey<Vector3[]>)member.Param.Key;
700  mesh.Parameters.Set(info.DirectionKey, new Vector3[member.Count]);
701  info.Count = member.Count;
702  lightTypeGuess = lightTypeGuess | LightTypeGuess.Directional;
703  break;
704  case LightParamSemantic.PositionWS:
705  info.PositionKey = (ParameterKey<Vector3[]>)member.Param.Key;
706  mesh.Parameters.Set(info.PositionKey, new Vector3[member.Count]);
707  info.Count = member.Count;
708  lightTypeGuess = lightTypeGuess | LightTypeGuess.Point;
709  break;
710  case LightParamSemantic.DirectionWS:
711  info.DirectionKey = (ParameterKey<Vector3[]>)member.Param.Key;
712  mesh.Parameters.Set(info.DirectionKey, new Vector3[member.Count]);
713  info.Count = member.Count;
714  lightTypeGuess = lightTypeGuess | LightTypeGuess.Directional;
715  break;
716  case LightParamSemantic.ColorWithGamma:
717  info.ColorKey = (ParameterKey<Color3[]>)member.Param.Key;
718  mesh.Parameters.Set(info.ColorKey, new Color3[member.Count]);
719  info.Count = member.Count;
720  break;
721  case LightParamSemantic.Intensity:
722  info.IntensityKey = (ParameterKey<float[]>)member.Param.Key;
723  mesh.Parameters.Set(info.IntensityKey, new float[member.Count]);
724  info.Count = member.Count;
725  break;
726  case LightParamSemantic.Decay:
727  info.DecayKey = (ParameterKey<float[]>)member.Param.Key;
728  mesh.Parameters.Set(info.DecayKey, new float[member.Count]);
729  info.Count = member.Count;
730  lightTypeGuess = lightTypeGuess | LightTypeGuess.Point;
731  break;
732  case LightParamSemantic.SpotBeamAngle:
733  info.SpotBeamAngleKey = (ParameterKey<float[]>)member.Param.Key;
734  mesh.Parameters.Set(info.SpotBeamAngleKey, new float[member.Count]);
735  info.Count = member.Count;
736  lightTypeGuess = lightTypeGuess | LightTypeGuess.Spot;
737  break;
738  case LightParamSemantic.SpotFieldAngle:
739  info.SpotFieldAngleKey = (ParameterKey<float[]>)member.Param.Key;
740  mesh.Parameters.Set(info.SpotFieldAngleKey, new float[member.Count]);
741  info.Count = member.Count;
742  lightTypeGuess = lightTypeGuess | LightTypeGuess.Spot;
743  break;
744  case LightParamSemantic.Count:
745  info.LightCountKey = (ParameterKey<int>)member.Param.Key;
746  break;
747  default:
748  throw new ArgumentOutOfRangeException();
749  }
750  }
751  }
752  }
753  if (foundParam)
754  {
755  switch (lightTypeGuess)
756  {
757  case LightTypeGuess.Directional:
758  info.Type = LightingUpdateType.Directional + typeOffset;
759  break;
760  case LightTypeGuess.Point:
761  info.Type = LightingUpdateType.Point + typeOffset;
762  break;
763  case LightTypeGuess.Spot:
764  info.Type = LightingUpdateType.Spot + typeOffset;
765  break;
766  }
767  if (lightTypeGuess != LightTypeGuess.None)
768  {
769  info.Index = index;
770  finalList.Add(info);
771  }
772  }
773  return foundParam;
774  }
775 
776  private static List<ShadowUpdateInfo> CreateEffectShadowParams(LightingConfiguration config)
777  {
778  var configs = new List<ShadowUpdateInfo>();
779 
780  for (var i = 0; i < config.ShadowConfigurations.Groups.Count; ++i)
781  {
782  var group = LightingProcessorHelpers.CreateShadowUpdateInfo(i, config.ShadowConfigurations.Groups[i].CascadeCount);
783  configs.Add(group);
784  }
785 
786  return configs;
787  }
788 
789  private void UpdateLightingParameterSemantics(int index, string compositionName)
790  {
791  lightingParameterSemantics.Clear();
792  var lightGroupSubKey = string.Format("." + compositionName + "[{0}]", index);
793  foreach (var param in LightParametersDict)
794  {
795  lightingParameterSemantics.Add(ParameterKeys.AppendKey(param.Key, lightGroupSubKey), param.Value);
796  }
797  }
798 
799  #endregion
800 
801  #region Helpers
802 
803  [Flags]
804  private enum LightTypeGuess
805  {
806  None = 0x0,
807  Directional = 0x1, // direction is needed
808  Point = 0x2, // position is needed
809  Spot = Directional | Point // angle falloff is needed
810  }
811 
812  private static bool BelongToGroup(LightComponent light, ShadowMap shadow, ShadowConfiguration config, int groupCount, Texture2D groupTexture)
813  {
814  return light.ShadowMapCascadeCount == config.CascadeCount
815  && light.ShadowMapFilterType == config.FilterType
816  && groupCount < config.ShadowCount
817  && (groupTexture == null || groupTexture == shadow.Texture.ShadowMapDepthTexture);
818  }
819 
820  private static void CreateParametersFromLightingConfiguration(LightingConfiguration config, ParameterCollection parameters)
821  {
822  // Apply parameters for effect change
823  parameters.Set(LightingKeys.MaxDirectionalLights, config.MaxNumDirectionalLight);
824  parameters.Set(LightingKeys.MaxPointLights, config.MaxNumPointLight);
825  parameters.Set(LightingKeys.MaxSpotLights, config.MaxNumSpotLight);
826 
827  // TODO: cache some objects since it is done at each frame
828  // TODO: try to reuse the parameter collections?
829 
830  if (config.ShadowConfigurations != null)
831  {
832  var groupCount = 0;
833  foreach (var group in config.ShadowConfigurations.Groups)
834  groupCount += (group.ShadowCount > 0 ? 1 : 0);
835 
836  if (groupCount == 0)
837  {
838  parameters.Remove(ShadowMapParameters.ShadowMaps);
839  return;
840  }
841 
842  var shadowMapParameters = new ShadowMapParameters[groupCount];
843  var index = 0;
844  for (var i = 0; i < config.ShadowConfigurations.Groups.Count; ++i)
845  {
846  if (config.ShadowConfigurations.Groups[i].ShadowCount > 0)
847  {
848  var shadowParams = new ShadowMapParameters();
849  shadowParams.Set(ShadowMapParameters.LightType, config.ShadowConfigurations.Groups[i].LightType);
850  shadowParams.Set(ShadowMapParameters.ShadowMapCount, config.ShadowConfigurations.Groups[i].ShadowCount);
851  shadowParams.Set(ShadowMapParameters.ShadowMapCascadeCount, config.ShadowConfigurations.Groups[i].CascadeCount);
852  shadowParams.Set(ShadowMapParameters.FilterType, config.ShadowConfigurations.Groups[i].FilterType);
853  shadowMapParameters[index] = shadowParams;
854  ++index;
855  }
856  }
857  parameters.Set(ShadowMapParameters.ShadowMaps, shadowMapParameters);
858  }
859  else
860  parameters.Remove(ShadowMapParameters.ShadowMaps);
861 
862  //mesh.Parameters.Set(LightingKeys.UnrollDirectionalLightLoop, foundConfiguration.UnrollDirectionalLightLoop);
863  //mesh.Parameters.Set(LightingKeys.UnrollPointLightLoop, foundConfiguration.UnrollPointLightLoop);
864  //mesh.Parameters.Set(LightingKeys.UnrollSpotLightLoop, foundConfiguration.UnrollSpotLightLoop);
865  }
866 
867  #endregion
868  }
869 
870  public struct LightGroup
871  {
872  public Dictionary<ParameterKey, LightParamSemantic> LightingParameterSemantics;
873 
874  public LightGroup(int index, string compositionName)
875  {
876  LightingParameterSemantics = new Dictionary<ParameterKey, LightParamSemantic>();
877  var lightGroupSubKey = string.Format("." + compositionName + "[{0}]", index);
878  foreach (var param in LightForwardModelRenderer.LightParametersDict)
879  {
880  LightingParameterSemantics.Add(ParameterKeys.AppendKey(param.Key, lightGroupSubKey), param.Value);
881  }
882  }
883  }
884 }
Add a light to an Entity, that will be used during rendering.
Dictionary< ParameterKey, LightParamSemantic > LightingParameterSemantics
Represents a color in the form of rgb.
Definition: Color3.cs:41
Represents a shadow map for the ShadowMapRenderer.
Definition: ShadowMap.cs:15
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
A service registry is a IServiceProvider that provides methods to register and unregister services...
Flags
Enumeration of the new Assimp's flags.
_In_ size_t count
Definition: DirectXTexP.h:174
Structure using the same layout than System.Drawing.Point.
Definition: Point.cs:35
SiliconStudio.Core.Mathematics.Color Color
Definition: ColorPicker.cs:14
Manage a collection of entities.
Definition: EntitySystem.cs:22
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
Definition: Texture2D.cs:37
System.Windows.Point Point
Definition: ColorPicker.cs:15
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47