예제 #1
0
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectMotionBlur"/> class.
        /// </summary>
        /// <param name="graphicsService">The graphics service.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="graphicsService"/> is <see langword="null"/>.
        /// </exception>
        public ObjectMotionBlur(IGraphicsService graphicsService)
            : base(graphicsService)
        {
            _effect = GraphicsService.Content.Load <Effect>("DigitalRune/PostProcessing/ObjectMotionBlur");
            _viewportSizeParameter     = _effect.Parameters["ViewportSize"];
            _sourceTextureParameter    = _effect.Parameters["SourceTexture"];
            _numberOfSamplesParameter  = _effect.Parameters["NumberOfSamples"];
            _velocityTextureParameter  = _effect.Parameters["VelocityTexture"];
            _velocityTexture2Parameter = _effect.Parameters["VelocityTexture2"];
            _maxBlurRadiusParameter    = _effect.Parameters["MaxBlurRadius"];
            _sourceSizeParameter       = _effect.Parameters["SourceSize"];
            _gBuffer0Parameter         = _effect.Parameters["GBuffer0"];
            _jitterTextureParameter    = _effect.Parameters["JitterTexture"];
            _softZExtentParameter      = _effect.Parameters["SoftZExtent"];
            _singlePass             = _effect.CurrentTechnique.Passes["Single"];
            _dualPass               = _effect.CurrentTechnique.Passes["Dual"];
            _downsampleMaxParameter = _effect.CurrentTechnique.Passes["DownsampleMax"];
            _downsampleMaxFromFloatBufferParameter = _effect.CurrentTechnique.Passes["DownsampleMaxFromFloatBuffer"];
            _neighborMaxPass = _effect.CurrentTechnique.Passes["NeighborMax"];
            _softEdgePass    = _effect.CurrentTechnique.Passes["SoftEdge"];
            _jitterTexture   = NoiseHelper.GetGrainTexture(GraphicsService, 128);

            NumberOfSamples = 9;
            MaxBlurRadius   = 20;
        }
예제 #2
0
        private EffectParameterBinding CreateJitterMapBinding <T>(Effect effect,
                                                                  EffectParameter parameter, IDictionary <string, object> opaqueData) where T : Texture
        {
            var jitterMap = NoiseHelper.GetGrainTexture(_graphicsService, NoiseHelper.DefaultJitterMapWidth);

            return(new ConstParameterBinding <T>(effect, parameter, jitterMap as T));
        }
