Esempio n. 1
0
 /// <summary>
 /// Creates a dynamic parameter key for texel size updated from the texture size.
 /// </summary>
 /// <param name="textureKey">Key of the texture to take the size from</param>
 /// <returns>A dynamic TexelSize parameter key updated according to the specified texture</returns>
 public static ParameterKey <Vector2> CreateDynamicTexelSizeParameterKey(ParameterKey <Texture> textureKey)
 {
     if (textureKey == null)
     {
         throw new ArgumentNullException("textureKey");
     }
     return(ParameterKeys.NewDynamic(ParameterDynamicValue.New <Vector2, Texture>(textureKey, UpdateTexelSize)));
 }
Esempio n. 2
0
        public static ParameterKey <T[]> NewDynamic <T>(int arraySize, ParameterDynamicValue <T[]> dynamicValue, string name = null) where T : struct
        {
            if (name == null)
            {
                name = string.Empty;
            }

            var metadata = new ParameterKeyValueMetadata <T[]>(dynamicValue);
            var result   = new ParameterKey <T[]>(name, arraySize, metadata);

            return(result);
        }
Esempio n. 3
0
        public static ParameterKey <T> NewDynamic <T>(ParameterDynamicValue <T> dynamicValue, string name = null)
        {
            if (name == null)
            {
                name = string.Empty;
            }

            var metadata = new ParameterKeyValueMetadata <T>(dynamicValue);
            var result   = new ParameterKey <T>(name, 1, metadata);

            return(result);
        }
Esempio n. 4
0
 static TransformationKeys()
 {
     View                = ParameterKeys.New(Matrix.Identity);
     Projection          = ParameterKeys.New(Matrix.Identity);
     World               = ParameterKeys.New(Matrix.Identity);
     WorldView           = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix, Matrix>(World, View, Matrix.MultiplyRef));
     WorldViewProjection = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix, Matrix>(World, ViewProjection, Matrix.MultiplyRef));
     ProjScreenRay       = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Vector2, Matrix>(Projection, ExtractProjScreenRay));
     Eye                   = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Vector4, Matrix>(View, ViewToEye));
     EyeMS                 = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Vector4, Matrix>(WorldView, WorldViewToEyeMS));
     WorldInverse          = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix>(World, InvertMatrix));
     WorldInverseTranspose = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix>(WorldInverse, TransposeMatrix));
     ViewInverse           = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix>(View, InvertMatrix));
     ProjectionInverse     = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix>(Projection, InvertMatrix));
     WorldViewInverse      = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Matrix, Matrix>(WorldView, InvertMatrix));
     WorldScale            = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Vector3, Matrix>(World, ExtractScale));
 }
