Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
LightingPrepassRenderer.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 using SiliconStudio.Paradox.Shaders.Compiler;
16 
18 
19 namespace SiliconStudio.Paradox.Effects.Modules.Renderers
20 {
22  {
23  #region Static members
24 
25  /// <summary>
26  /// The key linking the parameters of each point light.
27  /// </summary>
28  public static readonly ParameterKey<PointLightData[]> PointLightInfos = ParameterKeys.New(new PointLightData[64]);
29 
30  /// <summary>
31  /// The key linking the parameters of each directional light.
32  /// </summary>
33  public static readonly ParameterKey<DirectLightData[]> DirectLightInfos = ParameterKeys.New(new DirectLightData[64]);
34 
35  /// <summary>
36  /// The key linking the parameters of each spot light.
37  /// </summary>
38  public static readonly ParameterKey<SpotLightData[]> SpotLightInfos = ParameterKeys.New(new SpotLightData[64]);
39 
40  /// <summary>
41  /// The key setting the number of lights.
42  /// </summary>
43  public static readonly ParameterKey<int> LightCount = ParameterKeys.New(64);
44 
45  #endregion
46 
47  #region Internal static members
48 
49  internal static Dictionary<ParameterKey, LightingDeferredSemantic> LightParametersDict = new Dictionary<ParameterKey, LightingDeferredSemantic>
50  {
51  { LightingPrepassRenderer.PointLightInfos, LightingDeferredSemantic.PointLightInfos },
52  { DeferredPointLightingKeys.LightAttenuationCutoff, LightingDeferredSemantic.LightAttenuationCutoff },
53  { LightingPrepassRenderer.DirectLightInfos, LightingDeferredSemantic.DirectLightInfos },
54  { LightingPrepassRenderer.SpotLightInfos, LightingDeferredSemantic.SpotLightInfos },
55  { LightingPrepassRenderer.LightCount, LightingDeferredSemantic.LightCount }
56  };
57 
58  #endregion
59 
60  #region Constant values
61 
62  public const int TileCountX = 16;
63 
64  public const int TileCountY = 10;
65 
66  public const float AttenuationCutoff = 0.1f;
67 
68  // TODO: make this configurable or extract from the effect
69  public const int MaxPointLightsPerTileDrawCall = 64;
70 
71  public const int MaxDirectLightsPerTileDrawCall = 1;
72 
73  public const int MaxSpotLightsPerTileDrawCall = 1;
74 
75  public const int MaxSpotShadowLightsPerTileDrawCall = 1;
76 
77  public const int MaxDirectShadowLightsPerTileDrawCall = 1;
78 
79  #endregion
80 
81  #region Private members
82 
83  private string effectName;
84 
85  private ShadowMapReceiverInfo[] receiverInfos;
86 
87  private ShadowMapReceiverVsmInfo[] receiverVsmInfos;
88 
89  private ShadowMapCascadeReceiverInfo[] cascadeInfos;
90 
91  private ParameterCollection[] effectParameterCollections;
92 
93  private List<EntityLightShadow> validLights;
94 
95  private List<EntityLightShadow> pointLights;
96 
97  private List<EntityLightShadow> spotLights;
98 
99  private List<EntityLightShadow> spotShadowLights;
100 
101  private List<EntityLightShadow> directionalLights;
102 
103  private List<EntityLightShadow> directionalShadowLights;
104 
105  private List<PointLightData> pointLightDatas;
106 
107  private List<SpotLightData> spotLightDatas;
108 
109  private List<DirectLightData> directionalLightDatas;
110 
111  private Dictionary<int, List<int>> regroupedTiles;
112 
113  private List<PointLightData>[] tilesGroups = new List<PointLightData>[TileCountX * TileCountY];
114 
115  private PointLightData[] currentPointLights = new PointLightData[MaxPointLightsPerTileDrawCall];
116 
117  private SpotLightData[] currentSpotLights = new SpotLightData[MaxSpotLightsPerTileDrawCall];
118 
119  private SpotLightData[] currentSpotShadowLights = new SpotLightData[MaxSpotShadowLightsPerTileDrawCall];
120 
121  private DirectLightData[] currentDirectLights = new DirectLightData[MaxDirectLightsPerTileDrawCall];
122 
123  private DirectLightData[] currentDirectShadowLights = new DirectLightData[MaxDirectShadowLightsPerTileDrawCall];
124 
125  private RenderTarget lightRenderTarget;
126 
127  private BlendState accumulationBlendState;
128 
129  private Effect pointLightingPrepassEffect;
130 
131  private Effect spotLightingPrepassEffect;
132 
133  private Effect directLightingPrepassEffect;
134 
135  private Dictionary<ShadowEffectInfo, Effect> shadowEffects;
136 
137  private Dictionary<ShadowEffectInfo, List<EntityLightShadow>> shadowLights;
138 
139  private Dictionary<ShadowEffectInfo, List<DirectLightData>> directShadowLightDatas;
140 
141  private Dictionary<ShadowEffectInfo, List<SpotLightData>> spotShadowLightDatas;
142 
143  private Dictionary<Effect, LightingDeferredParameters[]> lightingConfigurationsPerEffect;
144 
145  private Dictionary<ParameterKey, LightingDeferredSemantic> lightingParameterSemantics;
146 
147  private VertexArrayObject vertexArrayObject;
148 
149  private MeshDraw meshDraw;
150 
151  // External references
152  private Texture2D depthStencilTexture;
153 
154  // External references
155  private Texture2D gbufferTexture;
156 
157  #endregion
158 
159  #region Contructor
160 
161  /// <summary>
162  /// LightPrepassRenderer constructor.
163  /// </summary>
164  /// <param name="services">The services.</param>
165  /// <param name="effectName">The name of the effect used to compute lighting.</param>
166  /// <param name="depthStencilTexture">The depth texture.</param>
167  /// <param name="gbufferTexture">The gbuffer texture.</param>
168  public LightingPrepassRenderer(IServiceRegistry services, string effectName, Texture2D depthStencilTexture, Texture2D gbufferTexture)
169  : base(services)
170  {
171  validLights = new List<EntityLightShadow>();
172  pointLights = new List<EntityLightShadow>();
173  spotLights = new List<EntityLightShadow>();
174  spotShadowLights = new List<EntityLightShadow>();
175  directionalLights = new List<EntityLightShadow>();
176  directionalShadowLights = new List<EntityLightShadow>();
177  pointLightDatas = new List<PointLightData>();
178  spotLightDatas = new List<SpotLightData>();
179  directionalLightDatas = new List<DirectLightData>();
180  regroupedTiles = new Dictionary<int, List<int>>();
181  lightingConfigurationsPerEffect = new Dictionary<Effect, LightingDeferredParameters[]>();
182  lightingParameterSemantics = new Dictionary<ParameterKey, LightingDeferredSemantic>();
183  shadowEffects = new Dictionary<ShadowEffectInfo, Effect>();
184  shadowLights = new Dictionary<ShadowEffectInfo, List<EntityLightShadow>>();
185  directShadowLightDatas = new Dictionary<ShadowEffectInfo, List<DirectLightData>>();
186  spotShadowLightDatas = new Dictionary<ShadowEffectInfo, List<SpotLightData>>();
187 
188  receiverInfos = new ShadowMapReceiverInfo[4];
189  receiverVsmInfos = new ShadowMapReceiverVsmInfo[4];
190  cascadeInfos = new ShadowMapCascadeReceiverInfo[16];
191  effectParameterCollections = new ParameterCollection[2];
192 
193  this.effectName = effectName;
194  this.depthStencilTexture = depthStencilTexture;
195  this.gbufferTexture = gbufferTexture;
196  DebugName = string.Format("LightingPrepass [{0}]", effectName);
197  }
198 
199  #endregion
200 
201  #region Public methods
202 
203  /// <inheritdoc/>
204  public override void Load()
205  {
206  base.Load();
207 
208  // Initialize tile groups
209  for (int i = 0; i < tilesGroups.Length; ++i)
210  tilesGroups[i] = new List<PointLightData>();
211 
212  pointLightingPrepassEffect = EffectSystem.LoadEffect(effectName + ".ParadoxPointPrepassLighting");
213  CreateLightingUpdateInfo(pointLightingPrepassEffect);
214 
215  spotLightingPrepassEffect = EffectSystem.LoadEffect(effectName + ".ParadoxSpotPrepassLighting");
216  CreateLightingUpdateInfo(spotLightingPrepassEffect);
217 
218  // TODO: find a way to enumerate available shaders
219  /*var parameters = new CompilerParameters();
220  for (var i = 2; i <= 64; i = i + 62)
221  {
222  parameters.Set(LightingKeys.MaxDeferredLights, i);
223  var effect = EffectSystem.LoadEffect("LightPrepassEffect", parameters);
224  lightPrepassEffects.Add(i, effect);
225  lightConfigurations.Add(i);
226 
227  CreateLightingUpdateInfo(effect);
228  }*/
229 
230  // directional lights
231  directLightingPrepassEffect = EffectSystem.LoadEffect(effectName + ".ParadoxDirectPrepassLighting");
232  CreateLightingUpdateInfo(directLightingPrepassEffect);
233 
234  // shadow lights
235  var parameters = new CompilerParameters();
236  for (var cascadeCount = 1; cascadeCount < 5; ++cascadeCount)
237  {
238  AddShadowEffect(cascadeCount, ShadowMapFilterType.Nearest, parameters);
239  AddShadowEffect(cascadeCount, ShadowMapFilterType.PercentageCloserFiltering, parameters);
240  AddShadowEffect(cascadeCount, ShadowMapFilterType.Variance, parameters);
241  }
242 
243  // Create lighting accumulation texture
244  var lightTexture = Texture2D.New(GraphicsDevice, GraphicsDevice.BackBuffer.Width, GraphicsDevice.BackBuffer.Height, PixelFormat.R16G16B16A16_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget);
245  lightRenderTarget = lightTexture.ToRenderTarget();
246 
247  // Set GBuffer and depth stencil as input, as well as light texture
248  Pass.Parameters.Set(RenderTargetKeys.DepthStencilSource, depthStencilTexture);
249  Pass.Parameters.Set(GBufferBaseKeys.GBufferTexture, gbufferTexture);
250  Pass.Parameters.Set(LightDeferredShadingKeys.LightTexture, lightTexture);
251 
252  // Generates a quad for post effect rendering (should be utility function)
253  var vertices = new[]
254  {
255  -1.0f, 1.0f,
256  1.0f, 1.0f,
257  -1.0f, -1.0f,
258  1.0f, -1.0f,
259  };
260 
261  // Create the quad used for tile rendering
262  meshDraw = new MeshDraw
263  {
264  DrawCount = 4,
265  PrimitiveType = PrimitiveType.TriangleStrip,
266  VertexBuffers = new[]
267  {
268  new VertexBufferBinding(Buffer.Vertex.New(GraphicsDevice, vertices), new VertexDeclaration(VertexElement.Position<Vector2>()), 4)
269  }
270  };
271 
272  // TODO: fix the effect signature (not safe here)
273  // Prepare VAO
274  vertexArrayObject = VertexArrayObject.New(GraphicsDevice, pointLightingPrepassEffect.InputSignature, meshDraw.VertexBuffers);
275 
276  // Prepare blend state used for second pass (accumulation)
277  var blendStateDesc = new BlendStateDescription();
278  blendStateDesc.SetDefaults();
279  blendStateDesc.AlphaToCoverageEnable = false;
280  blendStateDesc.IndependentBlendEnable = false;
281  blendStateDesc.RenderTargets[0].BlendEnable = true;
282 
283  blendStateDesc.RenderTargets[0].AlphaBlendFunction = BlendFunction.Add;
284  blendStateDesc.RenderTargets[0].AlphaSourceBlend = Blend.One;
285  blendStateDesc.RenderTargets[0].AlphaDestinationBlend = Blend.One;
286 
287  blendStateDesc.RenderTargets[0].ColorBlendFunction = BlendFunction.Add;
288  blendStateDesc.RenderTargets[0].ColorSourceBlend = Blend.One;
289  blendStateDesc.RenderTargets[0].ColorDestinationBlend = Blend.One;
290 
291  blendStateDesc.RenderTargets[0].ColorWriteChannels = ColorWriteChannels.All;
292 
293  accumulationBlendState = BlendState.New(GraphicsDevice, blendStateDesc);
294  }
295 
296  /// <inheritdoc/>
297  public override void Unload()
298  {
299  base.Unload();
300 
301  lightRenderTarget.Dispose();
302  lightRenderTarget.Texture.Dispose();
303  lightRenderTarget = null;
304  }
305 
306  #endregion
307 
308  #region Private methods
309 
310  private void AddShadowEffect(int cascadeCount, ShadowMapFilterType filterType, CompilerParameters parameters)
311  {
312  parameters.Set(ShadowMapParameters.ShadowMapCascadeCount, cascadeCount);
313  parameters.Set(ShadowMapParameters.FilterType, filterType);
314 
315  //////////////////////////////////////////////
316  // DIRECTIONAL LIGHT
317  parameters.Set(ShadowMapParameters.LightType, LightType.Directional);
318 
319  ShadowEffectInfo seiDirect;
320  seiDirect.LightType = LightType.Directional;
321  seiDirect.CascadeCount = cascadeCount;
322  seiDirect.Filter = filterType;
323  AddEffect(seiDirect, cascadeCount, parameters, directShadowLightDatas);
324 
325  //////////////////////////////////////////////
326  // SPOT LIGHT
327  parameters.Set(ShadowMapParameters.LightType, LightType.Spot);
328 
329  ShadowEffectInfo seiSpot;
330  seiSpot.LightType = LightType.Spot;
331  seiSpot.CascadeCount = cascadeCount;
332  seiSpot.Filter = filterType;
333 
334  AddEffect(seiSpot, cascadeCount, parameters, spotShadowLightDatas);
335  }
336 
337  private void AddEffect<T>(ShadowEffectInfo sei, int cascadeCount, CompilerParameters parameters, Dictionary<ShadowEffectInfo, List<T>> lightDatas)
338  {
339  var effect = EffectSystem.LoadEffect(effectName + ".ParadoxShadowPrepassLighting", parameters);
340  var lightingGroupInfo = CreateLightingUpdateInfo(effect);
341  lightingGroupInfo.ShadowParameters = new List<ShadowUpdateInfo>
342  {
343  LightingProcessorHelpers.CreateShadowUpdateInfo(0, cascadeCount)
344  };
345 
346  shadowEffects.Add(sei, effect);
347  shadowLights.Add(sei, new List<EntityLightShadow>());
348  lightDatas.Add(sei, new List<T>());
349  }
350 
351  /// <summary>
352  /// Update light lists and choose the new light configuration.
353  /// </summary>
354  /// <param name="context">The render context.</param>
355  private void UpdateLightDatas(RenderContext context)
356  {
357  // get the lightprocessor
358  var entitySystem = Services.GetServiceAs<EntitySystem>();
359  if (entitySystem == null)
360  return;
361  var lightProcessor = entitySystem.GetProcessor<LightShadowProcessor>();
362  if (lightProcessor == null)
363  return;
364 
365  // TODO: better detection of shadows?
366  var hasShadowRenderer = RenderSystem.Pipeline.GetProcessor<ShadowMapRenderer>() != null;
367 
368  // filter out the non-deferred lights
369  foreach (var light in lightProcessor.Lights)
370  {
371  if (light.Value.Light.Deferred && light.Value.Light.Enabled)
372  {
373  validLights.Add(light.Value);
374 
375  switch (light.Value.Light.Type)
376  {
377  case LightType.Point:
378  pointLights.Add(light.Value);
379  break;
380  case LightType.Spherical:
381  break;
382  case LightType.Directional:
383  if (hasShadowRenderer && light.Value.HasShadowMap && lightProcessor.ActiveShadowMaps.Contains(light.Value.ShadowMap))
384  directionalShadowLights.Add(light.Value);
385  else
386  directionalLights.Add(light.Value);
387  break;
388  case LightType.Spot:
389  if (hasShadowRenderer && light.Value.HasShadowMap && lightProcessor.ActiveShadowMaps.Contains(light.Value.ShadowMap))
390  spotShadowLights.Add(light.Value);
391  else
392  spotLights.Add(light.Value);
393  break;
394  }
395  }
396  }
397 
398  foreach (var light in pointLights)
399  {
400  PointLightData data;
401  data.DiffuseColor = light.Light.Color;
402  // TODO: Linearize intensity
403  data.LightIntensity = light.Light.Intensity;//(float)Math.Pow(light.Light.Intensity, 2.2f);
404  data.LightPosition = new Vector3(light.Entity.Transformation.WorldMatrix.M41, light.Entity.Transformation.WorldMatrix.M42, light.Entity.Transformation.WorldMatrix.M43);
405  data.LightPosition /= light.Entity.Transformation.WorldMatrix.M44;
406  data.LightRadius = light.Light.DecayStart;
407 
408  // TODO: Linearize color
409  //data.DiffuseColor.Pow(2.2f);
410 
411  pointLightDatas.Add(data);
412  }
413 
414  foreach (var light in directionalLights)
415  directionalLightDatas.Add(GetDirectLightData(light));
416 
417  foreach (var light in directionalShadowLights)
418  {
419  ShadowEffectInfo sei;
420  sei.LightType = LightType.Directional;
421  sei.CascadeCount = light.Light.ShadowMapCascadeCount;
422  sei.Filter = light.Light.ShadowMapFilterType;
423 
424  List<DirectLightData> dataList;
425  if (directShadowLightDatas.TryGetValue(sei, out dataList))
426  {
427  dataList.Add(GetDirectLightData(light));
428  shadowLights[sei].Add(light);
429  }
430  }
431 
432  foreach (var light in spotLights)
433  spotLightDatas.Add(GetSpotLightData(light));
434 
435  foreach (var light in spotShadowLights)
436  {
437  ShadowEffectInfo sei;
438  sei.LightType = LightType.Spot;
439  sei.CascadeCount = light.Light.ShadowMapCascadeCount;
440  sei.Filter = light.Light.ShadowMapFilterType;
441 
442  List<SpotLightData> dataList;
443  if (spotShadowLightDatas.TryGetValue(sei, out dataList))
444  {
445  dataList.Add(GetSpotLightData(light));
446  shadowLights[sei].Add(light);
447  }
448  }
449  }
450 
451 
452 
453  /// <summary>
454  /// Clear the lists.
455  /// </summary>
456  /// <param name="context">The render context.</param>
457  private void EndRender(RenderContext context)
458  {
459  validLights.Clear();
460  pointLights.Clear();
461  spotLights.Clear();
462  spotShadowLights.Clear();
463  directionalLights.Clear();
464  directionalShadowLights.Clear();
465  pointLightDatas.Clear();
466  spotLightDatas.Clear();
467  directionalLightDatas.Clear();
468 
469  foreach(var lightList in shadowLights)
470  lightList.Value.Clear();
471  foreach (var dataList in directShadowLightDatas)
472  dataList.Value.Clear();
473  foreach (var dataList in spotShadowLightDatas)
474  dataList.Value.Clear();
475 
476  regroupedTiles.Clear();
477  lightingParameterSemantics.Clear();
478  }
479 
480  /*private void RegroupTilesPerShader()
481  {
482  var maxLightCountperTile = new int[tilesGroups.Length];
483 
484  for (var tileIndex = 0; tileIndex < tilesGroups.Length; ++tileIndex)
485  {
486  int lightsInShader = lightConfigurations[lightConfigurations.Count - 1];
487  foreach (var config in lightConfigurations)
488  {
489  if (config >= tilesGroups[tileIndex].Count)
490  {
491  lightsInShader = config;
492  break;
493  }
494  }
495  maxLightCountperTile[tileIndex] = lightsInShader;
496  }
497 
498  for (var tileIndex = 0; tileIndex < tilesGroups.Length; ++tileIndex)
499  {
500  var lightCount = maxLightCountperTile[tileIndex];
501  if (!regroupedTiles.ContainsKey(lightCount))
502  regroupedTiles.Add(lightCount, new List<int>());
503  regroupedTiles[lightCount].Add(tileIndex);
504  }
505  }*/
506 
507  protected override void OnRendering(RenderContext context)
508  {
509  // update the effects
510  CreateLightingUpdateInfo(pointLightingPrepassEffect);
511  CreateLightingUpdateInfo(spotLightingPrepassEffect);
512  CreateLightingUpdateInfo(directLightingPrepassEffect);
513  foreach (var shadowEffect in shadowEffects)
514  CreateLightingUpdateInfo(shadowEffect.Value);
515 
516  // update the list of lights
517  UpdateLightDatas(context);
518 
519  // if there is no light, use albedo
520  if (pointLights.Count == 0 && spotLights.Count == 0 && directionalLights.Count == 0 && directionalShadowLights.Count == 0 && spotShadowLights.Count == 0)
521  {
522  GraphicsDevice.Clear(lightRenderTarget, new Color4(1.0f, 1.0f, 1.0f, 0.0f));
523  }
524  else
525  {
526  // Clear and set light accumulation target
527  GraphicsDevice.Clear(lightRenderTarget, new Color4(0.0f, 0.0f, 0.0f, 0.0f));
528  GraphicsDevice.SetRenderTarget(lightRenderTarget); // no depth buffer
529  // TODO: make sure that the lightRenderTarget.Texture is not bound to any shader to prevent some warnings
530 
531  // Set default blend state
532  GraphicsDevice.SetBlendState(null);
533 
534  // set default depth stencil test
535  GraphicsDevice.SetDepthStencilState(GraphicsDevice.DepthStencilStates.None);
536 
537  // TODO: remove this?
538  // override specular intensity
539  context.Parameters.Set(MaterialKeys.SpecularIntensity, 1.0f);
540 
541  UpdateTiles(Pass.Parameters);
542 
543  // direct lighting
544  var hasPreviousLighting = RenderTileForDirectLights(context);
545 
546  // spot lights
547  hasPreviousLighting |= RenderTileForSpotLights(context, hasPreviousLighting);
548 
549  // lighting with shadows
550  foreach (var lightList in shadowLights)
551  {
552  if (lightList.Value.Count > 0)
553  {
554  var effect = shadowEffects[lightList.Key];
555  // direct light or spot light
556  if ((lightList.Key.LightType == LightType.Directional && RenderTileForDirectShadowLights(context, hasPreviousLighting, effect, lightList.Value, directShadowLightDatas[lightList.Key], lightList.Key.Filter == ShadowMapFilterType.Variance))
557  || lightList.Key.LightType == LightType.Spot && RenderTileForSpotShadowLights(context, hasPreviousLighting, effect, lightList.Value, spotShadowLightDatas[lightList.Key], lightList.Key.Filter == ShadowMapFilterType.Variance))
558  {
559  effect.UnbindResources();
560  hasPreviousLighting = true;
561  }
562  }
563  }
564 
565  // point lights
566  RenderTilesForPointLights(context, hasPreviousLighting);
567 
568  // Reset default blend state
569  GraphicsDevice.SetBlendState(null);
570  }
571 
572  // reset the light infos
573  EndRender(context);
574 
575  // TDO: remove this
576  // Reset some values
577  context.Parameters.Reset(MaterialKeys.SpecularIntensity);
578  }
579 
580  private void SetDirectLightParameters(RenderContext context, Effect effect, DirectLightData[] data, int lightCount)
581  {
582  LightingDeferredParameters[] deferredParameters = null;
583  if (lightingConfigurationsPerEffect.TryGetValue(effect, out deferredParameters))
584  {
585  foreach (var deferredParam in deferredParameters)
586  {
587  if ((deferredParam.Semantic & LightingDeferredSemantic.DirectLightInfos) != 0)
588  context.Parameters.Set(deferredParam.DirectLightInfosKey, data);
589  if ((deferredParam.Semantic & LightingDeferredSemantic.LightCount) != 0)
590  context.Parameters.Set(deferredParam.LightCountKey, lightCount);
591  }
592  }
593  }
594 
595  private void SetSpotLightParameters(RenderContext context, Effect effect, SpotLightData[] data, int lightCount)
596  {
597  LightingDeferredParameters[] deferredParameters = null;
598  if (lightingConfigurationsPerEffect.TryGetValue(effect, out deferredParameters))
599  {
600  foreach (var deferredParam in deferredParameters)
601  {
602  if ((deferredParam.Semantic & LightingDeferredSemantic.SpotLightInfos) != 0)
603  context.Parameters.Set(deferredParam.SpotLightInfosKey, data);
604  if ((deferredParam.Semantic & LightingDeferredSemantic.LightCount) != 0)
605  context.Parameters.Set(deferredParam.LightCountKey, lightCount);
606  }
607  }
608  }
609 
610  private int SetCascadeInfo(List<EntityLightShadow> lights, int startLightIndex, int lightIndex, int cascadeCount, ShadowUpdateInfo shadowUpdateInfo)
611  {
612  var shadowLight = lights[startLightIndex + lightIndex];
613  receiverInfos[lightIndex] = shadowLight.ShadowMap.ReceiverInfo;
614  receiverVsmInfos[lightIndex] = shadowLight.ShadowMap.ReceiverVsmInfo;
615  for (var cascade = 0; cascade < shadowUpdateInfo.CascadeCount; ++cascade)
616  cascadeInfos[cascadeCount + cascade] = shadowLight.ShadowMap.Cascades[cascade].ReceiverInfo;
617 
618  return cascadeCount + shadowUpdateInfo.CascadeCount;
619  }
620 
621  private void RenderTile(RenderContext context, Effect effect, bool hasPreviousDraw, int currentDrawIndex)
622  {
623  // Render this tile (we only need current pass and context parameters)
624  effectParameterCollections[0] = context.CurrentPass.Parameters;
625  effectParameterCollections[1] = context.Parameters;
626 
627  // Apply effect & parameters
628  effect.Apply(effectParameterCollections);
629 
630  // the blend state is null at the beginning of the renderer. We should switch to accumulation blend state at the second render.
631  // Any further render do not need to switch the blend state since it is already corerctly set.
632  if (!hasPreviousDraw && currentDrawIndex == 1)
633  GraphicsDevice.SetBlendState(accumulationBlendState);
634 
635  // Set VAO and draw tile
636  GraphicsDevice.SetVertexArrayObject(vertexArrayObject);
637  GraphicsDevice.Draw(meshDraw.PrimitiveType, meshDraw.DrawCount, meshDraw.StartLocation);
638  }
639 
640  private void RenderShadowLight(RenderContext context, List<EntityLightShadow> lights, int startLightIndex, int lightCount, int cascadeCount, bool varianceShadowMap, bool hasPreviousDraw, int currentDrawIndex, ShadowUpdateInfo shadowUpdateInfo, Effect effect)
641  {
642  // update shadow parameters
643  context.Parameters.Set((ParameterKey<ShadowMapReceiverInfo[]>)shadowUpdateInfo.ShadowMapReceiverInfoKey, receiverInfos, 0, lightCount);
644  context.Parameters.Set((ParameterKey<ShadowMapCascadeReceiverInfo[]>)shadowUpdateInfo.ShadowMapLevelReceiverInfoKey, cascadeInfos, 0, cascadeCount);
645  context.Parameters.Set(shadowUpdateInfo.ShadowMapLightCountKey, lightCount);
646  // TODO: change texture set when multiple shadow maps will be handled.
647  if (varianceShadowMap)
648  context.Parameters.Set(shadowUpdateInfo.ShadowMapTextureKey, lights[startLightIndex].ShadowMap.Texture.ShadowMapTargetTexture);
649  else
650  context.Parameters.Set(shadowUpdateInfo.ShadowMapTextureKey, lights[startLightIndex].ShadowMap.Texture.ShadowMapDepthTexture);
651 
652  RenderTile(context, effect, hasPreviousDraw, currentDrawIndex);
653  }
654 
655  private bool RenderTileForDirectLights(RenderContext context)
656  {
657  // only one tile since the directional lights affects the whole screen
658  context.Parameters.Set(DeferredTiledShaderKeys.TileCountX, 1);
659  context.Parameters.Set(DeferredTiledShaderKeys.TileCountY, 1);
660  context.Parameters.Set(DeferredTiledShaderKeys.TileIndex, 0);
661 
662  int directLightCount = directionalLightDatas.Count;
663 
664  int drawCount = (directLightCount + MaxDirectLightsPerTileDrawCall - 1) / MaxDirectLightsPerTileDrawCall;
665  var startLightIndex = 0;
666 
667  for (int currentDrawIndex = 0; currentDrawIndex < drawCount; ++currentDrawIndex)
668  {
669  int lightCount = Math.Min(directLightCount - startLightIndex, MaxDirectLightsPerTileDrawCall);
670 
671  // prepare directional light datas
672  for (int lightIndex = 0; lightIndex < lightCount; ++lightIndex)
673  currentDirectLights[lightIndex] = directionalLightDatas[startLightIndex + lightIndex];
674 
675  // Set data for shader
676  SetDirectLightParameters(context, directLightingPrepassEffect, currentDirectLights, lightCount);
677 
678  RenderTile(context, directLightingPrepassEffect, false, currentDrawIndex);
679 
680  startLightIndex += MaxDirectLightsPerTileDrawCall;
681  }
682 
683  if (drawCount > 0)
684  {
685  directLightingPrepassEffect.UnbindResources();
686  return true;
687  }
688 
689  return false;
690  }
691 
692  private bool RenderTileForDirectShadowLights(RenderContext context, bool hasPreviousDraw, Effect effect, List<EntityLightShadow> lights, List<DirectLightData> lightDatas, bool varianceShadowMap)
693  {
694  // only one tile since the directional lights affects the whole screen
695  context.Parameters.Set(DeferredTiledShaderKeys.TileCountX, 1);
696  context.Parameters.Set(DeferredTiledShaderKeys.TileCountY, 1);
697  context.Parameters.Set(DeferredTiledShaderKeys.TileIndex, 0);
698 
699  int directShadowLightCount = lightDatas.Count;
700 
701  if (hasPreviousDraw)
702  GraphicsDevice.SetBlendState(accumulationBlendState);
703 
704  int drawCount = (directShadowLightCount + MaxDirectShadowLightsPerTileDrawCall - 1) / MaxDirectShadowLightsPerTileDrawCall;
705  var startLightIndex = 0;
706 
707  // TODO: change that to handle mutiple shadow maps in the same shader - works now since the shader only render with 1 shadow map at a time.
708  var lightingGroupInfo = LightingGroupInfo.GetOrCreate(effect);
709  var shadowUpdateInfo = lightingGroupInfo.ShadowParameters[0];
710 
711  for (int i = 0; i < drawCount; ++i)
712  {
713  int lightCount = Math.Min(directShadowLightCount - startLightIndex, MaxDirectShadowLightsPerTileDrawCall);
714  var cascadeCount = 0;
715  // prepare directional shadow light datas
716  for (int lightIndex = 0; lightIndex < lightCount; ++lightIndex)
717  {
718  currentDirectShadowLights[lightIndex] = lightDatas[startLightIndex + lightIndex];
719  cascadeCount = SetCascadeInfo(lights, startLightIndex, lightIndex, cascadeCount, shadowUpdateInfo);
720  }
721 
722  // Set data for shader
723  SetDirectLightParameters(context, effect, currentDirectShadowLights, lightCount);
724 
725  RenderShadowLight(context, lights, startLightIndex, lightCount, cascadeCount, varianceShadowMap, hasPreviousDraw, i, shadowUpdateInfo, effect);
726 
727  startLightIndex += MaxDirectShadowLightsPerTileDrawCall;
728  }
729 
730  return (drawCount > 0);
731  }
732 
733  private bool RenderTileForSpotShadowLights(RenderContext context, bool hasPreviousDraw, Effect effect, List<EntityLightShadow> lights, List<SpotLightData> lightDatas, bool varianceShadowMap)
734  {
735  // TODO: look for tiles covered by spot lights
736  // only one tile for spot lights for now
737  context.Parameters.Set(DeferredTiledShaderKeys.TileCountX, 1);
738  context.Parameters.Set(DeferredTiledShaderKeys.TileCountY, 1);
739  context.Parameters.Set(DeferredTiledShaderKeys.TileIndex, 0);
740 
741  int spotShadowLightCount = lightDatas.Count;
742 
743  if (hasPreviousDraw)
744  GraphicsDevice.SetBlendState(accumulationBlendState);
745 
746  int drawCount = (spotShadowLightCount + MaxSpotShadowLightsPerTileDrawCall - 1) / MaxSpotShadowLightsPerTileDrawCall;
747  var startLightIndex = 0;
748 
749  // TODO: change that to handle mutiple shadow maps in the same shader - works now since the shader only render with 1 shadow map at a time.
750  var lightGroupInfo = LightingGroupInfo.GetOrCreate(effect);
751  var shadowUpdateInfo = lightGroupInfo.ShadowParameters[0];
752 
753  for (int i = 0; i < drawCount; ++i)
754  {
755  int lightCount = Math.Min(spotShadowLightCount - startLightIndex, MaxSpotShadowLightsPerTileDrawCall);
756  int cascadeCount = 0;
757  // prepare spot shadow light datas
758  for (int lightIndex = 0; lightIndex < lightCount; ++lightIndex)
759  {
760  currentSpotShadowLights[lightIndex] = lightDatas[startLightIndex + lightIndex];
761  cascadeCount = SetCascadeInfo(lights, startLightIndex, lightIndex, cascadeCount, shadowUpdateInfo);
762  }
763 
764  // Set data for shader
765  SetSpotLightParameters(context, effect, currentSpotShadowLights, lightCount);
766 
767  RenderShadowLight(context, lights, startLightIndex, lightCount, cascadeCount, varianceShadowMap, hasPreviousDraw, i, shadowUpdateInfo, effect);
768 
769  startLightIndex += MaxSpotShadowLightsPerTileDrawCall;
770  }
771 
772  if (drawCount > 0)
773  {
774  effect.UnbindResources();
775  return true;
776  }
777 
778  return false;
779  }
780 
781  private bool RenderTileForSpotLights(RenderContext context, bool hasPreviousDraw)
782  {
783  // TODO: look for tiles covered by spot lights
784  // only one tile for spot lights for now
785  context.Parameters.Set(DeferredTiledShaderKeys.TileCountX, 1);
786  context.Parameters.Set(DeferredTiledShaderKeys.TileCountY, 1);
787  context.Parameters.Set(DeferredTiledShaderKeys.TileIndex, 0);
788 
789  int spotLightCount = spotLightDatas.Count;
790 
791  if (hasPreviousDraw)
792  GraphicsDevice.SetBlendState(accumulationBlendState);
793 
794  int drawCount = (spotLightCount + MaxSpotLightsPerTileDrawCall - 1) / MaxSpotLightsPerTileDrawCall;
795  var startLightIndex = 0;
796 
797  for (int currentDrawIndex = 0; currentDrawIndex < drawCount; ++currentDrawIndex)
798  {
799  int lightCount = Math.Min(spotLightCount - startLightIndex, MaxSpotLightsPerTileDrawCall);
800 
801  // prepare spotlight datas
802  for (int lightIndex = 0; lightIndex < lightCount; ++lightIndex)
803  currentSpotLights[lightIndex] = spotLightDatas[startLightIndex + lightIndex];
804 
805  // Set data for shader
806  SetSpotLightParameters(context, spotLightingPrepassEffect, currentSpotLights, lightCount);
807 
808  RenderTile(context, spotLightingPrepassEffect, hasPreviousDraw, currentDrawIndex);
809 
810  startLightIndex += MaxSpotLightsPerTileDrawCall;
811  }
812 
813  if (drawCount > 0)
814  {
815  spotLightingPrepassEffect.UnbindResources();
816  return true;
817  }
818 
819  return false;
820  }
821 
822  private void RenderTilesForPointLights(RenderContext context, bool hasPreviousDraw)
823  {
824  context.Parameters.Set(DeferredTiledShaderKeys.TileCountX, TileCountX);
825  context.Parameters.Set(DeferredTiledShaderKeys.TileCountY, TileCountY);
826 
827  var hasDrawn = false;
828 
829  for (var tileIndex = 0; tileIndex < TileCountX * TileCountY; ++tileIndex)
830  {
831  var tilesGroup = this.tilesGroups[tileIndex];
832 
833  /*var lastEffect = lightPrepassEffects.Last();
834  var effect = lastEffect.Value;
835  var maxLightCount = lastEffect.Key;
836  foreach (var effectKP in lightPrepassEffects)
837  {
838  if (effectKP.Key >= tilesGroup.Count)
839  {
840  effect = effectKP.Value;
841  maxLightCount = effectKP.Key;
842  }
843  }*/
844 
845  // Set tile index
846  context.Parameters.Set(DeferredTiledShaderKeys.TileIndex, tileIndex);
847 
848  int drawCount = (tilesGroup.Count + MaxPointLightsPerTileDrawCall - 1) / MaxPointLightsPerTileDrawCall;
849 
850  if (hasPreviousDraw)
851  GraphicsDevice.SetBlendState(accumulationBlendState);
852  else
853  GraphicsDevice.SetBlendState(null);
854 
855  var startLightIndex = 0;
856 
857  // One draw for every MaxPointLightsPerTileDrawCall lights
858  for (int currentDrawIndex = 0; currentDrawIndex < drawCount; ++currentDrawIndex)
859  {
860  // prepare PointLightData[]
861  int lightCount = Math.Min(tilesGroup.Count - startLightIndex, MaxPointLightsPerTileDrawCall);
862  for (int lightIndex = 0; lightIndex < lightCount; ++lightIndex)
863  currentPointLights[lightIndex] = tilesGroup[startLightIndex + lightIndex];
864 
865  // Set data for shader
866  LightingDeferredParameters[] deferredParameters = null;
867  if (lightingConfigurationsPerEffect.TryGetValue(pointLightingPrepassEffect, out deferredParameters))
868  {
869  foreach (var deferredParam in deferredParameters)
870  {
871  if ((deferredParam.Semantic & LightingDeferredSemantic.PointLightInfos) != 0)
872  {
873  context.Parameters.Set(deferredParam.PointLightInfosKey, currentPointLights);
874  }
875  if ((deferredParam.Semantic & LightingDeferredSemantic.LightCount) != 0)
876  {
877  context.Parameters.Set(deferredParam.LightCountKey, lightCount);
878  }
879  if ((deferredParam.Semantic & LightingDeferredSemantic.LightAttenuationCutoff) != 0)
880  {
881  context.Parameters.Set(deferredParam.LightAttenuationCutoffKey, 0.1f);
882  }
883  }
884  }
885 
886  RenderTile(context, pointLightingPrepassEffect, hasPreviousDraw, currentDrawIndex);
887 
888  startLightIndex += MaxPointLightsPerTileDrawCall;
889  }
890 
891  hasDrawn |= (drawCount > 0);
892  }
893 
894  if (hasDrawn)
895  pointLightingPrepassEffect.UnbindResources();
896  }
897 
898  private void UpdateTiles(ParameterCollection viewParameters)
899  {
900  for (int i = 0; i < tilesGroups.Length; ++i)
901  tilesGroups[i].Clear();
902 
903  var lightAttenuationCutoff = AttenuationCutoff;
904 
905  Matrix viewMatrix;
906  viewParameters.Get(TransformationKeys.View, out viewMatrix);
907  Matrix projMatrix;
908  viewParameters.Get(TransformationKeys.Projection, out projMatrix);
909 
910  for (int index = 0; index < pointLightDatas.Count; index++)
911  {
912  var lightData = pointLightDatas[index];
913 
914  // Transform light position from WS to VS
915  Vector3.TransformCoordinate(ref lightData.LightPosition, ref viewMatrix, out lightData.LightPosition);
916 
917  // ------------------------------------------------------------------------------------------
918  // TEMPORARY FIX FOR DEFERRED LIGHTS
919  // ------------------------------------------------------------------------------------------
920  //lightData2[index].DiffuseColor.Pow(1 / 4.0f);
921  //lightData2[index].LightIntensity = (float)Math.Pow(lightData2[index].LightIntensity, 1.0f / 2.2f);
922  // ------------------------------------------------------------------------------------------
923 
924  float lightDistanceMax = CalculateMaxDistance(lightData.LightIntensity, lightData.LightRadius, lightAttenuationCutoff);
925 
926  // Check if this light is really visible (not behind us)
927  if (lightData.LightPosition.Z - lightDistanceMax > 0.0f)
928  continue;
929 
930  var clipRegion = ComputeClipRegion(lightData.LightPosition, lightDistanceMax, ref projMatrix);
931 
932  var tileStartX = (int)((clipRegion.X * 0.5f + 0.5f) * TileCountX);
933  var tileEndX = (int)((clipRegion.Z * 0.5f + 0.5f) * TileCountX);
934  var tileStartY = (int)((clipRegion.Y * 0.5f + 0.5f) * TileCountY);
935  var tileEndY = (int)((clipRegion.W * 0.5f + 0.5f) * TileCountY);
936 
937  for (int y = tileStartY; y <= tileEndY; ++y)
938  {
939  if (y < 0 || y >= TileCountY)
940  continue;
941  for (int x = tileStartX; x <= tileEndX; ++x)
942  {
943  if (x < 0 || x >= TileCountX)
944  continue;
945  tilesGroups[y * TileCountX + x].Add(lightData);
946  }
947  }
948  }
949 
950  for (int index = 0; index < spotLightDatas.Count; index++)
951  {
952  var lightData = spotLightDatas[index];
953 
954  // Transform light direction from WS to VS
955  Vector3.TransformNormal(ref lightData.LightDirection, ref viewMatrix, out lightData.LightDirection);
956  // Transform light position from WS to VS
957  Vector3.TransformCoordinate(ref lightData.LightPosition, ref viewMatrix, out lightData.LightPosition);
958  spotLightDatas[index] = lightData;
959  }
960 
961  foreach (var lightDatas in spotShadowLightDatas)
962  {
963  for (int index = 0; index < lightDatas.Value.Count; index++)
964  {
965  var lightData = lightDatas.Value[index];
966 
967  // Transform light direction from WS to VS
968  Vector3.TransformNormal(ref lightData.LightDirection, ref viewMatrix, out lightData.LightDirection);
969  // Transform light position from WS to VS
970  Vector3.TransformCoordinate(ref lightData.LightPosition, ref viewMatrix, out lightData.LightPosition);
971  lightDatas.Value[index] = lightData;
972  }
973  }
974 
975  for (int index = 0; index < directionalLightDatas.Count; index++)
976  {
977  var lightData = directionalLightDatas[index];
978 
979  // Transform light direction from WS to VS
980  Vector3.TransformNormal(ref lightData.LightDirection, ref viewMatrix, out lightData.LightDirection);
981  directionalLightDatas[index] = lightData;
982  }
983 
984  foreach (var lightDatas in directShadowLightDatas)
985  {
986  for (int index = 0; index < lightDatas.Value.Count; index++)
987  {
988  var lightData = lightDatas.Value[index];
989 
990  // Transform light direction from WS to VS
991  Vector3.TransformNormal(ref lightData.LightDirection, ref viewMatrix, out lightData.LightDirection);
992  lightDatas.Value[index] = lightData;
993  }
994  }
995  }
996 
997  private static float CalculateMaxDistance(float lightIntensity, float lightRadius, float cutoff)
998  {
999  // DMax = r + r * (sqrt(Li/Ic) - 1) = r * sqrt(Li/Ic)
1000  return (float)(lightRadius * Math.Sqrt(lightIntensity / cutoff));
1001  }
1002 
1003  private static void UpdateClipRegionRoot(float nc, // Tangent plane x/y normal coordinate (view space)
1004  float lc, // Light x/y coordinate (view space)
1005  float lz, // Light z coordinate (view space)
1006  float lightRadius,
1007  float cameraScale, // Project scale for coordinate (_11 or _22 for x/y respectively)
1008  ref float clipMin,
1009  ref float clipMax)
1010  {
1011  float nz = (lightRadius - nc * lc) / lz;
1012  float pz = (lc * lc + lz * lz - lightRadius * lightRadius) /
1013  (lz - (nz / nc) * lc);
1014 
1015  if (pz > 0.0f)
1016  {
1017  float c = -nz * cameraScale / nc;
1018  if (nc > 0.0f)
1019  { // Left side boundary
1020  clipMin = Math.Max(clipMin, c);
1021  }
1022  else
1023  { // Right side boundary
1024  clipMax = Math.Min(clipMax, c);
1025  }
1026  }
1027  }
1028 
1029  private static void UpdateClipRegion(float lc, // Light x/y coordinate (view space)
1030  float lz, // Light z coordinate (view space)
1031  float lightRadius,
1032  float cameraScale, // Project scale for coordinate (_11 or _22 for x/y respectively)
1033  ref float clipMin,
1034  ref float clipMax)
1035  {
1036  float rSq = lightRadius * lightRadius;
1037  float lcSqPluslzSq = lc * lc + lz * lz;
1038  float d = rSq * lc * lc - lcSqPluslzSq * (rSq - lz * lz);
1039 
1040  if (d > 0)
1041  {
1042  float a = lightRadius * lc;
1043  float b = (float)Math.Sqrt(d);
1044  float nx0 = (a + b) / lcSqPluslzSq;
1045  float nx1 = (a - b) / lcSqPluslzSq;
1046 
1047  UpdateClipRegionRoot(nx0, lc, lz, lightRadius, cameraScale, ref clipMin, ref clipMax);
1048  UpdateClipRegionRoot(nx1, lc, lz, lightRadius, cameraScale, ref clipMin, ref clipMax);
1049  }
1050  }
1051 
1052  private static Vector4 ComputeClipRegion(Vector3 lightPosView, float lightRadius, ref Matrix projection)
1053  {
1054  var clipRegion = new Vector4(1.0f, 1.0f, 0.0f, 0.0f);
1055  var clipMin = new Vector2(-1.0f, -1.0f);
1056  var clipMax = new Vector2(1.0f, 1.0f);
1057 
1058  UpdateClipRegion(lightPosView.X, -lightPosView.Z, lightRadius, projection.M11, ref clipMin.X, ref clipMax.X);
1059  UpdateClipRegion(lightPosView.Y, -lightPosView.Z, lightRadius, projection.M22, ref clipMin.Y, ref clipMax.Y);
1060 
1061  clipRegion = new Vector4(clipMin.X, clipMin.Y, clipMax.X, clipMax.Y);
1062 
1063  return clipRegion;
1064  }
1065 
1066  private LightingGroupInfo CreateLightingUpdateInfo(Effect effect)
1067  {
1068  var lightingGroupInfo = LightingGroupInfo.GetOrCreate(effect);
1069 
1070  if (!lightingGroupInfo.IsLightingSetup || !lightingConfigurationsPerEffect.ContainsKey(effect))
1071  {
1072  var finalList = new List<LightingDeferredParameters>();
1073  var continueSearch = true;
1074  var index = 0;
1075  while (continueSearch)
1076  {
1077  continueSearch = SearchLightingGroup(effect, index, "lightingGroups", finalList);
1078  ++index;
1079  }
1080 
1081  continueSearch = true;
1082  index = 0;
1083  while (continueSearch)
1084  {
1085  continueSearch = SearchLightingGroup(effect, index, "shadows", finalList);
1086  ++index;
1087  }
1088 
1089  lightingConfigurationsPerEffect.Remove(effect);
1090 
1091  if (finalList.Count > 0)
1092  lightingConfigurationsPerEffect.Add(effect, finalList.ToArray());
1093 
1094  lightingGroupInfo.IsLightingSetup = true;
1095  }
1096 
1097  return lightingGroupInfo;
1098  }
1099 
1100  private bool SearchLightingGroup(Effect effect, int index, string groupName, List<LightingDeferredParameters> finalList)
1101  {
1102  var constantBuffers = effect.ConstantBuffers;
1103  var info = new LightingDeferredParameters();
1104 
1105  LightingDeferredSemantic foundParameterSemantic;
1106  var foundParam = false;
1107 
1108  UpdateLightingParameterSemantics(index, groupName);
1109 
1110  foreach (var constantBuffer in constantBuffers)
1111  {
1112  foreach (var member in constantBuffer.Members)
1113  {
1114  if (lightingParameterSemantics.TryGetValue(member.Param.Key, out foundParameterSemantic))
1115  {
1116  info.Semantic = info.Semantic | foundParameterSemantic;
1117  foundParam = true;
1118  switch (foundParameterSemantic)
1119  {
1120  case LightingDeferredSemantic.PointLightInfos:
1121  info.Count = member.Count;
1122  info.PointLightInfosKey = (ParameterKey<PointLightData[]>)member.Param.Key;
1123  break;
1124  case LightingDeferredSemantic.DirectLightInfos:
1125  info.Count = member.Count;
1126  info.DirectLightInfosKey = (ParameterKey<DirectLightData[]>)member.Param.Key;
1127  break;
1128  case LightingDeferredSemantic.SpotLightInfos:
1129  info.Count = member.Count;
1130  info.SpotLightInfosKey = (ParameterKey<SpotLightData[]>)member.Param.Key;
1131  break;
1132  case LightingDeferredSemantic.LightAttenuationCutoff:
1133  info.LightAttenuationCutoffKey = (ParameterKey<float>)member.Param.Key;
1134  break;
1135  case LightingDeferredSemantic.LightCount:
1136  info.LightCountKey = (ParameterKey<int>)member.Param.Key;
1137  break;
1138  default:
1139  throw new ArgumentOutOfRangeException();
1140  }
1141  }
1142  }
1143  }
1144  if (foundParam)
1145  finalList.Add(info);
1146  return foundParam;
1147  }
1148 
1149  private void UpdateLightingParameterSemantics(int index, string compositionName)
1150  {
1151  lightingParameterSemantics.Clear();
1152  var lightGroupSubKey = string.Format("." + compositionName + "[{0}]", index);
1153  foreach (var param in LightParametersDict)
1154  {
1155  lightingParameterSemantics.Add(param.Key.AppendKey(lightGroupSubKey), param.Value);
1156  }
1157  }
1158 
1159  #endregion
1160 
1161  #region Private static methods
1162 
1163  private static DirectLightData GetDirectLightData(EntityLightShadow light)
1164  {
1165  DirectLightData data;
1166  Vector3 lightDirection;
1167  data.DiffuseColor = light.Light.Color;
1168  // TODO: Linearize intensity
1169  data.LightIntensity = light.Light.Intensity;//(float)Math.Pow(light.Light.Intensity, 2.2f);
1170  var lightDir = light.Light.LightDirection;
1171  Vector3.TransformNormal(ref lightDir, ref light.Entity.Transformation.WorldMatrix, out lightDirection);
1172  data.LightDirection = lightDirection;
1173 
1174  // TODO: Linearize color
1175  //data.DiffuseColor.Pow(2.2f);
1176 
1177  return data;
1178  }
1179 
1180  private static SpotLightData GetSpotLightData(EntityLightShadow light)
1181  {
1182  SpotLightData data;
1183  Vector3 lightDirection;
1184  Vector3 lightPosition;
1185  var zero = Vector3.Zero;
1186  var lightDir = light.Light.LightDirection;
1187  Vector3.TransformNormal(ref lightDir, ref light.Entity.Transformation.WorldMatrix, out lightDirection);
1188  data.LightDirection = lightDirection;
1189  data.DiffuseColor = light.Light.Color;
1190  // TODO: Linearize intensity
1191  data.LightIntensity = light.Light.Intensity;//(float)Math.Pow(light.Light.Intensity, 2.2f);
1193  data.LightPosition /= light.Entity.Transformation.WorldMatrix.M44;
1194 
1195  data.SpotBeamAngle = (float)Math.Cos(Math.PI * light.Light.SpotBeamAngle / 180);
1196  data.SpotFieldAngle = (float)Math.Cos(Math.PI * light.Light.SpotFieldAngle / 180);
1197 
1198  data.Range = light.Light.DecayStart;
1199 
1200  // TODO: Linearize color
1201  //data.DiffuseColor.Pow(2.2f);
1202 
1203  return data;
1204  }
1205 
1206  #endregion
1207 
1208  #region Helper structures
1209 
1210  private class LightingDeferredParameters
1211  {
1212  public LightingDeferredSemantic Semantic;
1213  public int Count;
1214  public ParameterKey<int> LightCountKey;
1215  public ParameterKey<PointLightData[]> PointLightInfosKey;
1216  public ParameterKey<DirectLightData[]> DirectLightInfosKey;
1217  public ParameterKey<SpotLightData[]> SpotLightInfosKey;
1218  public ParameterKey<float> LightAttenuationCutoffKey;
1219 
1220  public LightingDeferredParameters()
1221  {
1222  Semantic = LightingDeferredSemantic.None;
1223  Count = 0;
1224  PointLightInfosKey = null;
1225  DirectLightInfosKey = null;
1226  SpotLightInfosKey = null;
1227  LightCountKey = null;
1228  LightAttenuationCutoffKey = null;
1229  }
1230  }
1231 
1232  [Flags]
1233  internal enum LightingDeferredSemantic
1234  {
1235  None = 0x0,
1236  PointLightInfos = 0x1,
1237  DirectLightInfos = 0x2,
1238  SpotLightInfos = 0x4,
1239  LightAttenuationCutoff = 0x8,
1240  LightCount = 0x10
1241  }
1242 
1243  private struct ShadowEffectInfo
1244  {
1245  public LightType LightType;
1246  public int CascadeCount;
1247  public ShadowMapFilterType Filter;
1248  }
1249 
1250  #endregion
1251  }
1252 }
float SpotBeamAngle
Gets or sets the beam angle of the spot light.
Key of an effect parameter.
Definition: ParameterKey.cs:15
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
The layout of a vertex buffer with a set of VertexElement.
float Y
The Y component of the vector.
Definition: Vector3.cs:84
Matrix WorldMatrix
The world matrix. Use UpdateWorldMatrix to ensure it is updated.
Represents a two dimensional mathematical vector.
Definition: Vector2.cs:42
function b
function a
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
Performs render pipeline transformations attached to a specific RenderPass.
Definition: Renderer.cs:13
override void Load()
Loads this instance. This method is called when a RenderPass is attached (directly or indirectly) to ...
LightingPrepassRenderer(IServiceRegistry services, string effectName, Texture2D depthStencilTexture, Texture2D gbufferTexture)
LightPrepassRenderer constructor.
float X
The X component of the vector.
Definition: Vector3.cs:78
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
float M42
Value at row 4 column 2 of the matrix.
Definition: Matrix.cs:107
TransformationComponent Transformation
Gets or sets the Transformation associated to this entity. Added for convenience over usual Get/Set m...
Definition: Entity.cs:74
A service registry is a IServiceProvider that provides methods to register and unregister services...
Represents a color in the form of rgba.
Definition: Color4.cs:42
All-in-One Buffer class linked SharpDX.Direct3D11.Buffer.
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.
ParameterCollection Parameters
Gets the parameters shared by this instance.
Flags
Enumeration of the new Assimp's flags.
static Buffer New(GraphicsDevice device, BufferDescription description, PixelFormat viewFormat=PixelFormat.None)
Creates a new Buffer instance.
Definition: Buffer.cs:343
float SpotFieldAngle
Gets or sets the spot field angle of the spot light.
Represents a four dimensional mathematical vector.
Definition: Vector4.cs:42
Thread-local storage context used during rendering.
SiliconStudio.Core.Mathematics.Color Color
Definition: ColorPicker.cs:14
Manage a collection of entities.
Definition: EntitySystem.cs:22
float M41
Value at row 4 column 1 of the matrix.
Definition: Matrix.cs:87
SiliconStudio.Paradox.Graphics.Buffer Buffer
override void Unload()
Unloads this instance. This method is called when a RenderPass is de-attached (directly or indirectly...
static VertexElement Position(PixelFormat format, int offsetInBytes=AppendAligned)
Declares a VertexElement with the semantic "POSITION".
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
Definition: Texture2D.cs:37
ColorWriteChannels
Identify which components of each pixel of a render target are writable during blending.
SiliconStudio.Paradox.Graphics.PrimitiveType PrimitiveType
PrimitiveType
Defines how vertex data is ordered.
SiliconStudio.Core.Mathematics.Vector3 Vector3
float M43
Value at row 4 column 3 of the matrix.
Definition: Matrix.cs:127
float Z
The Z component of the vector.
Definition: Vector3.cs:90
A description of a single element for the input-assembler stage. This structure is related to Direct3...
A container to handle a hierarchical collection of effect variables.
Binding structure that specifies a vertex buffer and other per-vertex parameters (such as offset and ...
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47