Пример #1
0
        public void AddShadowMap(ShadowMap shadowMap)
        {
            shadowMaps.Add(shadowMap);
            shadowMap.Passes  = new RenderPass[shadowMap.LevelCount];
            shadowMap.Plugins = new RenderTargetsPlugin[shadowMap.LevelCount];

            for (int i = 0; i < shadowMap.Passes.Length; i++)
            {
                shadowMap.Passes[i] = new RenderPass(string.Format("Pass {0}", i))
                {
                    Parameters = new ParameterCollection(string.Format("Parameters ShadowMap {0}", i))
                };
                shadowMap.Passes[i].Parameters.AddSources(MainPlugin.ViewParameters);
                shadowMap.Passes[i].Parameters.AddSources(shadowMap.CasterParameters);

                unsafe
                {
                    int currentPassIndex = i;
                    shadowMap.Passes[i].Parameters.AddDynamic(TransformationKeys.ViewProjection,
                                                              ParameterDynamicValue.New(LightingPlugin.ViewProjectionArray, (ref ShadowMapData input, ref Matrix output) =>
                    {
                        fixed(Matrix * vpPtr = &input.ViewProjCaster0)
                        {
                            output = vpPtr[currentPassIndex];
                        }
                    }));
                    shadowMap.Passes[i].Parameters.AddDynamic(LightingPlugin.ShadowLightOffset,
                                                              ParameterDynamicValue.New(LightingPlugin.ViewProjectionArray, (ref ShadowMapData input, ref Vector3 output) =>
                    {
                        fixed(Vector3 * vpPtr = &input.Offset0)
                        {
                            output = vpPtr[currentPassIndex];
                        }
                    }));
                }

                shadowMap.Plugins[i] = new RenderTargetsPlugin
                {
                    Services          = Services,
                    EnableClearTarget = false,
                    EnableClearDepth  = false,
                    RenderPass        = shadowMap.Passes[i],
                    RenderTarget      = null,
                };
                shadowMap.Plugins[i].Apply();
            }

            RenderPass.Passes.InsertRange(0, shadowMap.Passes);

            // Dynamic value used for ViewProjectionArray key
            var dynamicViewProjectionArray = ParameterDynamicValue.New(
                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) =>
            {
                if (projections == null)
                {
                    // Preallocates temporary variables (thread static)
                    projections     = new Matrix[4];
                    views           = new Matrix[4];
                    shadowsViewProj = new Matrix[8];
                    points          = new Vector3[8];
                    directions      = new Vector3[4];
                }

                Matrix inverseView, inverseProjection;
                Matrix.Invert(ref projection, out inverseProjection);
                Matrix.Invert(ref view, out inverseView);

                // Frustum in World Space
                for (int i = 0; i < 8; ++i)
                {
                    Vector3.TransformCoordinate(ref FrustrumBasePoints[i], ref inverseProjection, out points[i]);
                }

                for (int i = 0; i < 4; i++)
                {
                    directions[i] = Vector3.Normalize(points[i + 4] - points[i]);
                }

                // TODO Make these factors configurable. They need also to be correctly tweaked.
                float shadowDistribute = 1.0f / shadowMap.LevelCount;
                float znear            = 1.0f;
                float zfar             = shadowMap.ShadowDistance;

                var shadowOffsets     = new Vector3[shadowMap.LevelCount];
                var boudingBoxVectors = new Vector3[shadowMap.LevelCount * 2];
                var direction         = Vector3.Normalize(lightDirection);

                // Fake value
                // It will be setup by next loop
                Vector3 side = Vector3.UnitX;
                Vector3 up   = Vector3.UnitX;

                // Select best Up vector
                foreach (var vectorUp in VectorUps)
                {
                    if (Vector3.Dot(direction, vectorUp) < (1.0 - 0.0001))
                    {
                        side = Vector3.Normalize(Vector3.Cross(vectorUp, direction));
                        up   = Vector3.Normalize(Vector3.Cross(direction, side));
                        break;
                    }
                }

                for (int cascadeLevel = 0; cascadeLevel < shadowMap.LevelCount; ++cascadeLevel)
                {
                    float k0  = (float)(cascadeLevel + 0) / shadowMap.LevelCount;
                    float k1  = (float)(cascadeLevel + 1) / shadowMap.LevelCount;
                    float min = (float)(znear * Math.Pow(zfar / znear, k0)) * (1.0f - shadowDistribute) + (znear + (zfar - znear) * k0) * shadowDistribute;
                    float max = (float)(znear * Math.Pow(zfar / znear, k1)) * (1.0f - shadowDistribute) + (znear + (zfar - znear) * k1) * shadowDistribute;

                    for (int j = 0; j < shadowMap.LevelCount; j++)
                    {
                        boudingBoxVectors[j] = points[j] + directions[j] * min;
                        boudingBoxVectors[j + shadowMap.LevelCount] = points[j] + directions[j] * max;
                    }
                    var boundingBox = BoundingBox.FromPoints(boudingBoxVectors);

                    var radius = (boundingBox.Maximum - boundingBox.Minimum).Length() * 0.5f;
                    var target = Vector3.TransformCoordinate(boundingBox.Center, inverseView);

                    // Snap camera to texel units (so that shadow doesn't jitter)
                    var shadowMapHalfSize = shadowMap.ShadowMapSize * 0.5f;
                    float x = (float)Math.Ceiling(Vector3.Dot(target, up) * shadowMapHalfSize / radius) * radius / shadowMapHalfSize;
                    float y = (float)Math.Ceiling(Vector3.Dot(target, side) * shadowMapHalfSize / radius) * radius / shadowMapHalfSize;
                    float z = Vector3.Dot(target, direction);
                    //target = up * x + side * y + direction * R32G32B32_Float.Dot(target, direction);
                    target = up * x + side * y + direction * z;

                    views[cascadeLevel]       = Matrix.LookAtLH(target - direction * zfar * 0.5f, target + direction * zfar * 0.5f, up); // View;
                    projections[cascadeLevel] = Matrix.OrthoOffCenterLH(-radius, radius, -radius, radius, znear / zfar, zfar);           // Projection

                    //float leftX = shadowMap.Level == CascadeShadowMapLevel.X1 ? 0.5f : 0.25f;
                    //float leftY = shadowMap.Level == CascadeShadowMapLevel.X4 ? 0.25f : 0.5f;
                    //float centerX = 0.5f * (cascadeLevel % 2) + leftX;
                    //float centerY = 0.5f * (cascadeLevel / 2) + leftY;

                    var cascadeTextureCoords = shadowMap.TextureCoordsBorder[cascadeLevel];

                    float leftX   = (float)shadowMap.ShadowMapSize / (float)AtlasSize * 0.5f;
                    float leftY   = (float)shadowMap.ShadowMapSize / (float)AtlasSize * 0.5f;
                    float centerX = 0.5f * (cascadeTextureCoords.X + cascadeTextureCoords.Z);
                    float centerY = 0.5f * (cascadeTextureCoords.Y + cascadeTextureCoords.W);

                    shadowsViewProj[cascadeLevel]     = views[cascadeLevel] * projections[cascadeLevel];
                    shadowsViewProj[cascadeLevel + 4] = shadowsViewProj[cascadeLevel]
                                                        * Matrix.Scaling(leftX, -leftY, 0.5f)         // Texture0 mapping offsets/scaling
                                                        * Matrix.Translation(centerX, centerY, 0.5f);

                    var shadowVInverse          = Matrix.Invert(views[cascadeLevel]);
                    shadowOffsets[cascadeLevel] = new Vector3(shadowVInverse.M41, shadowVInverse.M42, shadowVInverse.M43);
                }

                result.LightColor = lightColor;

                unsafe
                {
                    fixed(Matrix * resultPtr = &result.ViewProjCaster0)
                    Utilities.Write((IntPtr)resultPtr, shadowsViewProj, 0, shadowsViewProj.Length);

                    fixed(Vector3 * resultPtr = &result.Offset0)
                    Utilities.Write((IntPtr)resultPtr, shadowOffsets, 0, shadowOffsets.Length);
                }
            });

            shadowMap.Parameters.SetDefault(LightKeys.LightDirection);
            shadowMap.Parameters.SetDefault(Offsets);
            shadowMap.Parameters.SetDefault(ViewProjectionArray);
            shadowMap.Parameters.AddDynamic(ViewProjectionArray, dynamicViewProjectionArray);
            shadowMap.CasterParameters.Set(EffectPlugin.RasterizerStateKey, null);
            shadowMap.Texture = shadowMap.Filter is ShadowMapFilterVsm ? ShadowMapVsm : ShadowMapDepth.Texture;
        }
Пример #2
0
 public void RemoveShadowMap(ShadowMap shadowMap)
 {
     shadowMaps.Remove(shadowMap);
     RenderPass.Passes.RemoveAll(shadowMap.Passes.Contains);
 }
Пример #3
0
 public ShadowMapFilterVsm(ShadowMap shadowMap)
     : base(shadowMap)
 {
     MinVariance    = 0.0000001f;
     BleedingFactor = 0.38f;
 }
Пример #4
0
 protected ShadowMapFilter(ShadowMap shadowMap)
 {
     this.shadowMap = shadowMap;
 }
Пример #5
0
 public ShadowMapFilterDefault(ShadowMap shadowMap)
     : base(shadowMap)
 {
 }