Esempio n. 5
0
        public override void Load()
        {
            base.Load();

            if (OfflineCompilation)
            {
                return;
            }

            var renderTargets = new RenderTarget[2];
            DepthStencilBuffer depthStencilBuffer  = null;
            Texture2D          depthStencilTexture = null;

            Parameters.AddSources(MainPlugin.ViewParameters);

            Parameters.RegisterParameter(EffectPlugin.BlendStateKey);

            var filteredPasses = new FastList <RenderPass>();

            RenderPass.UpdatePasses += updatePassesAction = (RenderPass currentRenderPass, ref FastList <RenderPass> currentPasses) =>
            {
                var originalPasses = currentPasses;
                filteredPasses.Clear();
                currentPasses = filteredPasses;

                Parameters.Set(PickingFrameIndex, ++currentPickingFrameIndex);
                Request[] requests;

                lock (pendingRequests)
                {
                    // No picking request or no mesh to pick?
                    if (pendingRequests.Count == 0)
                    {
                        return;
                    }

                    requests = pendingRequests.ToArray();
                    pendingRequests.Clear();
                }

                foreach (var request in requests)
                {
                    requestResults.Add(request);
                }

                if (originalPasses == null)
                {
                    return;
                }

                // Count mesh passes
                int meshIndex = 0;
                foreach (var pass in originalPasses)
                {
                    meshIndex += pass.Passes.Count;
                }

                // No mesh to pick?
                if (meshIndex == 0)
                {
                    return;
                }

                // Copy mesh passes and assign indices
                var meshPasses = new EffectMesh[meshIndex];
                meshIndex = 0;
                foreach (var pass in RenderPass.Passes)
                {
                    throw new NotImplementedException();
                    //foreach (var effectMeshPass in pass.Meshes)
                    //{
                    //    meshPasses[meshIndex] = (EffectMesh)effectMeshPass;
                    //    // Prefix increment so that 0 means no rendering.
                    //    effectMeshPass.Parameters.Set(PickingMeshIndex, ++meshIndex);
                    //}
                }

                // For now, it generates one rendering per picking.
                // It would be quite easy to optimize it by make Picking shader works on multiple picking points at a time.
                foreach (var request in requests)
                {
                    var pickingRenderPass = new RenderPass("Picking");

                    pickingRenderPass.StartPass.AddFirst = (threadContext) =>
                    {
                        threadContext.GraphicsDevice.Clear(renderTargets[0], Color.Black);
                        threadContext.GraphicsDevice.Clear(renderTargets[1], Color.Black);
                        threadContext.Parameters.Set(PickingScreenPosition, request.Location);
                        threadContext.GraphicsDevice.SetViewport(new Viewport(0, 0, renderTargets[0].Description.Width, renderTargets[0].Description.Height));

                        threadContext.GraphicsDevice.Clear(depthStencilBuffer, DepthStencilClearOptions.DepthBuffer);
                        threadContext.GraphicsDevice.SetRenderTargets(depthStencilBuffer, renderTargets);
                    };
                    pickingRenderPass.EndPass.AddLast = (threadContext) =>
                    {
                        threadContext.Parameters.Reset(PickingScreenPosition);
                        threadContext.GraphicsDevice.Copy(renderTargets[0].Texture, request.ResultTextures[0]);
                        threadContext.GraphicsDevice.Copy(renderTargets[1].Texture, request.ResultTextures[1]);
                    };
                    //pickingRenderPass.PassesInternal = originalPasses;
                    throw new NotImplementedException();

                    request.MeshPasses = meshPasses;

                    currentPasses.Add(pickingRenderPass);

                    request.HasResults = true;

                    // Wait 2 frames before pulling the results.
                    request.FrameCounter = 2;
                }
            };

            RenderSystem.GlobalPass.EndPass.AddLast = CheckPickingResults;

            var backBuffer = GraphicsDevice.BackBuffer;

            int pickingArea = 1 + PickingDistance * 2;

            renderTargets[0] = Texture.New2D(GraphicsDevice, pickingArea, pickingArea, PixelFormat.R32_UInt, TextureFlags.ShaderResource | TextureFlags.RenderTarget).ToRenderTarget().KeepAliveBy(ActiveObjects);
            renderTargets[1] = Texture.New2D(GraphicsDevice, pickingArea, pickingArea, PixelFormat.R32G32B32A32_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget).ToRenderTarget().KeepAliveBy(ActiveObjects);

            depthStencilTexture = Texture.New2D(GraphicsDevice, pickingArea, pickingArea, PixelFormat.D32_Float, TextureFlags.ShaderResource | TextureFlags.DepthStencil).KeepAliveBy(ActiveObjects);
            depthStencilBuffer  = depthStencilTexture.ToDepthStencilBuffer(false);

            Parameters.AddDynamic(PickingMatrix, ParameterDynamicValue.New(PickingScreenPosition, (ref Vector2 pickingPosition, ref Matrix picking) =>
            {
                // Move center to picked position, and zoom (it is supposed to stay per-pixel according to render target size)
                picking = Matrix.Translation(1.0f - (pickingPosition.X) / backBuffer.Width * 2.0f, -1.0f + (pickingPosition.Y) / backBuffer.Height * 2.0f, 0.0f)
                          * Matrix.Scaling((float)backBuffer.Width / (float)pickingArea, (float)backBuffer.Height / (float)pickingArea, 1.0f);
            }));
        }
Esempio n. 6
0
 static CameraKeys()
 {
     ZProjection = ParameterKeys.NewDynamic(ParameterDynamicValue.New <Vector2, float, float>(NearClipPlane, FarClipPlane, ZProjectionACalculate));
 }
