3 using System.Collections.Generic;
5 using SiliconStudio.Paradox.BinPacking;
6 using SiliconStudio.Paradox.Effects.Modules;
7 using SiliconStudio.Paradox.Games;
8 using SiliconStudio.Paradox.Graphics;
9 using SiliconStudio.Core;
10 using SiliconStudio.Core.Collections;
11 using SiliconStudio.Core.Mathematics;
13 namespace SiliconStudio.
Paradox.Effects
18 [ThreadStatic]
static Matrix[] projections;
19 [ThreadStatic]
static Matrix[] views;
20 [ThreadStatic]
static Matrix[] shadowsViewProj;
21 [ThreadStatic]
static Vector3[] points;
22 [ThreadStatic]
static Vector3[] directions;
27 internal static readonly
ParameterKey<Vector3> ShadowLightOffset = ShadowMapCasterBaseKeys.shadowLightOffset;
51 private List<ShadowMap> shadowMaps =
new List<ShadowMap>();
52 private GuillotinePacker guillotinePacker =
new GuillotinePacker();
53 private EffectOld[] blurEffects;
69 public int AtlasSize {
get; set; }
71 public int BlurCount {
get; set; }
73 internal static readonly
ParameterKey<int> ShadowMapLightCount = ParameterKeys.Value(0);
82 internal RenderPass PostPass {
get;
private set; }
86 protected Texture2D ShadowMapVsm {
get;
private set; }
90 shadowMaps.Add(shadowMap);
91 shadowMap.Passes =
new RenderPass[shadowMap.LevelCount];
94 for (
int i = 0; i < shadowMap.Passes.Length; i++)
96 shadowMap.Passes[i] =
new RenderPass(
string.Format(
"Pass {0}", i)) { Parameters =
new ParameterCollection(
string.Format(
"Parameters ShadowMap {0}", i)) };
97 shadowMap.Passes[i].Parameters.AddSources(MainPlugin.ViewParameters);
98 shadowMap.Passes[i].Parameters.AddSources(shadowMap.CasterParameters);
102 int currentPassIndex = i;
103 shadowMap.Passes[i].Parameters.AddDynamic(TransformationKeys.ViewProjection,
104 ParameterDynamicValue.New(LightingPlugin.ViewProjectionArray, (ref ShadowMapData input, ref
Matrix output) =>
106 fixed (
Matrix* vpPtr = &input.ViewProjCaster0)
108 output = vpPtr[currentPassIndex];
111 shadowMap.Passes[i].Parameters.AddDynamic(LightingPlugin.ShadowLightOffset,
112 ParameterDynamicValue.New(LightingPlugin.ViewProjectionArray, (ref ShadowMapData input, ref
Vector3 output) =>
114 fixed (
Vector3* vpPtr = &input.Offset0)
116 output = vpPtr[currentPassIndex];
124 EnableClearTarget =
false,
125 EnableClearDepth =
false,
129 shadowMap.Plugins[i].Apply();
132 RenderPass.Passes.InsertRange(0, shadowMap.Passes);
135 var dynamicViewProjectionArray = ParameterDynamicValue.New(
136 TransformationKeys.View, TransformationKeys.Projection, LightKeys.LightDirection, LightKeys.LightColor, LightingPlugin.Offsets, (ref
Matrix view, ref
Matrix projection, ref
Vector3 lightDirection, ref
Color3 lightColor, ref
Vector3[] offsets, ref ShadowMapData result) =>
138 if (projections == null)
141 projections =
new Matrix[4];
143 shadowsViewProj =
new Matrix[8];
148 Matrix inverseView, inverseProjection;
149 Matrix.Invert(ref projection, out inverseProjection);
150 Matrix.Invert(ref view, out inverseView);
153 for (
int i = 0; i < 8; ++i)
156 for (
int i = 0; i < 4; i++)
158 directions[i] = Vector3.Normalize(points[i + 4] - points[i]);
162 float shadowDistribute = 1.0f / shadowMap.LevelCount;
164 float zfar = shadowMap.ShadowDistance;
166 var shadowOffsets =
new Vector3[shadowMap.LevelCount];
167 var boudingBoxVectors =
new Vector3[shadowMap.LevelCount * 2];
168 var direction = Vector3.Normalize(lightDirection);
176 foreach (var vectorUp
in VectorUps)
178 if (
Vector3.
Dot(direction, vectorUp) < (1.0 - 0.0001))
180 side = Vector3.Normalize(Vector3.Cross(vectorUp, direction));
181 up = Vector3.Normalize(Vector3.Cross(direction, side));
186 for (
int cascadeLevel = 0; cascadeLevel < shadowMap.LevelCount; ++cascadeLevel)
188 float k0 = (float)(cascadeLevel + 0) / shadowMap.LevelCount;
189 float k1 = (float)(cascadeLevel + 1) / shadowMap.LevelCount;
190 float min = (float)(znear * Math.Pow(zfar / znear, k0)) * (1.0f - shadowDistribute) + (znear + (zfar - znear) * k0) * shadowDistribute;
191 float max = (float)(znear * Math.Pow(zfar / znear, k1)) * (1.0f - shadowDistribute) + (znear + (zfar - znear) * k1) * shadowDistribute;
193 for (
int j = 0; j < shadowMap.LevelCount; j++)
195 boudingBoxVectors[j] = points[j] + directions[j] * min;
196 boudingBoxVectors[j + shadowMap.LevelCount] = points[j] + directions[j] * max;
198 var boundingBox = BoundingBox.FromPoints(boudingBoxVectors);
200 var radius = (boundingBox.Maximum - boundingBox.Minimum).Length() * 0.5f;
201 var target = Vector3.TransformCoordinate(boundingBox.Center, inverseView);
204 var shadowMapHalfSize = shadowMap.ShadowMapSize * 0.5f;
205 float x = (float)Math.Ceiling(
Vector3.
Dot(target, up) * shadowMapHalfSize / radius) * radius / shadowMapHalfSize;
206 float y = (float)Math.Ceiling(
Vector3.
Dot(target, side) * shadowMapHalfSize / radius) * radius / shadowMapHalfSize;
207 float z = Vector3.Dot(target, direction);
209 target = up * x + side * y + direction *
z;
211 views[cascadeLevel] = Matrix.LookAtLH(target - direction * zfar * 0.5f, target + direction * zfar * 0.5f, up);
212 projections[cascadeLevel] = Matrix.OrthoOffCenterLH(-radius, radius, -radius, radius, znear / zfar, zfar);
219 var cascadeTextureCoords = shadowMap.TextureCoordsBorder[cascadeLevel];
221 float leftX = (float)shadowMap.
ShadowMapSize / (
float)AtlasSize * 0.5f;
222 float leftY = (float)shadowMap.
ShadowMapSize / (
float)AtlasSize * 0.5f;
223 float centerX = 0.5f * (cascadeTextureCoords.X + cascadeTextureCoords.Z);
224 float centerY = 0.5f * (cascadeTextureCoords.Y + cascadeTextureCoords.W);
226 shadowsViewProj[cascadeLevel] = views[cascadeLevel] * projections[cascadeLevel];
227 shadowsViewProj[cascadeLevel + 4] = shadowsViewProj[cascadeLevel]
228 * Matrix.Scaling(leftX, -leftY, 0.5f)
231 var shadowVInverse = Matrix.Invert(views[cascadeLevel]);
232 shadowOffsets[cascadeLevel] =
new Vector3(shadowVInverse.M41, shadowVInverse.M42, shadowVInverse.M43);
235 result.LightColor = lightColor;
239 fixed (
Matrix* resultPtr = &result.ViewProjCaster0)
240 Utilities.Write((IntPtr)resultPtr, shadowsViewProj, 0, shadowsViewProj.Length);
242 fixed (
Vector3* resultPtr = &result.Offset0)
243 Utilities.Write((IntPtr)resultPtr, shadowOffsets, 0, shadowOffsets.Length);
247 shadowMap.Parameters.SetDefault(LightKeys.LightDirection);
248 shadowMap.Parameters.SetDefault(Offsets);
249 shadowMap.Parameters.SetDefault(ViewProjectionArray);
250 shadowMap.Parameters.AddDynamic(ViewProjectionArray, dynamicViewProjectionArray);
251 shadowMap.CasterParameters.Set(EffectPlugin.RasterizerStateKey, null);
252 shadowMap.Texture = shadowMap.Filter is
ShadowMapFilterVsm ? ShadowMapVsm : ShadowMapDepth.Texture;
257 shadowMaps.Remove(shadowMap);
258 RenderPass.Passes.RemoveAll(shadowMap.Passes.Contains);
263 guillotinePacker.Clear(ShadowMapDepth.Description.Width, ShadowMapDepth.Description.Height);
266 foreach (var shadowMap
in shadowMaps)
274 var cascadeTextureCoords =
new Vector4[shadowMap.LevelCount];
275 var cascadeTextureCoordsBorder =
new Vector4[shadowMap.LevelCount];
276 for (
int i = 0; i < shadowMap.LevelCount; ++i)
278 var rect = guillotinePacker.Insert(shadowMap.ShadowMapSize, shadowMap.ShadowMapSize);
282 throw new InvalidOperationException(
"Could not allocate enough texture space for shadow map texture.");
285 cascadeTextureCoord.X = (float)(rect.X) / guillotinePacker.Width;
286 cascadeTextureCoord.Y = (float)(rect.Y) / guillotinePacker.Height;
287 cascadeTextureCoord.Z = (float)(rect.X + rect.Width) / guillotinePacker.Width;
288 cascadeTextureCoord.W = (float)(rect.Y + rect.Height) / guillotinePacker.Height;
290 cascadeTextureCoords[i] = cascadeTextureCoord;
292 cascadeTextureCoord.X += 0.01f;
293 cascadeTextureCoord.Y += 0.01f;
294 cascadeTextureCoord.Z -= 0.01f;
295 cascadeTextureCoord.W -= 0.01f;
297 cascadeTextureCoordsBorder[i] = cascadeTextureCoord;
299 shadowMap.Plugins[i]
.Viewport =
new Viewport(rect.X, rect.Y, shadowMap.ShadowMapSize, shadowMap.ShadowMapSize);
300 shadowMap.Plugins[i].DepthStencil = ShadowMapDepth;
303 shadowMap.Parameters.Set(CascadeTextureCoords, cascadeTextureCoords);
304 shadowMap.Parameters.Set(CascadeTextureCoordsBorder, cascadeTextureCoordsBorder);
306 shadowMap.CasterParameters.Set(EffectPlugin.RasterizerStateKey, casterRasterizerState);
307 shadowMap.CasterParameters.Set(EffectPlugin.DepthStencilStateKey, depthStencilStateZStandard);
309 shadowMap.TextureCoordsBorder = cascadeTextureCoordsBorder;
317 blurEffects =
new EffectOld[]
319 this.EffectSystemOld.BuildEffect(
"VsmBlurH")
321 .Using(
new BasicShaderPlugin(
"PostEffectBlurHVsm"))
324 this.EffectSystemOld.BuildEffect(
"VsmBlurV")
326 .Using(
new BasicShaderPlugin(
"PostEffectBlur"))
330 if (OfflineCompilation)
333 RenderSystem.GlobalPass.StartPass += UpdateShadowMaps;
340 if (OfflineCompilation)
343 RenderSystem.GlobalPass.StartPass -= UpdateShadowMaps;
350 if (OfflineCompilation)
354 PostPass =
new RenderPass(
"PostPass").KeepAliveBy(ActiveObjects);
355 RenderPass.AddPass(PostPass);
358 var depthStencilTexture = Texture2D.New(
GraphicsDevice, AtlasSize, AtlasSize, PixelFormat.D32_Float, TextureFlags.DepthStencil | TextureFlags.ShaderResource).KeepAliveBy(ActiveObjects);
359 var depthStencilBuffer = depthStencilTexture.ToDepthStencilBuffer(
false);
360 ShadowMapDepth = depthStencilBuffer;
368 EnableClearDepth =
true,
369 EnableSetTargets =
false,
374 renderTargetPlugin.Apply();
377 depthStencilStateZStandard = DepthStencilState.New(GraphicsDevice,
new DepthStencilStateDescription().Default()).KeepAliveBy(ActiveObjects);
378 depthStencilStateZStandard.Name =
"ZStandard";
380 Parameters.Set(EffectPlugin.DepthStencilStateKey, depthStencilStateZStandard);
386 var shadowMapTextureDesc = ShadowMapDepth.Description;
387 var shadowMapBlurH = Texture2D.New(GraphicsDevice, shadowMapTextureDesc.Width, shadowMapTextureDesc.Height, PixelFormat.R32G32_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget).KeepAliveBy(ActiveObjects);
388 var shadowMapBlurV = Texture2D.New(GraphicsDevice, shadowMapTextureDesc.Width, shadowMapTextureDesc.Height, PixelFormat.R32G32_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget).KeepAliveBy(ActiveObjects);
390 Texture2D textureSourceH = ShadowMapDepth.Texture;
391 Texture2D textureSourceV = shadowMapBlurH;
392 RenderTarget renderTargetH = shadowMapBlurH.ToRenderTarget();
393 RenderTarget renderTargetV = shadowMapBlurV.ToRenderTarget();
395 var blurQuadMesh =
new EffectMesh[2];
396 for (
int j = 0; j < BlurCount; j++)
398 for (
int i = 0; i < 2; ++i)
400 blurQuadMesh[i] =
new EffectMesh(j > 0 ? blurEffects[1] : blurEffects[i]).KeepAliveBy(ActiveObjects);
401 blurQuadMesh[i].Parameters.Set(PostEffectBlurKeys.Coefficients,
new[] { 0.2270270270f, 0.3162162162f, 0.3162162162f, 0.0702702703f, 0.0702702703f });
402 var unit = i == 0 ? Vector2.UnitX : Vector2.UnitY;
403 blurQuadMesh[i].Parameters.Set(PostEffectBlurKeys.Offsets,
new[] { Vector2.Zero, unit * -1.3846153846f, unit * +1.3846153846f, unit * -3.2307692308f, unit * +3.2307692308f });
405 PostPass.AddPass(blurQuadMesh[i].EffectPass);
407 RenderSystem.GlobalMeshes.AddMesh(blurQuadMesh[i]);
410 blurQuadMesh[0].Parameters.Set(TexturingKeys.Texture0, textureSourceH);
411 blurQuadMesh[1].Parameters.Set(TexturingKeys.Texture0, textureSourceV);
412 blurQuadMesh[0].Parameters.Set(RenderTargetKeys.RenderTarget, renderTargetH);
413 blurQuadMesh[1].Parameters.Set(RenderTargetKeys.RenderTarget, renderTargetV);
415 textureSourceH = shadowMapBlurV;
416 textureSourceV = shadowMapBlurH;
419 ShadowMapVsm = shadowMapBlurV;
427 RenderPass.RemovePass(PostPass);
435 private static readonly
Vector3[] FrustrumBasePoints =
437 new Vector3(-1.0f,-1.0f,-1.0f),
new Vector3(1.0f,-1.0f,-1.0f),
new Vector3(-1.0f,1.0f,-1.0f),
new Vector3(1.0f,1.0f,-1.0f),
438 new Vector3(-1.0f,-1.0f, 1.0f),
new Vector3(1.0f,-1.0f, 1.0f),
new Vector3(-1.0f,1.0f, 1.0f),
new Vector3(1.0f,1.0f, 1.0f),
441 private static readonly
Vector3[] VectorUps =
new[] { Vector3.UnitZ, Vector3.UnitY, Vector3.UnitX };
Key of an effect parameter.
A renderable texture view.
static void Dot(ref Vector3 left, ref Vector3 right, out float result)
Calculates the dot product of two vectors.
int ShadowMapSize
Gets or sets the size of the shadow map (default: 1024)
Describes a rasterizer state.
Contains depth-stencil state for the device.
Represents a color in the form of rgb.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Represents a three dimensional mathematical vector.
static void Translation(ref Vector3 value, out Matrix result)
Creates a translation matrix using the specified offsets.
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.
CullMode
Indicates triangles facing a particular direction are not drawn.
void RemoveShadowMap(ShadowMap shadowMap)
Represents a four dimensional mathematical vector.
Defines the window dimensions of a render-target surface onto which a 3D volume projects.
Plugin used for the main rendering view.
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
Level10 render pass using a depth buffer and a render target.
void AddShadowMap(ShadowMap shadowMap)
Describes a depth stencil state.
SiliconStudio.Core.Mathematics.Vector3 Vector3
static void TransformCoordinate(ref Vector3 coordinate, ref Matrix transform, out Vector3 result)
Performs a coordinate transformation using the given SiliconStudio.Core.Mathematics.Matrix.
RenderPass is a hierarchy that defines how to collect and render meshes.
override void Initialize()
void UpdateShadowMaps(ThreadContext context)
A container to handle a hierarchical collection of effect variables.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t size_t z
Represents a 4x4 mathematical matrix.