5 using System.Collections.Generic;
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;
16 namespace SiliconStudio.
Paradox.Effects.Modules.Renderers
26 private const float VsmBlurSize = 4.0f;
30 #region Private static members
35 private static readonly
Vector3[] FrustrumBasePoints =
37 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),
38 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),
44 private static readonly
Vector3[] VectorUps =
new[] { Vector3.UnitZ, Vector3.UnitY, Vector3.UnitX };
49 internal static readonly
ParameterKey<int> ShadowMapLightCount = ParameterKeys.New(0);
53 #region Private members
59 private Effect vsmHorizontalBlur;
61 private Effect vsmVerticalBlur;
64 private HashSet<ShadowMapTexture> shadowMapTexturesToBlur =
new HashSet<ShadowMapTexture>();
73 vsmHorizontalBlur = EffectSystem.LoadEffect(
"HorizontalVsmBlur");
74 vsmVerticalBlur = EffectSystem.LoadEffect(
"VerticalVsmBlur");
84 var entitySystem = Services.GetServiceAs<
EntitySystem>();
86 if (lightProcessor == null)
89 var graphicsDevice = context.GraphicsDevice;
93 Pass.Parameters.Get(TransformationKeys.View, out view);
94 Pass.Parameters.Get(TransformationKeys.Projection, out projection);
97 foreach (var shadowMapTexture
in lightProcessor.ActiveShadowMapTextures)
100 graphicsDevice.Clear(shadowMapTexture.ShadowMapDepthBuffer, DepthStencilClearOptions.DepthBuffer);
102 if (shadowMapTexture.IsVarianceShadowMap)
103 graphicsDevice.Clear(shadowMapTexture.ShadowMapRenderTarget, Color4.White);
106 shadowMapTexture.GuillotinePacker.Clear(shadowMapTexture.ShadowMapDepthTexture.Width, shadowMapTexture.ShadowMapDepthTexture.Height);
110 var hasFilter = graphicsDevice.Parameters.ContainsKey(ShadowMapParameters.FilterType);
111 filterBackup = graphicsDevice.Parameters.Get(ShadowMapParameters.FilterType);
113 if (lightProcessor.ActiveShadowMaps.Count > 0)
116 Matrix inverseView, inverseProjection;
117 Matrix.Invert(ref projection, out inverseProjection);
118 Matrix.Invert(ref view, out inverseView);
121 for (
int i = 0; i < 8; ++i)
125 for (
int i = 0; i < 4; i++)
129 foreach (var shadowMap
in lightProcessor.ActiveShadowMaps)
131 Vector3.Normalize(ref shadowMap.LightDirection, out shadowMap.LightDirectionNormalized);
134 ComputeShadowMap(shadowMap, ref inverseView);
137 graphicsDevice.SetRenderTarget(shadowMap.Texture.ShadowMapDepthBuffer, shadowMap.Texture.ShadowMapRenderTarget);
139 graphicsDevice.SetRenderTarget(shadowMap.Texture.ShadowMapDepthBuffer);
142 context.Parameters.Set(RenderingParameters.ActiveRenderLayer, shadowMap.Layers);
145 for (
int i = 0; i < shadowMap.CascadeCount; ++i)
147 var cascade = shadowMap.Cascades[i];
150 graphicsDevice.Parameters.Set(ShadowMapKeys.DistanceMax, shadowMap.LightType == LightType.Directional ? shadowMap.ShadowFarDistance : shadowMap.ShadowFarDistance - shadowMap.ShadowNearDistance);
151 graphicsDevice.Parameters.Set(LightKeys.LightDirection, shadowMap.LightDirectionNormalized);
152 graphicsDevice.Parameters.Set(ShadowMapCasterBaseKeys.shadowLightOffset, cascade.ReceiverInfo.Offset);
156 graphicsDevice.Parameters.Set(TransformationKeys.View, Matrix.Identity);
157 graphicsDevice.Parameters.Set(TransformationKeys.Projection, cascade.ViewProjCaster);
160 var cascadeTextureCoord = cascade.CascadeTextureCoords;
161 var viewPortCoord =
new Vector4(
162 cascadeTextureCoord.X * shadowMap.Texture.ShadowMapDepthTexture.Width,
163 cascadeTextureCoord.Y * shadowMap.Texture.ShadowMapDepthTexture.Height,
164 cascadeTextureCoord.Z * shadowMap.Texture.ShadowMapDepthTexture.Width,
165 cascadeTextureCoord.W * shadowMap.Texture.ShadowMapDepthTexture.Height);
168 graphicsDevice.SetViewport(
new Viewport((
int)viewPortCoord.X, (
int)viewPortCoord.Y, (
int)(viewPortCoord.Z - viewPortCoord.X), (
int)(viewPortCoord.W - viewPortCoord.Y)));
171 shadowMapTexturesToBlur.Add(shadowMap.Texture);
173 graphicsDevice.Parameters.Set(ShadowMapParameters.FilterType, shadowMap.Filter);
174 base.OnRendering(context);
178 context.Parameters.Reset(RenderingParameters.ActiveRenderLayer);
182 graphicsDevice.Parameters.Reset(ShadowMapKeys.DistanceMax);
183 graphicsDevice.Parameters.Reset(LightKeys.LightDirection);
184 graphicsDevice.Parameters.Reset(ShadowMapCasterBaseKeys.shadowLightOffset);
185 graphicsDevice.Parameters.Reset(TransformationKeys.View);
186 graphicsDevice.Parameters.Reset(TransformationKeys.Projection);
188 graphicsDevice.Parameters.Set(ShadowMapParameters.FilterType, filterBackup);
190 graphicsDevice.Parameters.Reset(ShadowMapParameters.FilterType);
193 foreach (var shadowMap
in shadowMapTexturesToBlur)
195 graphicsDevice.SetDepthStencilState(graphicsDevice.DepthStencilStates.None);
196 graphicsDevice.SetRasterizerState(graphicsDevice.RasterizerStates.CullNone);
199 graphicsDevice.SetRenderTarget(shadowMap.ShadowMapDepthBuffer, shadowMap.IntermediateBlurRenderTarget);
200 vsmHorizontalBlur.Parameters.Set(TexturingKeys.Texture0, shadowMap.ShadowMapTargetTexture);
201 vsmHorizontalBlur.Parameters.Set(TexturingKeys.Sampler, GraphicsDevice.SamplerStates.LinearClamp);
202 graphicsDevice.DrawQuad(vsmHorizontalBlur);
205 graphicsDevice.SetRenderTarget(shadowMap.ShadowMapDepthBuffer, shadowMap.ShadowMapRenderTarget);
206 vsmVerticalBlur.Parameters.Set(TexturingKeys.Texture0, shadowMap.IntermediateBlurTexture);
207 vsmVerticalBlur.Parameters.Set(TexturingKeys.Sampler, GraphicsDevice.SamplerStates.LinearClamp);
208 graphicsDevice.DrawQuad(vsmVerticalBlur);
211 shadowMapTexturesToBlur.Clear();
214 private void ComputeShadowMap(
ShadowMap shadowMap, ref
Matrix inverseView)
216 float shadowDistribute = 1.0f / shadowMap.CascadeCount;
217 float znear = shadowMap.ShadowNearDistance;
218 float zfar = shadowMap.ShadowFarDistance;
220 var boudingBoxVectors =
new Vector3[8];
221 var direction = Vector3.Normalize(shadowMap.LightDirectionNormalized);
230 foreach (var vectorUp
in VectorUps)
232 if (
Vector3.
Dot(direction, vectorUp) < (1.0 - 0.0001))
234 side = Vector3.Normalize(Vector3.Cross(vectorUp, direction));
235 up = Vector3.Normalize(Vector3.Cross(direction, side));
241 var cascades = shadowMap.Cascades;
242 if (cascades == null)
243 cascades = shadowMap.Cascades =
new ShadowMapCascadeInfo[shadowMap.CascadeCount];
245 for (
int cascadeLevel = 0; cascadeLevel < shadowMap.CascadeCount; ++cascadeLevel)
248 var shadowMapView = Matrix.Zero;
249 var shadowMapProjection = Matrix.Zero;
250 if (shadowMap.LightType ==
LightType.Directional)
253 float k0 = (float)(cascadeLevel + 0) / shadowMap.CascadeCount;
254 float k1 = (float)(cascadeLevel + 1) / shadowMap.CascadeCount;
255 float min = (float)(znear * Math.Pow(zfar / znear, k0)) * (1.0f - shadowDistribute) + (znear + (zfar - znear) * k0) * shadowDistribute;
256 float max = (float)(znear * Math.Pow(zfar / znear, k1)) * (1.0f - shadowDistribute) + (znear + (zfar - znear) * k1) * shadowDistribute;
259 for (
int j = 0; j < 4; j++)
261 boudingBoxVectors[j * 2 + 0] = points[j] + directions[j] * min;
262 boudingBoxVectors[j * 2 + 1] = points[j] + directions[j] * max;
264 var boundingBox = BoundingBox.FromPoints(boudingBoxVectors);
268 var radius = (boundingBox.Maximum - boundingBox.Minimum).Length() * 0.5f;
269 var target = Vector3.TransformCoordinate(boundingBox.Center, inverseView);
272 var shadowMapHalfSize = shadowMap.ShadowMapSize * 0.5f;
273 float x = (float)Math.Ceiling(
Vector3.
Dot(target, up) * shadowMapHalfSize / radius) * radius / shadowMapHalfSize;
274 float y = (float)Math.Ceiling(
Vector3.
Dot(target, side) * shadowMapHalfSize / radius) * radius / shadowMapHalfSize;
275 float z = Vector3.Dot(target, direction);
277 target = up * x + side * y + direction *
z;
280 shadowMapView = Matrix.LookAtRH(target - direction * zfar * 0.5f, target + direction * zfar * 0.5f, up);
281 shadowMapProjection = Matrix.OrthoOffCenterRH(-radius, radius, -radius, radius, znear, zfar);
287 Matrix.Invert(ref shadowMapView, out shadowVInverse);
288 cascades[cascadeLevel].ReceiverInfo.Offset =
new Vector3(shadowVInverse.M41, shadowVInverse.M42, shadowVInverse.M43);
290 else if (shadowMap.LightType ==
LightType.Spot)
292 shadowMapView = Matrix.LookAtRH(shadowMap.LightPosition, shadowMap.LightPosition + shadowMap.LightDirection, up);
293 shadowMapProjection = Matrix.PerspectiveFovRH(shadowMap.Fov, 1, znear, zfar);
296 cascades[cascadeLevel].ReceiverInfo.Offset = shadowMap.LightPosition + znear * shadowMap.LightDirectionNormalized;
300 var shadowMapRectangle =
new Rectangle();
302 throw new InvalidOperationException(
"Not enough space to allocate all shadow maps.");
304 var cascadeTextureCoords =
new Vector4(
305 (
float)shadowMapRectangle.Left / (
float)shadowMap.
Texture.ShadowMapDepthTexture.
Width,
306 (
float)shadowMapRectangle.Top / (
float)shadowMap.
Texture.ShadowMapDepthTexture.
Height,
307 (
float)shadowMapRectangle.Right / (
float)shadowMap.
Texture.ShadowMapDepthTexture.
Width,
308 (
float)shadowMapRectangle.Bottom / (
float)shadowMap.
Texture.ShadowMapDepthTexture.
Height);
311 cascades[cascadeLevel].CascadeTextureCoords = cascadeTextureCoords;
314 var boderSizeU = VsmBlurSize / shadowMap.Texture.ShadowMapDepthTexture.Width;
315 var boderSizeV = VsmBlurSize / shadowMap.Texture.ShadowMapDepthTexture.Height;
316 cascadeTextureCoords.X += boderSizeU;
317 cascadeTextureCoords.Y += boderSizeV;
318 cascadeTextureCoords.Z -= boderSizeU;
319 cascadeTextureCoords.W -= boderSizeV;
321 float leftX = (float)shadowMap.
ShadowMapSize / (
float)shadowMap.Texture.ShadowMapDepthTexture.Width * 0.5f;
322 float leftY = (float)shadowMap.
ShadowMapSize / (
float)shadowMap.Texture.ShadowMapDepthTexture.Height * 0.5f;
323 float centerX = 0.5f * (cascadeTextureCoords.X + cascadeTextureCoords.Z);
324 float centerY = 0.5f * (cascadeTextureCoords.Y + cascadeTextureCoords.W);
327 Matrix.Multiply(ref shadowMapView, ref shadowMapProjection, out cascades[cascadeLevel].ViewProjCaster);
332 Matrix.Multiply(ref cascades[cascadeLevel].ViewProjCaster, ref adjustmentMatrix, out cascades[cascadeLevel].ReceiverInfo.ViewProjReceiver);
335 cascades[cascadeLevel].ReceiverInfo.CascadeTextureCoordsBorder = cascadeTextureCoords;
Key of an effect parameter.
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)
ShadowMapRenderer(IServiceRegistry services, RenderPipeline recursivePipeline)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Represents a three dimensional mathematical vector.
A service registry is a IServiceProvider that provides methods to register and unregister services...
static void Translation(ref Vector3 value, out Matrix result)
Creates a translation matrix using the specified offsets.
This Renderer recursively render another RenderPass.
Represents a four dimensional mathematical vector.
int Height
The height of this texture view.
Thread-local storage context used during rendering.
Manage a collection of entities.
Defines the window dimensions of a render-target surface onto which a 3D volume projects.
int Width
The width of this texture view.
System.Windows.Shapes.Rectangle Rectangle
SiliconStudio.Core.Mathematics.Vector3 Vector3
void Normalize()
Converts the vector into a unit vector.
static void TransformCoordinate(ref Vector3 coordinate, ref Matrix transform, out Vector3 result)
Performs a coordinate transformation using the given SiliconStudio.Core.Mathematics.Matrix.
Defines an entry point for mesh instantiation and recursive rendering.
override void OnRendering(RenderContext context)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t size_t z
Represents a 4x4 mathematical matrix.