Esempio n. 7
0
        public void SetupLighting(EffectShaderPass effectPass, object permutationKeyObject)
        {
            var permutationKey = (LightingPermutation.KeyInfo)permutationKeyObject;

            if (permutationKey.PerPixelDirectionalLightCount > 0)
            {
                effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingPerPixel", permutationKey.PerPixelDirectionalLightCount));

                // Light colors
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerPixelKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
                                                                                                                                          (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
                                                                                                                                          LightColorsUpdate(lightPermutation.PerPixelDirectionalLights, lightColorsWithGamma)
                                                                                                                                          , autoCheckDependencies: false));

                // LightDirectionVS
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerPixelKeys.LightDirectionsVS, ParameterDynamicValue.New(LightingPermutation.Key, TransformationKeys.View, (ref LightingPermutation lightPermutation, ref Matrix view, ref Vector3[] lightDirectionVS) =>
                {
                    int index = 0;
                    foreach (var lightBinding in lightPermutation.PerPixelDirectionalLights)
                    {
                        var lightDirection = ((DirectionalLight)lightBinding.Light).LightDirection;
                        LightKeys.LightDirectionVSUpdate(ref lightDirection, ref view, ref lightDirectionVS[index++]);
                    }
                }, autoCheckDependencies: false));
            }

            if (permutationKey.PerPixelDiffuseDirectionalLightCount > 0)
            {
                effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingDiffusePerPixel", permutationKey.PerPixelDiffuseDirectionalLightCount));

                // Light colors
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingDiffusePerPixelKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
                                                                                                                                                 (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
                                                                                                                                                 LightColorsUpdate(lightPermutation.PerPixelDiffuseDirectionalLights, lightColorsWithGamma)
                                                                                                                                                 , autoCheckDependencies: false));

                // LightDirectionVS
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingDiffusePerPixelKeys.LightDirectionsVS, ParameterDynamicValue.New(LightingPermutation.Key, TransformationKeys.View, (ref LightingPermutation lightPermutation, ref Matrix view, ref Vector3[] lightDirectionVS) =>
                {
                    int index = 0;
                    foreach (var lightBinding in lightPermutation.PerPixelDiffuseDirectionalLights)
                    {
                        var lightDirection = ((DirectionalLight)lightBinding.Light).LightDirection;
                        LightKeys.LightDirectionVSUpdate(ref lightDirection, ref view, ref lightDirectionVS[index++]);
                    }
                }, autoCheckDependencies: false));
            }

            if (permutationKey.PerVertexDirectionalLightCount > 0)
            {
                effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingPerVertex", permutationKey.PerVertexDirectionalLightCount));

                // Light colors
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerVertexKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
                                                                                                                                           (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
                                                                                                                                           LightColorsUpdate(lightPermutation.PerVertexDirectionalLights, lightColorsWithGamma)
                                                                                                                                           , autoCheckDependencies: false));

                // LightDirectionWS
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingPerVertexKeys.LightDirectionsWS, ParameterDynamicValue.New(LightingPermutation.Key, (ref LightingPermutation lightPermutation, ref Vector3[] lightDirectionWS) =>
                {
                    int index = 0;
                    foreach (var lightBinding in lightPermutation.PerVertexDirectionalLights)
                    {
                        lightDirectionWS[index++] = ((DirectionalLight)lightBinding.Light).LightDirection;
                    }
                }, autoCheckDependencies: false));
            }

            if (permutationKey.PerVertexDiffusePixelSpecularDirectionalLightCount > 0)
            {
                effectPass.Shader.Mixins.Add(new ShaderClassSource("LightMultiDirectionalShadingSpecularPerPixel", permutationKey.PerVertexDiffusePixelSpecularDirectionalLightCount));

                // Light colors
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingSpecularPerPixelKeys.LightColorsWithGamma, ParameterDynamicValue.New(LightingPermutation.Key,
                                                                                                                                                  (ref LightingPermutation lightPermutation, ref Color3[] lightColorsWithGamma) =>
                                                                                                                                                  LightColorsUpdate(lightPermutation.PerVertexDiffusePixelSpecularDirectionalLights, lightColorsWithGamma)
                                                                                                                                                  , autoCheckDependencies: false));

                // LightDirectionWS
                effectPass.Parameters.AddDynamic(LightMultiDirectionalShadingSpecularPerPixelKeys.LightDirectionsWS, ParameterDynamicValue.New(LightingPermutation.Key, (ref LightingPermutation lightPermutation, ref Vector3[] lightDirectionWS) =>
                {
                    int index = 0;
                    foreach (var lightBinding in lightPermutation.PerVertexDiffusePixelSpecularDirectionalLights)
                    {
                        lightDirectionWS[index++] = ((DirectionalLight)lightBinding.Light).LightDirection;
                    }
                }, autoCheckDependencies: false));
            }
        }
