Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
LightingShaderPlugin.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using SiliconStudio.Paradox.DataModel;
5 using SiliconStudio.Paradox.Effects.Modules;
6 using SiliconStudio.Paradox.Games;
7 using SiliconStudio.Paradox.Graphics;
8 using SiliconStudio.Core.Mathematics;
9 using SiliconStudio.Paradox.Shaders;
10 
11 namespace SiliconStudio.Paradox.Effects
12 {
13  public class LightingShaderPlugin : ShaderPlugin<LightingPlugin>
14  {
15  private ShaderMixinSource mainShaderSource;
16  private ShaderMacro[] mainShaderMacros;
17 
18  public RenderTargetsPlugin MainTargetPlugin { get; set; }
19 
20  public override void SetupPasses(EffectMesh effectMesh)
21  {
22  var effectSystem = Services.GetSafeServiceAs<IEffectSystemOld>();
23 
24  throw new NotImplementedException();
25  EffectShaderPass mainShaderPass;
26  //DefaultShaderPass = FindShaderPassFromPlugin(MainTargetPlugin);
27 
28  //effectSystemOld.RegisterPermutation(DefaultShaderPass, this, ShadowMapPermutationArray.Key, SetupShadersPermutationReceiver);
29  //effectSystemOld.RegisterPermutation(DefaultShaderPass, this, ShadowMapPermutationArray.Key, SetupShadersPermutationCaster);
30  //effectSystemOld.RegisterPermutation(DefaultShaderPass, this, LightingPermutation.Key, SetupLighting);
31  }
32 
33  public override void SetupShaders(EffectMesh effectMesh)
34  {
35  mainShaderSource = (ShaderMixinSource)DefaultShaderPass.Shader.Clone();
36  mainShaderMacros = DefaultShaderPass.Macros.ToArray();
37  }
38 
39  public void SetupLighting(EffectShaderPass effectPass, object permutationKeyObject)
40  {
41  var permutationKey = (LightingPermutation.KeyInfo)permutationKeyObject;
42 
43  if (permutationKey.PerPixelDirectionalLightCount > 0)
44  {
45  effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingPerPixel", permutationKey.PerPixelDirectionalLightCount));
46 
47  // Light colors
48  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerPixelKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
49  (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
50  LightColorsUpdate(lightPermutation.PerPixelDirectionalLights, lightColorsWithGamma)
51  , autoCheckDependencies: false));
52 
53  // LightDirectionVS
54  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerPixelKeys.LightDirectionsVS, ParameterDynamicValue.New(LightingPermutation.Key, TransformationKeys.View, (ref LightingPermutation lightPermutation, ref Matrix view, ref Vector3[] lightDirectionVS) =>
55  {
56  int index = 0;
57  foreach (var lightBinding in lightPermutation.PerPixelDirectionalLights)
58  {
59  var lightDirection = ((DirectionalLight)lightBinding.Light).LightDirection;
60  LightKeys.LightDirectionVSUpdate(ref lightDirection, ref view, ref lightDirectionVS[index++]);
61  }
62  }, autoCheckDependencies: false));
63  }
64 
65  if (permutationKey.PerPixelDiffuseDirectionalLightCount > 0)
66  {
67  effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingDiffusePerPixel", permutationKey.PerPixelDiffuseDirectionalLightCount));
68 
69  // Light colors
70  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingDiffusePerPixelKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
71  (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
72  LightColorsUpdate(lightPermutation.PerPixelDiffuseDirectionalLights, lightColorsWithGamma)
73  , autoCheckDependencies: false));
74 
75  // LightDirectionVS
76  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingDiffusePerPixelKeys.LightDirectionsVS, ParameterDynamicValue.New(LightingPermutation.Key, TransformationKeys.View, (ref LightingPermutation lightPermutation, ref Matrix view, ref Vector3[] lightDirectionVS) =>
77  {
78  int index = 0;
79  foreach (var lightBinding in lightPermutation.PerPixelDiffuseDirectionalLights)
80  {
81  var lightDirection = ((DirectionalLight)lightBinding.Light).LightDirection;
82  LightKeys.LightDirectionVSUpdate(ref lightDirection, ref view, ref lightDirectionVS[index++]);
83  }
84  }, autoCheckDependencies: false));
85  }
86 
87  if (permutationKey.PerVertexDirectionalLightCount > 0)
88  {
89  effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingPerVertex", permutationKey.PerVertexDirectionalLightCount));
90 
91  // Light colors
92  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerVertexKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
93  (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
94  LightColorsUpdate(lightPermutation.PerVertexDirectionalLights, lightColorsWithGamma)
95  , autoCheckDependencies: false));
96 
97  // LightDirectionWS
98  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerVertexKeys.LightDirectionsWS, ParameterDynamicValue.New(LightingPermutation.Key, (ref LightingPermutation lightPermutation, ref Vector3[] lightDirectionWS) =>
99  {
100  int index = 0;
101  foreach (var lightBinding in lightPermutation.PerVertexDirectionalLights)
102  {
103  lightDirectionWS[index++] = ((DirectionalLight)lightBinding.Light).LightDirection;
104  }
105  }, autoCheckDependencies: false));
106  }
107 
108  if (permutationKey.PerVertexDiffusePixelSpecularDirectionalLightCount > 0)
109  {
110  effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingSpecularPerPixel", permutationKey.PerVertexDiffusePixelSpecularDirectionalLightCount));
111 
112  // Light colors
113  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingSpecularPerPixelKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
114  (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
115  LightColorsUpdate(lightPermutation.PerVertexDiffusePixelSpecularDirectionalLights, lightColorsWithGamma)
116  , autoCheckDependencies: false));
117 
118  // LightDirectionWS
119  effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingSpecularPerPixelKeys.LightDirectionsWS, ParameterDynamicValue.New(LightingPermutation.Key, (ref LightingPermutation lightPermutation, ref Vector3[] lightDirectionWS) =>
120  {
121  int index = 0;
122  foreach (var lightBinding in lightPermutation.PerVertexDiffusePixelSpecularDirectionalLights)
123  {
124  lightDirectionWS[index++] = ((DirectionalLight)lightBinding.Light).LightDirection;
125  }
126  }, autoCheckDependencies: false));
127  }
128  }
129 
130  private static void LightColorsUpdate(LightBinding[] lightBindings, Color3[] lightColorsWithGamma)
131  {
132  int index = 0;
133  foreach (var lightBinding in lightBindings)
134  {
135  var lightColor = lightBinding.Light.LightColor;
136  lightColor.Pow(Color.DefaultGamma);
137  lightColorsWithGamma[index++] = lightColor;
138  }
139  }
140 
142  {
143  var shadowMapPermutation = (ShadowMap)permutationKey;
144 
145  var shaderCaster = new ShaderClassSource("ShadowMapCasterBase");
146 
147  for (int i = 0; i < shadowMapPermutation.LevelCount; ++i)
148  {
149  // Shadow caster
150  var shaderPass = new EffectShaderPass(shadowMapPermutation.Passes[i], "ShadowMap");
151  shaderPass.Parameters.AddSources(shadowMapPermutation.Passes[i].Parameters);
152  shaderPass.Shader = (ShaderMixinSource)mainShaderSource.Clone();
153  shaderPass.Macros.AddRange(mainShaderMacros);
154  shaderPass.Shader.Mixins.Add(shaderCaster);
155  yield return shaderPass;
156  }
157  }
158 
159  public void SetupShadersPermutationReceiver(EffectShaderPass effectPass, object permutationKey)
160  {
161  var currentShadowMapsPermutation = (ShadowMapPermutationArray)permutationKey;
162 
163  if (currentShadowMapsPermutation.ShadowMaps.Count == 0)
164  return;
165 
166  var shadowsArray = new ShaderArraySource();
167  effectPass.Shader.Mixins.Add("ShadowMapReceiver");
168  effectPass.Shader.Compositions.Add("shadows", shadowsArray);
169 
170  // Group by shadow map types (one group can be processed in the same loop).
171  // Currently based on filtering type and number of cascades (but some more parameters might affect this later as new type of shadow maps are introduced).
172  var shadowMapTypes = currentShadowMapsPermutation.ShadowMaps.GroupBy(x => Tuple.Create(x.ShadowMap.Filter.GetType(), x.ShadowMap.LevelCount, x.ShadowMap.Texture));
173 
174  int shadowMapTypeIndex = 0;
175  foreach (var shadowMapType in shadowMapTypes)
176  {
177  var shadowMapTypeCopy = shadowMapType.ToArray();
178  var shadowMixin = new ShaderMixinSource();
179 
180  // Currently use shadow map count, but we should probably use next power of two to limit number of permutations.
181  var maxShadowMapCount = shadowMapTypeCopy.Length;
182 
183  // Setup shadow mapping
184  shadowMixin.Mixins.Add(new ShaderClassSource("ShadowMapCascadeBase", shadowMapType.Key.Item2, 0, maxShadowMapCount, 1));
185  //shadowMixin.Mixins.Add(new ShaderClassSource("LightDirectionalShading", shadowMapPermutation.Index));
186 
187  // Setup the filter
188  // TODO: Use static based on type of filter? (should use Key instead of First()).
189  shadowMixin.Mixins.Add(shadowMapType.First().ShadowMap.Filter.GenerateShaderSource(maxShadowMapCount));
190 
191  shadowsArray.Add(shadowMixin);
192 
193  // Register keys for this shadow map type
194  var shadowSubKey = string.Format(".shadows[{0}]", shadowMapTypeIndex++);
195 
196  effectPass.Parameters.Set(ShadowMapKeys.Texture.AppendKey(shadowSubKey), shadowMapType.Key.Item3);
197 
198  effectPass.Parameters.Set(LightingPlugin.ShadowMapLightCount.AppendKey(shadowSubKey), shadowMapTypeCopy.Length);
199 
200  effectPass.Parameters.AddDynamic(LightingPlugin.ReceiverInfo.AppendKey(shadowSubKey), ParameterDynamicValue.New(ShadowMapPermutationArray.Key, TransformationKeys.World, TransformationKeys.ViewProjection, (ref ShadowMapPermutationArray shadowMapPermutations, ref Matrix world, ref Matrix viewProj, ref ShadowMapReceiverInfo[] output) =>
201  {
202  unsafe
203  {
204  for (int i = 0; i < shadowMapTypeCopy.Length; ++i)
205  {
206  var permutationParameters = shadowMapTypeCopy[i].ShadowMap.Parameters;
207 
208  // TODO: Optimize dictionary access this using SetKeyMapping
209  var shadowMapData = permutationParameters.Get(LightingPlugin.ViewProjectionArray);
210  var textureCoords = permutationParameters.Get(LightingPlugin.CascadeTextureCoordsBorder);
211  var distanceMax = permutationParameters.Get(ShadowMapKeys.DistanceMax);
212  var lightDirection = permutationParameters.Get(LightKeys.LightDirection);
213 
214  Matrix* vpPtr = &shadowMapData.ViewProjReceiver0;
215  fixed (Matrix* wvpPtr = &output[i].WorldViewProjReceiver0)
216  {
217  for (int j = 0; j < 4; ++j)
218  Matrix.Multiply(ref world, ref vpPtr[j], ref wvpPtr[j]);
219  }
220 
221  output[i].Offset0 = shadowMapData.Offset0;
222  output[i].Offset1 = shadowMapData.Offset1;
223  output[i].Offset2 = shadowMapData.Offset2;
224  output[i].Offset3 = shadowMapData.Offset3;
225 
226  fixed (Vector4* targetPtr = &output[i].CascadeTextureCoordsBorder0)
227  fixed (Vector4* sourcePtr = &textureCoords[0])
228  {
229  for (int j = 0; j < 4; ++j)
230  targetPtr[j] = sourcePtr[j];
231  }
232 
233  output[i].ShadowLightDirection = lightDirection;
234  LightKeys.LightDirectionVSUpdate(ref output[i].ShadowLightDirection, ref viewProj, ref output[i].ShadowLightDirectionVS);
235  output[i].ShadowMapDistance = distanceMax;
236  output[i].ShadowLightColor = shadowMapData.LightColor;
237  }
238  }
239  }, autoCheckDependencies: false)); // Always update (permutation won't get updated, only its content)!
240 
241  // Register VSM filter if necessary
242  if (shadowMapType.Key.Item1 == typeof(ShadowMapFilterVsm))
243  {
244  effectPass.Parameters.AddDynamic(LightingPlugin.ReceiverVsmInfo.AppendKey(shadowSubKey), ParameterDynamicValue.New(ShadowMapPermutationArray.Key, (ref ShadowMapPermutationArray shadowMapPermutations, ref ShadowMapReceiverVsmInfo[] output) =>
245  {
246  for (int i = 0; i < shadowMapTypeCopy.Length; ++i)
247  {
248  var permutationParameters = shadowMapTypeCopy[i].ShadowMap.Parameters;
249  output[i].BleedingFactor = permutationParameters.Get(ShadowMapFilterVsm.VsmBleedingFactor);
250  output[i].MinVariance = permutationParameters.Get(ShadowMapFilterVsm.VsmMinVariance);
251  }
252  }, autoCheckDependencies: false));
253  }
254  }
255  }
256  }
257 }
static ParameterKey< ShadowMapPermutationArray > Key
A mixin performing a combination of ShaderClassSource and other mixins.
Represents a color in the form of rgb.
Definition: Color3.cs:41
abstract ShaderClassSource GenerateShaderSource(int shadowMapCount)
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
Represents a ShadowMap.
Definition: ShadowMap.cs:11
void SetupLighting(EffectShaderPass effectPass, object permutationKeyObject)
override void SetupPasses(EffectMesh effectMesh)
Base class for ParameterDynamicValue{T}.
static readonly ParameterKey< Matrix > ViewProjection
Level10 render pass using a depth buffer and a render target.
An array of ShaderSource used only in shader mixin compositions.
void SetupShadersPermutationReceiver(EffectShaderPass effectPass, object permutationKey)
IEnumerable< EffectShaderPass > SetupShadersPermutationCaster(object permutationKey)
override void SetupShaders(EffectMesh effectMesh)
static readonly ParameterKey< Matrix > World
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47