예제 #3
0
        public CloudMapRenderer(IGraphicsService graphicsService)
        {
            if (graphicsService == null)
            {
                throw new ArgumentNullException("graphicsService");
            }

            if (graphicsService.GraphicsDevice.GraphicsProfile == GraphicsProfile.Reach)
            {
                throw new NotSupportedException("The CloudMapRenderer does not support the Reach profile.");
            }

            // One 512x512 noise texture is used for all layers. Each layer which does not have
            // a user defined texture uses a part of this texture.
            _noiseTexture = NoiseHelper.GetGrainTexture(graphicsService, 512);

            _effect = graphicsService.Content.Load <Effect>("DigitalRune/Sky/CloudLayer");
            _parameterViewportSize       = _effect.Parameters["ViewportSize"];
            _parameterTexture0Parameters = _effect.Parameters["Texture0Parameters"];
            _parameterTexture1Parameters = _effect.Parameters["Texture1Parameters"];
            _parameterLerp = _effect.Parameters["LerpParameter"];

            _parameterTextures  = new EffectParameter[LayeredCloudMap.NumberOfTextures];
            _parameterDensities = new EffectParameter[LayeredCloudMap.NumberOfTextures];
            _parameterMatrices  = new EffectParameter[LayeredCloudMap.NumberOfTextures];
            for (int i = 0; i < LayeredCloudMap.NumberOfTextures; i++)
            {
                _parameterTextures[i]  = _effect.Parameters["NoiseTexture" + i];
                _parameterDensities[i] = _effect.Parameters["Density" + i];
                _parameterMatrices[i]  = _effect.Parameters["Matrix" + i];
            }

            _parameterCoverage = _effect.Parameters["Coverage"];
            _parameterDensity  = _effect.Parameters["Density"];

            _passLerp    = _effect.Techniques[0].Passes["Lerp"];
            _passDensity = _effect.Techniques[0].Passes["Density"];
        }
        public override void Update(GameTime gameTime)
        {
            Random random = new Random(1234567);

            // The debug renderer stores all draw commands. In this sample we recreate
            // the draw jobs each frame. --> Clear draw jobs of last frame.
            _debugRenderer.Clear();

            // The DebugRenderer can draw stuff "in" the scene (enabled z test) or "over"
            // the scene (disabled z test).

            // Draw some points and line "in" and "over" the scene.
            for (int i = 0; i < 10; i++)
            {
                var position = new Vector3F(-6, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawPoint(position, Color.Green, false);
            }

            for (int i = 0; i < 10; i++)
            {
                var position = new Vector3F(-4, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawPoint(position, Color.Yellow, true);
            }

            for (int i = 0; i < 10; i++)
            {
                var start = new Vector3F(-2, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                var end   = new Vector3F(-2, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawLine(start, end, Color.Green, false);
            }

            for (int i = 0; i < 10; i++)
            {
                var start = new Vector3F(0, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                var end   = new Vector3F(0, 0, -3) + random.NextVector3F(-0.5f, 0.5f);
                _debugRenderer.DrawLine(start, end, Color.Yellow, true);
            }

            // Text without a specified position is drawn at a default position.
            _debugRenderer.DefaultTextPosition = new Vector2F(10, 100);
            _debugRenderer.DrawText("White objects are positioned in screen space.");
            _debugRenderer.DrawText("Yellow objects are positioned in world space. Depth test disabled.");
            _debugRenderer.DrawText("Other objects are positioned in world space. Depth test enabled.");

            // Text can also be drawn in world space coordinates or in screen space coordinates.
            _debugRenderer.DrawText("WorldSpacePosition (0, 0, 0)", new Vector3F(0, 0, 0), Color.Green, false);
            _debugRenderer.DrawText("WorldSpacePosition (0, 0, -1)", new Vector3F(0, 0, -1), Color.Yellow, true);
            _debugRenderer.DrawText("ScreenPosition (600, 40)", new Vector2F(600, 40), Color.White);
            _debugRenderer.DrawText("ScreenPosition (640, 360)", new Vector2F(640, 360), Color.White);

            // It is often useful to copy textures to the screen for debugging.
            _debugRenderer.DrawTexture(NoiseHelper.GetGrainTexture(GraphicsService, 128), new Rectangle(1000, 10, 128, 128));

            // Axes can be drawn to display poses (positions and orientations).
            _debugRenderer.DrawAxes(new Pose(new Vector3F(0, 0, 0)), 1, true);

            // Axis-aligned bounding boxes (AABB)
            _debugRenderer.DrawAabb(new Aabb(new Vector3F(-0.5f), new Vector3F(0.5f)), new Pose(new Vector3F(2, 0, -3)), Color.Green, false);
            _debugRenderer.DrawAabb(new Aabb(new Vector3F(-0.5f), new Vector3F(0.5f)), new Pose(new Vector3F(4, 0, -3)), Color.Yellow, true);

            // Box shapes
            var orientation = random.NextQuaternionF();

            _debugRenderer.DrawBox(1, 1, 1, new Pose(new Vector3F(-6, 0, -5), orientation), new Color(255, 0, 0, 100), false, false);
            _debugRenderer.DrawBox(1, 1, 1, new Pose(new Vector3F(-6, 0, -5), orientation), Color.Green, true, false);
            _debugRenderer.DrawBox(1, 1, 1, new Pose(new Vector3F(-4, 0, -5), orientation), Color.Yellow, true, true);

            // View volumes (frustums)
            var viewVolume = new PerspectiveViewVolume(1, 2, 0.1f, 1f);

            _debugRenderer.DrawViewVolume(viewVolume, new Pose(new Vector3F(-2, 0, -5), orientation), new Color(0, 255, 0, 100), false, false);
            _debugRenderer.DrawViewVolume(viewVolume, new Pose(new Vector3F(-2, 0, -5), orientation), Color.Green, true, false);
            _debugRenderer.DrawViewVolume(viewVolume, new Pose(new Vector3F(0, 0, -5), orientation), Color.Yellow, true, true);

            // Spheres
            _debugRenderer.DrawSphere(0.5f, new Pose(new Vector3F(2, 0, -5), orientation), new Color(0, 0, 255, 100), false, false);
            _debugRenderer.DrawSphere(0.5f, new Pose(new Vector3F(2, 0, -5), orientation), Color.Green, true, false);
            _debugRenderer.DrawSphere(0.5f, new Pose(new Vector3F(4, 0, -5), orientation), Color.Yellow, true, true);

            // Capsules
            _debugRenderer.DrawCapsule(0.3f, 1, new Pose(new Vector3F(-6, 0, -7), orientation), new Color(255, 255, 0, 100), false, false);
            _debugRenderer.DrawCapsule(0.3f, 1, new Pose(new Vector3F(-6, 0, -7), orientation), Color.Green, true, false);
            _debugRenderer.DrawCapsule(0.3f, 1, new Pose(new Vector3F(-4, 0, -7), orientation), Color.Yellow, true, true);

            // Cylinders
            _debugRenderer.DrawCylinder(0.3f, 1, new Pose(new Vector3F(-2, 0, -7), orientation), new Color(255, 0, 255, 100), false, false);
            _debugRenderer.DrawCylinder(0.3f, 1, new Pose(new Vector3F(-2, 0, -7), orientation), Color.Green, true, false);
            _debugRenderer.DrawCylinder(0.3f, 1, new Pose(new Vector3F(0, 0, -7), orientation), Color.Yellow, true, true);

            // Cones
            _debugRenderer.DrawCone(0.3f, 1, new Pose(new Vector3F(2, 0, -7), orientation), new Color(0, 255, 255, 100), false, false);
            _debugRenderer.DrawCone(0.3f, 1, new Pose(new Vector3F(2, 0, -7), orientation), Color.Green, true, false);
            _debugRenderer.DrawCone(0.3f, 1, new Pose(new Vector3F(4, 0, -7), orientation), Color.Yellow, true, true);

            // The debug renderer can draw any IGeometricObjects, like SceneNodes, RigidBodies, etc.
            _debugRenderer.DrawObject(_geometricObject, Color.Brown, false, false);
            _debugRenderer.DrawObject(_geometricObject, Color.Yellow, true, true);

            // The debug renderer can also an XNA model (without materials).
            _debugRenderer.DrawModel(_xnaModel, new Pose(new Vector3F(0, 2, -2), orientation), new Vector3F(1, 2, 1), new Color(128, 255, 64, 100), false, false);
            _debugRenderer.DrawModel(_xnaModel, new Pose(new Vector3F(0, 2, -2), orientation), new Vector3F(1, 2, 1), Color.LightCyan, true, false);

            // Draw a DigitalRune model.
            _debugRenderer.DrawModel(_modelNode, Color.Peru, true, false);

            // Draw the bounding shapes of the meshes in this model.
            foreach (var node in _modelNode.GetSubtree())
            {
                _debugRenderer.DrawObject(node, Color.PeachPuff, true, false);
            }
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;

            var cameraNode = context.CameraNode;

            _parameterViewInverse.SetValue(cameraNode.PoseWorld);
            _parameterGBuffer0.SetValue(context.GBuffer0);

            Viewport viewport = context.Viewport;

            _parameterParameters0.SetValue(new Vector2(viewport.Width, viewport.Height));

            if (_jitterMap == null)
            {
                _jitterMap = NoiseHelper.GetGrainTexture(context.GraphicsService, NoiseHelper.DefaultJitterMapWidth);
            }

            _parameterJitterMap.SetValue(_jitterMap);

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var shadow = lightNode.Shadow as StandardShadow;
                if (shadow == null)
                {
                    continue;
                }

                if (shadow.ShadowMap == null || shadow.ShadowMask == null)
                {
                    continue;
                }

                // The effect must only render in a specific channel.
                // Do not change blend state if the correct write channels is already set, e.g. if this
                // shadow is part of a CompositeShadow, the correct blend state is already set.
                if ((int)graphicsDevice.BlendState.ColorWriteChannels != (1 << shadow.ShadowMaskChannel))
                {
                    graphicsDevice.BlendState = GraphicsHelper.BlendStateWriteSingleChannel[shadow.ShadowMaskChannel];
                }

                _parameterParameters1.SetValue(new Vector4(
                                                   shadow.Near,
                                                   shadow.Far,
                                                   shadow.EffectiveDepthBias,
                                                   shadow.EffectiveNormalOffset));

                // If we use a subset of the Poisson kernel, we have to normalize the scale.
                int   numberOfSamples = Math.Min(shadow.NumberOfSamples, PoissonKernel.Length);
                float filterRadius    = shadow.FilterRadius;
                if (numberOfSamples > 0)
                {
                    filterRadius /= PoissonKernel[numberOfSamples - 1].Length();
                }

                _parameterParameters2.SetValue(new Vector3(
                                                   shadow.ShadowMap.Width,
                                                   filterRadius,
                                                   // The StandardShadow.JitterResolution is the number of texels per world unit.
                                                   // In the shader the parameter JitterResolution contains the division by the jitter map size.
                                                   shadow.JitterResolution / _jitterMap.Width));

                _parameterLightPosition.SetValue((Vector3)cameraNode.PoseWorld.ToLocalPosition(lightNode.PoseWorld.Position));

                Matrix cameraViewToShadowView = cameraNode.PoseWorld * shadow.View;
                _parameterShadowView.SetValue(cameraViewToShadowView);
                _parameterShadowMatrix.SetValue(cameraViewToShadowView * shadow.Projection);
                _parameterShadowMap.SetValue(shadow.ShadowMap);

                var      rectangle           = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
                Vector2F texCoordTopLeft     = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
                Vector2F texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);
                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                var pass = GetPass(numberOfSamples);

                if (numberOfSamples > 0)
                {
                    if (_lastNumberOfSamples != numberOfSamples)
                    {
                        // Create an array with the first n samples and the rest set to 0.
                        _lastNumberOfSamples = numberOfSamples;
                        for (int j = 0; j < numberOfSamples; j++)
                        {
                            _samples[j].X = PoissonKernel[j].X;
                            _samples[j].Y = PoissonKernel[j].Y;
                            _samples[j].Z = 1.0f / numberOfSamples;

                            // Note [HelmutG]: I have tried weights decreasing with distance but that did not
                            // look better.
                        }

                        // Set the rest to zero.
                        for (int j = numberOfSamples; j < _samples.Length; j++)
                        {
                            _samples[j] = Vector3.Zero;
                        }

                        _parameterSamples.SetValue(_samples);
                    }
                    else if (i == 0)
                    {
                        // Apply offsets in the first loop.
                        _parameterSamples.SetValue(_samples);
                    }
                }

                pass.Apply();

                graphicsDevice.DrawQuad(rectangle);
            }

            _parameterGBuffer0.SetValue((Texture2D)null);
            _parameterJitterMap.SetValue((Texture2D)null);
            _parameterShadowMap.SetValue((Texture2D)null);
            savedRenderState.Restore();
        }
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            context.Validate(_effect);
            context.ThrowIfCameraMissing();

            var graphicsDevice   = _effect.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

            graphicsDevice.DepthStencilState = DepthStencilState.None;
            graphicsDevice.RasterizerState   = RasterizerState.CullNone;

            // Set camera properties.
            var    cameraNode  = context.CameraNode;
            var    cameraPose  = cameraNode.PoseWorld;
            Matrix viewInverse = cameraPose;

            _parameterViewInverse.SetValue(viewInverse);
            _parameterGBuffer0.SetValue(context.GBuffer0);

            Viewport viewport = context.Viewport;

            _parameterParameters0.SetValue(new Vector2(viewport.Width, viewport.Height));

            // Set jitter map.
            if (_jitterMap == null)
            {
                _jitterMap = NoiseHelper.GetGrainTexture(context.GraphicsService, NoiseHelper.DefaultJitterMapWidth);
            }

            _parameterJitterMap.SetValue(_jitterMap);

            float cameraFar = context.CameraNode.Camera.Projection.Far;

            for (int i = 0; i < numberOfNodes; i++)
            {
                var lightNode = nodes[i] as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                var shadow = lightNode.Shadow as CascadedShadow;
                if (shadow == null)
                {
                    continue;
                }

                if (shadow.ShadowMap == null || shadow.ShadowMask == null)
                {
                    continue;
                }

                // The effect must only render in a specific channel.
                // Do not change blend state if the correct write channels is already set, e.g. if this
                // shadow is part of a CompositeShadow, the correct blend state is already set.
                if ((int)graphicsDevice.BlendState.ColorWriteChannels != (1 << shadow.ShadowMaskChannel))
                {
                    graphicsDevice.BlendState = GraphicsHelper.BlendStateWriteSingleChannel[shadow.ShadowMaskChannel];
                }

                _parameterParameters1.SetValue(new Vector4(
                                                   shadow.FadeOutRange,
                                                   shadow.Distances[shadow.NumberOfCascades - 1],
                                                   shadow.VisualizeCascades ? 1 : 0,
                                                   shadow.ShadowFog));

                float filterRadius = shadow.FilterRadius;

                // If we use a subset of the Poisson kernel, we have to normalize the scale.
                int numberOfSamples = Math.Min(shadow.NumberOfSamples, StandardShadowMaskRenderer.PoissonKernel.Length);

                // Not all shader passes support cascade visualization. Use a similar pass instead.
                if (shadow.VisualizeCascades)
                {
                    if (numberOfSamples < 0)
                    {
                        numberOfSamples = 4;
                    }
                    else if (numberOfSamples == 0)
                    {
                        numberOfSamples = 1;
                        filterRadius    = 0;
                    }
                }

                // The best dithered CSM supports max 22 samples.
                if (shadow.CascadeSelection == ShadowCascadeSelection.BestDithered && numberOfSamples > 22)
                {
                    numberOfSamples = 22;
                }

                if (numberOfSamples > 0)
                {
                    filterRadius /= StandardShadowMaskRenderer.PoissonKernel[numberOfSamples - 1].Length();
                }

                _parameterParameters2.SetValue(new Vector4(
                                                   shadow.ShadowMap.Width,
                                                   shadow.ShadowMap.Height,
                                                   filterRadius,
                                                   // The StandardShadow.JitterResolution is the number of texels per world unit.
                                                   // In the shader the parameter JitterResolution contains the division by the jitter map size.
                                                   shadow.JitterResolution / _jitterMap.Width));

                // Split distances.
                if (_parameterDistances != null)
                {
                    // Set not used entries to large values.
                    Vector4 distances = shadow.Distances;
                    for (int j = shadow.NumberOfCascades; j < 4; j++)
                    {
                        distances[j] = 10 * cameraFar;
                    }

                    _parameterDistances.SetValue((Vector4)distances);
                }

                Debug.Assert(shadow.ViewProjections.Length == 4);
                for (int j = 0; j < _matrices.Length; j++)
                {
                    _matrices[j] = viewInverse * shadow.ViewProjections[j];
                }

                _parameterShadowMatrices.SetValue(_matrices);

                _parameterDepthBias.SetValue((Vector4)shadow.EffectiveDepthBias);
                _parameterNormalOffset.SetValue((Vector4)shadow.EffectiveNormalOffset);

                Vector3 lightBackwardWorld = lightNode.PoseWorld.Orientation.GetColumn(2);
                _parameterLightDirection.SetValue((Vector3)cameraPose.ToLocalDirection(lightBackwardWorld));
                _parameterNumberOfCascades.SetValue(shadow.NumberOfCascades);
                _parameterShadowMap.SetValue(shadow.ShadowMap);

                var      rectangle           = GraphicsHelper.GetViewportRectangle(cameraNode, viewport, lightNode);
                Vector2F texCoordTopLeft     = new Vector2F(rectangle.Left / (float)viewport.Width, rectangle.Top / (float)viewport.Height);
                Vector2F texCoordBottomRight = new Vector2F(rectangle.Right / (float)viewport.Width, rectangle.Bottom / (float)viewport.Height);
                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);
                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                var pass = GetPass(numberOfSamples, shadow.CascadeSelection, shadow.VisualizeCascades);

                if (numberOfSamples > 0)
                {
                    if (_lastNumberOfSamples != numberOfSamples)
                    {
                        // Create an array with the first n samples and the rest set to 0.
                        _lastNumberOfSamples = numberOfSamples;
                        for (int j = 0; j < numberOfSamples; j++)
                        {
                            _samples[j].Y = StandardShadowMaskRenderer.PoissonKernel[j].Y;
                            _samples[j].X = StandardShadowMaskRenderer.PoissonKernel[j].X;
                            _samples[j].Z = 1.0f / numberOfSamples;
                        }

                        // Set the rest to zero.
                        for (int j = numberOfSamples; j < _samples.Length; j++)
                        {
                            _samples[j] = Vector3.Zero;
                        }

                        _parameterSamples.SetValue(_samples);
                    }
                    else if (i == 0)
                    {
                        // Apply offsets in the first loop.
                        _parameterSamples.SetValue(_samples);
                    }
                }

                pass.Apply();

                graphicsDevice.DrawQuad(rectangle);
            }

            _parameterGBuffer0.SetValue((Texture2D)null);
            _parameterJitterMap.SetValue((Texture2D)null);
            _parameterShadowMap.SetValue((Texture2D)null);
            savedRenderState.Restore();
        }