Esempio n. 8
0
        public void SetupShadersPermutationReceiver(EffectShaderPass effectPass, object permutationKey)
        {
            var currentShadowMapsPermutation = (ShadowMapPermutationArray)permutationKey;

            if (currentShadowMapsPermutation.ShadowMaps.Count == 0)
            {
                return;
            }

            var shadowsArray = new ShaderArraySource();

            effectPass.Shader.Mixins.Add("ShadowMapReceiver");
            effectPass.Shader.Compositions.Add("shadows", shadowsArray);

            // Group by shadow map types (one group can be processed in the same loop).
            // 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).
            var shadowMapTypes = currentShadowMapsPermutation.ShadowMaps.GroupBy(x => Tuple.Create(x.ShadowMap.Filter.GetType(), x.ShadowMap.LevelCount, x.ShadowMap.Texture));

            int shadowMapTypeIndex = 0;

            foreach (var shadowMapType in shadowMapTypes)
            {
                var shadowMapTypeCopy = shadowMapType.ToArray();
                var shadowMixin       = new ShaderMixinSource();

                // Currently use shadow map count, but we should probably use next power of two to limit number of permutations.
                var maxShadowMapCount = shadowMapTypeCopy.Length;

                // Setup shadow mapping
                shadowMixin.Mixins.Add(new ShaderClassSource("ShadowMapCascadeBase", shadowMapType.Key.Item2, 0, maxShadowMapCount, 1));
                //shadowMixin.Mixins.Add(new ShaderClassSource("LightDirectionalShading", shadowMapPermutation.Index));

                // Setup the filter
                // TODO: Use static based on type of filter? (should use Key instead of First()).
                shadowMixin.Mixins.Add(shadowMapType.First().ShadowMap.Filter.GenerateShaderSource(maxShadowMapCount));

                shadowsArray.Add(shadowMixin);

                // Register keys for this shadow map type
                var shadowSubKey = string.Format(".shadows[{0}]", shadowMapTypeIndex++);

                effectPass.Parameters.Set(ShadowMapKeys.Texture.AppendKey(shadowSubKey), shadowMapType.Key.Item3);

                effectPass.Parameters.Set(LightingPlugin.ShadowMapLightCount.AppendKey(shadowSubKey), shadowMapTypeCopy.Length);

                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) =>
                {
                    unsafe
                    {
                        for (int i = 0; i < shadowMapTypeCopy.Length; ++i)
                        {
                            var permutationParameters = shadowMapTypeCopy[i].ShadowMap.Parameters;

                            // TODO: Optimize dictionary access this using SetKeyMapping
                            var shadowMapData  = permutationParameters.Get(LightingPlugin.ViewProjectionArray);
                            var textureCoords  = permutationParameters.Get(LightingPlugin.CascadeTextureCoordsBorder);
                            var distanceMax    = permutationParameters.Get(ShadowMapKeys.DistanceMax);
                            var lightDirection = permutationParameters.Get(LightKeys.LightDirection);

                            Matrix *vpPtr         = &shadowMapData.ViewProjReceiver0;
                            fixed(Matrix * wvpPtr = &output[i].WorldViewProjReceiver0)
                            {
                                for (int j = 0; j < 4; ++j)
                                {
                                    Matrix.Multiply(ref world, ref vpPtr[j], ref wvpPtr[j]);
                                }
                            }

                            output[i].Offset0 = shadowMapData.Offset0;
                            output[i].Offset1 = shadowMapData.Offset1;
                            output[i].Offset2 = shadowMapData.Offset2;
                            output[i].Offset3 = shadowMapData.Offset3;

                            fixed(Vector4 * targetPtr = &output[i].CascadeTextureCoordsBorder0)
                            fixed(Vector4 * sourcePtr = &textureCoords[0])
                            {
                                for (int j = 0; j < 4; ++j)
                                {
                                    targetPtr[j] = sourcePtr[j];
                                }
                            }

                            output[i].ShadowLightDirection = lightDirection;
                            LightKeys.LightDirectionVSUpdate(ref output[i].ShadowLightDirection, ref viewProj, ref output[i].ShadowLightDirectionVS);
                            output[i].ShadowMapDistance = distanceMax;
                            output[i].ShadowLightColor  = shadowMapData.LightColor;
                        }
                    }
                }, autoCheckDependencies: false));     // Always update (permutation won't get updated, only its content)!

                // Register VSM filter if necessary
                if (shadowMapType.Key.Item1 == typeof(ShadowMapFilterVsm))
                {
                    effectPass.Parameters.AddDynamic(LightingPlugin.ReceiverVsmInfo.AppendKey(shadowSubKey), ParameterDynamicValue.New(ShadowMapPermutationArray.Key, (ref ShadowMapPermutationArray shadowMapPermutations, ref ShadowMapReceiverVsmInfo[] output) =>
                    {
                        for (int i = 0; i < shadowMapTypeCopy.Length; ++i)
                        {
                            var permutationParameters = shadowMapTypeCopy[i].ShadowMap.Parameters;
                            output[i].BleedingFactor  = permutationParameters.Get(ShadowMapFilterVsm.VsmBleedingFactor);
                            output[i].MinVariance     = permutationParameters.Get(ShadowMapFilterVsm.VsmMinVariance);
                        }
                    }, autoCheckDependencies: false));
                }
            }
        }
Esempio n. 9
0
        public override void Initialize()
        {
            base.Initialize();

            boundingBoxPass   = new RenderPass("BoundingBoxPass");
            minMaxPass        = new RenderPass("MinmaxPass");
            lightShaftPass    = new RenderPass("LightShaftPass");
            filterUpscalePass = new RenderPass("UpscalePass");
            RenderPass.AddPass(boundingBoxPass, minMaxPass, lightShaftPass, filterUpscalePass);

            var useUpScaling = false;

            var bbRenderTargetPlugin = new RenderTargetsPlugin("BoundingBoxRenderTargetPlugin")
            {
                EnableSetTargets  = true,
                EnableClearTarget = true,
                RenderPass        = boundingBoxPass,
                Services          = Services,
            };

            var minMaxEffectBuilder = this.EffectSystemOld.BuildEffect("MinMax")
                                      .Using(new MinMaxShaderPlugin("MinMaxShaderPlugin")
            {
                RenderPassPlugin = bbRenderTargetPlugin
            })
                                      .Using(new BasicShaderPlugin("TransformationWVP")
            {
                RenderPassPlugin = bbRenderTargetPlugin
            });


            var minmaxEffectBuilder = this.EffectSystemOld.BuildEffect("LightShaftsMinMax")
                                      .Using(new PostEffectSeparateShaderPlugin()
            {
                RenderPass = minMaxPass
            })
                                      .Using(new BasicShaderPlugin("ForwardShadowMapBase")
            {
                RenderPass = minMaxPass
            })
                                      .Using(new BasicShaderPlugin(new ShaderClassSource("PostEffectMinMax", "ShadowMapUtils.shadowMapTexture", "PointSampler", 4, 4, 0.0, 1.0))
            {
                RenderPass = minMaxPass
            });

            var lightShaftsEffectBuilder = this.EffectSystemOld.BuildEffect("LightShafts")
                                           .Using(new PostEffectSeparateShaderPlugin()
            {
                RenderPass = lightShaftPass
            })
                                           .Using(new StateShaderPlugin()
            {
                UseBlendState = !useUpScaling, RenderPass = lightShaftPass
            })
                                           //.Using(new BasicShaderPlugin(new ShaderClassSource("PostEffectLightShafts", Debug ? 1 : 0, RenderContext.IsZReverse ? 1 : 0, StepCount)) { RenderPass = lightShaftPass });
                                           .Using(new BasicShaderPlugin(new ShaderClassSource("PostEffectLightShafts", Debug ? 1 : 0, false ? 1 : 0, StepCount))
            {
                RenderPass = lightShaftPass
            });

            if (OfflineCompilation)
            {
                minMaxEffectBuilder.InstantiatePermutation();
                minmaxEffectBuilder.InstantiatePermutation();
                lightShaftsEffectBuilder.InstantiatePermutation();
                return;
            }

            Parameters.AddSources(ViewParameters);
            Parameters.Set(RenderTargetKeys.DepthStencilSource, DepthStencil.Texture);
            Parameters.Set(TexturingKeys.Sampler, GraphicsDevice.SamplerStates.PointClamp);

            // BoundingBox prepass
            var gbufferDesc    = RenderTarget.Description;
            var bbRenderTarget = Texture.New2D(GraphicsDevice, gbufferDesc.Width / 8, gbufferDesc.Height / 8, PixelFormat.R32G32_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget);

            // Use MinMax Plugin
            bbRenderTargetPlugin.RenderTarget = bbRenderTarget.ToRenderTarget();
            bbRenderTargetPlugin.Parameters.AddSources(Parameters);
            bbRenderTargetPlugin.Apply();

            EffectOld minMaxEffect = minMaxEffectBuilder.InstantiatePermutation();

            // Add meshes
            foreach (var bbMeshData in BoundingBoxes)
            {
                // Mesh for MinPass
                var bbMesh = new EffectMesh(minMaxEffect, bbMeshData).KeepAliveBy(this);
                // Add mesh
                // boundingBoxPass.AddPass(bbMesh.EffectMeshPasses[0].EffectPass);
                RenderSystem.GlobalMeshes.AddMesh(bbMesh);
            }

            // MinMax render target
            var minMaxRenderTarget = Texture.New2D(GraphicsDevice, 256, 256, PixelFormat.R32G32_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget);

            minMaxPass.Parameters = new ParameterCollection(null);
            minMaxPass.Parameters.AddSources(ShadowMap.Parameters);
            minMaxPass.Parameters.AddSources(Parameters);
            minMaxPass.Parameters.AddDynamic(PostEffectMinMaxKeys.MinMaxCoords, ParameterDynamicValue.New(LightingPlugin.CascadeTextureCoords, (ref Vector4[] cascadeTextureCoords, ref Vector4 output) =>
            {
                output = cascadeTextureCoords[0];
            }, autoCheckDependencies: false));

            EffectOld minmaxEffect = minmaxEffectBuilder.InstantiatePermutation();

            var minMaxMesh = new EffectMesh(minmaxEffect).KeepAliveBy(this);

            minMaxMesh.Parameters.Set(RenderTargetKeys.RenderTarget, minMaxRenderTarget.ToRenderTarget());
            RenderSystem.GlobalMeshes.AddMesh(minMaxMesh);

            // Light Shafts effect
            var blendStateDesc = new BlendStateDescription();

            blendStateDesc.SetDefaults();
            blendStateDesc.AlphaToCoverageEnable        = false;
            blendStateDesc.IndependentBlendEnable       = false;
            blendStateDesc.RenderTargets[0].BlendEnable = true;

            blendStateDesc.RenderTargets[0].AlphaBlendFunction    = BlendFunction.Add;
            blendStateDesc.RenderTargets[0].AlphaSourceBlend      = Blend.One;
            blendStateDesc.RenderTargets[0].AlphaDestinationBlend = Blend.One;

            blendStateDesc.RenderTargets[0].ColorBlendFunction    = BlendFunction.Add;
            blendStateDesc.RenderTargets[0].ColorSourceBlend      = Blend.One;
            blendStateDesc.RenderTargets[0].ColorDestinationBlend = Blend.One;

            blendStateDesc.RenderTargets[0].ColorWriteChannels = ColorWriteChannels.All;

            var additiveBlending = BlendState.New(GraphicsDevice, blendStateDesc);

            additiveBlending.Name = "LightShaftAdditiveBlend";

            var shaftRenderTarget = useUpScaling ? Texture.New2D(GraphicsDevice, gbufferDesc.Width / 2, gbufferDesc.Height / 2, PixelFormat.R16G16B16A16_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget).ToRenderTarget() : RenderTarget;


            lightShaftPass.Parameters = new ParameterCollection();
            lightShaftPass.Parameters.AddSources(ShadowMap.Parameters);
            lightShaftPass.Parameters.AddSources(Parameters);

            this.lightShaftsEffect = lightShaftsEffectBuilder.InstantiatePermutation();


            var mesh = new EffectMesh(lightShaftsEffect).KeepAliveBy(this);

            mesh.Parameters.Set(TexturingKeys.Texture0, minMaxRenderTarget);
            mesh.Parameters.Set(TexturingKeys.Texture1, bbRenderTarget);
            mesh.Parameters.Set(RenderTargetKeys.RenderTarget, shaftRenderTarget);

            if (!useUpScaling)
            {
                mesh.Parameters.Set(EffectPlugin.BlendStateKey, additiveBlending);
            }
            RenderSystem.GlobalMeshes.AddMesh(mesh);

            // Bilateral Gaussian filtering for up-sampling
            if (useUpScaling)
            {
                var bbRenderTargetUpScaleH = Texture.New2D(GraphicsDevice, gbufferDesc.Width, gbufferDesc.Height / 2, PixelFormat.R16G16B16A16_Float, TextureFlags.ShaderResource | TextureFlags.RenderTarget);
                var bbRenderTargetUpScaleV = RenderTarget;
                //var bbRenderTargetUpScaleV = GraphicsDevice.RenderTarget2D.New(gbufferDesc.Width, gbufferDesc.Height, PixelFormat.HalfVector4);

                var blurEffects = new EffectOld[] {
                    this.EffectSystemOld.BuildEffect("BilateralGaussianFiltering")
                    .Using(new PostEffectSeparateShaderPlugin())
                    .Using(new BasicShaderPlugin(new ShaderClassSource("PostEffectBilateralGaussian", 0))),
                    this.EffectSystemOld.BuildEffect("BilateralGaussianFiltering")
                    .Using(new StateShaderPlugin()
                    {
                        UseBlendState = true
                    })
                    .Using(new PostEffectSeparateShaderPlugin())
                    .Using(new BasicShaderPlugin(new ShaderClassSource("PostEffectBilateralGaussian", 1))),
                };

                Texture2D    textureSourceH = (Texture2D)shaftRenderTarget.Texture;
                Texture2D    textureSourceV = bbRenderTargetUpScaleH;
                RenderTarget renderTargetH  = bbRenderTargetUpScaleH.ToRenderTarget();
                RenderTarget renderTargetV  = bbRenderTargetUpScaleV;

                var blurQuadMesh = new EffectMesh[2];
                for (int i = 0; i < 2; ++i)
                {
                    blurQuadMesh[i] = new EffectMesh(blurEffects[i]).KeepAliveBy(this);
                    filterUpscalePass.AddPass(blurQuadMesh[i].EffectPass);
                    RenderSystem.GlobalMeshes.AddMesh(blurQuadMesh[i]);
                }

                blurQuadMesh[0].Parameters.Set(TexturingKeys.Texture0, textureSourceH);
                blurQuadMesh[1].Parameters.Set(TexturingKeys.Texture0, textureSourceV);
                blurQuadMesh[0].Parameters.Set(RenderTargetKeys.RenderTarget, renderTargetH);
                blurQuadMesh[1].Parameters.Set(RenderTargetKeys.RenderTarget, renderTargetV);

                // Additive blending for 2nd render target
                blurQuadMesh[1].Parameters.Set(EffectPlugin.BlendStateKey, additiveBlending);
            }
        }
Esempio n. 10
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;
        }