Exemplo n.º 1
0
        /// <summary>
        /// Creates a graphics mesh with the triangle mesh data of the given shape and the given
        /// diffuse and specular material properties.
        /// </summary>
        /// <param name="contentManager">The contentManager manager.</param>
        /// <param name="graphicsService">The graphics service.</param>
        /// <param name="shape">The shape.</param>
        /// <param name="diffuse">The diffuse material color.</param>
        /// <param name="specular">The specular material color.</param>
        /// <param name="specularPower">The specular power of the material.</param>
        /// <returns>The graphics mesh.</returns>
        public static Mesh CreateMesh(ContentManager contentManager, IGraphicsService graphicsService, Shape shape,
                                      Vector3 diffuse, Vector3 specular, float specularPower)
        {
            // Create a DigitalRune.Geometry.Meshes.TriangleMesh from the shape and
            // convert this to a DigitalRune.Graphics.Mesh.
            TriangleMesh triangleMesh = shape.GetMesh(0.01f, 4);

            Submesh submesh = CreateSubmeshWithTexCoords(
                graphicsService.GraphicsDevice,
                triangleMesh,
                MathHelper.ToRadians(70));

            var mesh = CreateMesh(contentManager, graphicsService, submesh, diffuse, specular, specularPower);

            // Set bounding shape to a box that is equal to the AABB of the shape.
            var aabb     = shape.GetAabb(Pose.Identity);
            var boxShape = new BoxShape(aabb.Extent);
            var center   = aabb.Center;

            if (center.IsNumericallyZero)
            {
                mesh.BoundingShape = boxShape;
            }
            else
            {
                mesh.BoundingShape = new TransformedShape(new GeometricObject(boxShape, new Pose(center)));
            }

            return(mesh);
        }
Exemplo n.º 2
0
        public OcclusionCullingScreen(IServiceLocator services)
            : base(services)
        {
            _sceneNodes = new List <SceneNode>();

            // Create new occlusion buffer with default settings.
            OcclusionBuffer = new OcclusionBuffer(GraphicsService);
            OcclusionBuffer.ProgressiveShadowCasterCulling = true;

            EnableCulling = true;

            // Create a second camera for rendering a top-down view of the scene.
            var topDownPerspective = new PerspectiveProjection();

            topDownPerspective.SetFieldOfView(MathHelper.ToRadians(90), 1, 1, 512);
            _topDownCameraNode           = new CameraNode(new Camera(topDownPerspective));
            _topDownCameraNode.PoseWorld = new Pose(new Vector3F(-10, 120, -10));
            _topDownCameraNode.LookAt(new Vector3F(-10, 0, -10), Vector3F.UnitZ);

            _sceneQuery    = new CustomSceneQuery();
            _debugRenderer = new DebugRenderer(GraphicsService, null, null);

            // The DigitalRune Profiler is used to measure execution times.
            Profiler.SetFormat("Occlusion.Render", 1e3f, "[ms]");
            Profiler.SetFormat("Occlusion.Query", 1e3f, "[ms]");
        }
Exemplo n.º 3
0
        // Creates a 32x32 texture which defines the water flow (direction + speed).
        private Texture2D GenerateFlowMap()
        {
            const int size = 32;
            var       data = new Color[size * size];

            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    Vector2F flowDirection;
                    float    flowSpeed;
                    GetFlow(new Vector2F(x / (float)size, y / (float)size), out flowDirection, out flowSpeed);

                    // Encode in color. The flow map stores the normalized 2D direction in r and g.
                    // The speed (magnitude of the flow vector) is stored in b, where 0 represents
                    // no movement and 1 represents movement with max speed.

                    flowSpeed = MathHelper.Clamp(flowSpeed, 0, 1);

                    // Convert to byte.
                    data[y * size + x] = new Color(
                        (byte)((flowDirection.X / 2 + 0.5f) * 255),
                        (byte)((flowDirection.Y / 2 + 0.5f) * 255),
                        (byte)(flowSpeed * 255));
                }
            }

            var texture = new Texture2D(GraphicsService.GraphicsDevice, size, size, true, SurfaceFormat.Color);

            texture.SetData(data);

            return(texture);
        }
Exemplo n.º 4
0
        public Vector3 GetSunlight()
        {
            if (SunDirection.Y >= 0)
            {
                //----- Sun is above horizon.
                return(GetTransmittance(SunDirection) * SunIntensity);
            }

            //----- Sun is below horizon.
            // Get angle.
            float sunAngle = (float)MathHelper.ToDegrees(Math.Asin(SunDirection.Y));

            if (sunAngle < -5)
            {
                return(Vector3.Zero);
            }

            // Sample horizon instead of real direction.
            Vector3 direction = SunDirection;

            direction.Y = 0;
            if (!direction.TryNormalize())
            {
                return(Vector3.Zero);
            }

            Vector3 horizonSunlight = GetTransmittance(direction) * SunIntensity;

            // Lerp horizon sunlight to 0 at -5°.
            float f = 1 - MathHelper.Clamp(-sunAngle / 5.0f, 0, 1);

            return(horizonSunlight * f);
        }
Exemplo n.º 5
0
        public override void Update(GameTime gameTime)
        {
            // If <Space> is pressed, we fire a shot.
            if (InputService.IsPressed(Keys.Space, true))
            {
                // Get a random angle and a random distance from the target.
                float angle    = _angleDistribution.Next(_random);
                float distance = _distanceDistribution.Next(_random);

                // Create a vector v with the length of distance.
                Vector3 v = new Vector3(0, distance, 0);

                // Rotate v.
                Quaternion rotation = Quaternion.CreateRotationZ(MathHelper.ToRadians(angle));
                v = rotation.Rotate(v);

                // Draw a small cross for the hit.
                var debugRenderer = GraphicsScreen.DebugRenderer2D;
                debugRenderer.DrawLine(
                    _center + v + new Vector3(-10, -10, 0),
                    _center + v + new Vector3(10, 10, 0),
                    Color.Black,
                    true);
                debugRenderer.DrawLine(
                    _center + v + new Vector3(10, -10, 0),
                    _center + v + new Vector3(-10, 10, 0),
                    Color.Black, true);
            }

            base.Update(gameTime);
        }
Exemplo n.º 6
0
    public bool GetDisplacement(float x, float z, out Vector3 displacement, out Vector3 normal)
    {
      if (!EnableCpuQueries)
        throw new InvalidOperationException("OceanWaves.GetDisplacement() can only be called if EnableCpuQueries is set to true.");

      displacement = new Vector3(0);
      normal = new Vector3(0, 1, 0);
      if (_h == null)
        return false;

      float texCoordX = (x - TileCenter.X) / TileSize + 0.5f;
      float texCoordY = (z - TileCenter.Z) / TileSize + 0.5f;

      // Point sampling or bilinear filtering:

      // Convert to array indices.
      int xIndex = Wrap((int)(texCoordX * CpuSize));
      int yIndex = Wrap((int)(texCoordY * CpuSize));

      float h = _h[xIndex, yIndex].X;
      Vector2F d = _D[xIndex, yIndex];
      Vector2F n = _N[xIndex, yIndex];
#else
      // Sample 4 values. The upper left index is (without wrapping):
      float xIndex = texCoordX * CpuSize - 0.5f;
      float yIndex = texCoordY * CpuSize - 0.5f;

      // Get the 4 indices.
      int x0 = Wrap((int)xIndex);
      int x1 = Wrap((int)xIndex + 1);
      int y0 = Wrap((int)yIndex);
      int y1 = Wrap((int)yIndex + 1);

      // Get fractions to use as lerp parameters.
      float px = MathHelper.Frac(xIndex);
      float py = MathHelper.Frac(yIndex);

      float h = InterpolationHelper.Lerp(InterpolationHelper.Lerp(_h[x0, y0].X, _h[x1, y0].X, px),
                                         InterpolationHelper.Lerp(_h[x0, y1].X, _h[x1, y1].X, px),
                                         py);

      Vector2F d = InterpolationHelper.Lerp(InterpolationHelper.Lerp(_D[x0, y0], _D[x1, y0], px),
                                            InterpolationHelper.Lerp(_D[x0, y1], _D[x1, y1], px),
                                            py);

      Vector2F n = InterpolationHelper.Lerp(InterpolationHelper.Lerp(_N[x0, y0], _N[x1, y0], px),
                                            InterpolationHelper.Lerp(_N[x0, y1], _N[x1, y1], px),
                                            py);


      displacement = new Vector3(-d.X * Choppiness, h, -d.Y * Choppiness);

      normal = new Vector3(-n.X, 0, -n.Y);
      normal.Y = (float)Math.Sqrt(1 - normal.X * normal.X - normal.Y * normal.Y);
      return true;
    }
Exemplo n.º 7
0
        public void GetScreenSizeWithPerspective()
        {
            // Camera
            var projection = new PerspectiveProjection();

            projection.SetFieldOfView(MathHelper.ToRadians(90), 2.0f / 1.0f, 1.0f, 100f);
            var camera     = new Camera(projection);
            var cameraNode = new CameraNode(camera);

            cameraNode.PoseWorld = new Pose(new Vector3(123, 456, -789), Matrix.CreateRotation(new Vector3(1, -2, 3), MathHelper.ToRadians(75)));

            // 2:1 viewport
            var viewport = new Viewport(10, 10, 200, 100);

            // Test object
            var shape           = new SphereShape();
            var geometricObject = new GeometricObject(shape);

            // Empty sphere at camera position.
            shape.Radius         = 0;
            geometricObject.Pose = cameraNode.PoseWorld;
            Vector2F screenSize = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);

            Assert.AreEqual(0, screenSize.X);
            Assert.AreEqual(0, screenSize.Y);

            // Empty sphere centered at near plane.
            shape.Radius         = 0;
            geometricObject.Pose = cameraNode.PoseWorld * new Pose(new Vector3(0.123f, -0.543f, -1));
            screenSize           = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
            Assert.AreEqual(0, screenSize.X);
            Assert.AreEqual(0, screenSize.Y);

            // Create sphere which as a bounding sphere of ~1 unit diameter:
            // Since the bounding sphere is based on the AABB, we need to make the
            // actual sphere a bit smaller.
            shape.Radius = 1 / (2 * (float)Math.Sqrt(3)) + Numeric.EpsilonF;

            // Sphere at camera position.
            geometricObject.Pose = cameraNode.PoseWorld;
            screenSize           = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
            Assert.Greater(screenSize.X, 200);
            Assert.Greater(screenSize.Y, 100);

            // Sphere at near plane.
            geometricObject.Pose = cameraNode.PoseWorld * new Pose(new Vector3(0.123f, -0.543f, -1));
            screenSize           = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
            Assert.IsTrue(Numeric.AreEqual(screenSize.X, 50.0f, 10f));
            Assert.IsTrue(Numeric.AreEqual(screenSize.Y, 50.0f, 10f));

            // Double distance --> half size
            geometricObject.Pose = cameraNode.PoseWorld * new Pose(new Vector3(0.123f, -0.543f, -2));
            screenSize           = GraphicsHelper.GetScreenSize(cameraNode, viewport, geometricObject);
            Assert.IsTrue(Numeric.AreEqual(screenSize.X, 25.0f, 5f));
            Assert.IsTrue(Numeric.AreEqual(screenSize.Y, 25.0f, 5f));
        }
Exemplo n.º 8
0
        // Called when Kinect has new skeleton data.
        private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs eventArgs)
        {
            // Get the new skeleton data from Kinect.
            using (var skeletonFrame = eventArgs.OpenSkeletonFrame())
            {
                if (skeletonFrame == null)
                {
                    return;
                }

                if (_kinectSkeletons == null || _kinectSkeletons.Length != skeletonFrame.SkeletonArrayLength)
                {
                    _kinectSkeletons = new KinectSkeleton[skeletonFrame.SkeletonArrayLength];
                }

                skeletonFrame.CopySkeletonDataTo(_kinectSkeletons);
            }

            // Get the two tracked skeletons.
            KinectSkeleton skeletonDataA = null;
            KinectSkeleton skeletonDataB = null;

            foreach (var skeleton in _kinectSkeletons)
            {
                if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
                {
                    if (skeletonDataA == null)
                    {
                        skeletonDataA = skeleton;
                    }
                    else
                    {
                        skeletonDataB = skeleton;
                    }
                }
            }

            // Make sure that each player uses the same skeleton as last time.
            // Swap skeleton data if necessary.
            if (skeletonDataA != null && skeletonDataA.TrackingId == _trackingIdB ||
                skeletonDataB != null && skeletonDataB.TrackingId == _trackingIdA)
            {
                MathHelper.Swap(ref skeletonDataA, ref skeletonDataB);
            }

            // Update tracking IDs.
            _trackingIdA = (skeletonDataA != null) ? skeletonDataA.TrackingId : 0;
            _trackingIdB = (skeletonDataB != null) ? skeletonDataB.TrackingId : 0;

            // Update the SkeletonPose from the Kinect skeleton data.
            UpdateKinectSkeletonPose(skeletonDataA, SkeletonPoseA);
            UpdateKinectSkeletonPose(skeletonDataB, SkeletonPoseB);
        }
Exemplo n.º 9
0
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            // <1> / <Shift> + <1> --> Change strength.
            if (InputService.IsDown(Keys.D1))
            {
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float sign        = isShiftDown ? +1 : -1;
                float time        = (float)gameTime.ElapsedGameTime.TotalSeconds;
                float delta       = sign * time * 0.2f;
                _grainFilter.Strength = Math.Max(0, _grainFilter.Strength + delta);
            }

            // <2> / <Shift> + <2> --> Change grain scale.
            if (InputService.IsDown(Keys.D2))
            {
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float sign        = isShiftDown ? +1 : -1;
                float time        = (float)gameTime.ElapsedGameTime.TotalSeconds;
                float delta       = sign * time * 0.2f;
                _grainFilter.GrainScale = Math.Max(1, _grainFilter.GrainScale + delta);
            }

            // <3> / <Shift> + <3> --> Change luminance threshold.
            if (InputService.IsDown(Keys.D3))
            {
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float sign        = isShiftDown ? +1 : -1;
                float time        = (float)gameTime.ElapsedGameTime.TotalSeconds;
                float delta       = sign * time * 0.2f;
                _grainFilter.LuminanceThreshold = MathHelper.Clamp(_grainFilter.LuminanceThreshold + delta, 0, 1);
            }

            // <4> --> Toggle ScaleWithLuminance.
            if (InputService.IsPressed(Keys.D4, false))
            {
                _grainFilter.ScaleWithLuminance = !_grainFilter.ScaleWithLuminance;
            }

            // <5> --> Toggle IsAnimated.
            if (InputService.IsPressed(Keys.D5, false))
            {
                _grainFilter.IsAnimated = !_grainFilter.IsAnimated;
            }

            GraphicsScreen.DebugRenderer.DrawText(
                "\n\nHold <1> or <Shift>+<1> to decrease or increase the grain strength: " + _grainFilter.Strength
                + "\nHold <2> or <Shift>+<2> to decrease or increase the grain scale: " + _grainFilter.GrainScale
                + "\nHold <3> or <Shift>+<3> to decrease or increase the luminance threshold: " + _grainFilter.LuminanceThreshold
                + "\nPress <4> to toggle 'scale with luminance': " + _grainFilter.ScaleWithLuminance
                + "\nPress <5> to toggle between animated and static noise: " + _grainFilter.IsAnimated);
        }
Exemplo n.º 10
0
        private void UpdateSteeringAngle(float deltaTime)
        {
            // TODO: Reduce max steering angle at high speeds.

            const float MaxAngle     = 0.5f;
            const float SteeringRate = 3;

            // We limit the amount of change per frame.
            float change = SteeringRate * deltaTime;

            float direction = 0;

            if (_inputService.IsDown(Keys.A))
            {
                direction += 1;
            }
            if (_inputService.IsDown(Keys.D))
            {
                direction -= 1;
            }

            var gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            direction -= gamePadState.ThumbSticks.Left.X;

            if (direction != 0)
            {
                // Increase steering angle.
                _steeringAngle = MathHelper.Clamp(_steeringAngle + direction * change, -MaxAngle, +MaxAngle);
            }
            else
            {
                // Steer back to neutral position (angle 0).
                if (_steeringAngle > 0)
                {
                    _steeringAngle = MathHelper.Clamp(_steeringAngle - change, 0, +MaxAngle);
                }
                else if (_steeringAngle < 0)
                {
                    _steeringAngle = MathHelper.Clamp(_steeringAngle + change, -MaxAngle, 0);
                }

                // TODO: Maybe we steer back with half rate?
                // (Pressing a button steers faster than not pressing a button?)
            }

            VehicleHelper.SetCarSteeringAngle(_steeringAngle, Vehicle.Wheels[0], Vehicle.Wheels[1], Vehicle.Wheels[2], Vehicle.Wheels[3]);
        }
    private void UpdateOrientation(float deltaTime)
    {
      GamePadState gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

      // Compute new yaw and pitch from mouse movement and gamepad.
      float deltaYaw = -_inputService.MousePositionDelta.X;
      deltaYaw -= gamePadState.ThumbSticks.Right.X * ThumbStickFactor;
      _yaw += deltaYaw * deltaTime * AngularVelocityMagnitude;

      float deltaPitch = -_inputService.MousePositionDelta.Y;
      deltaPitch += gamePadState.ThumbSticks.Right.Y * ThumbStickFactor;
      _pitch += deltaPitch * deltaTime * AngularVelocityMagnitude;

      // Limit the pitch angle to +/- 90°.
      _pitch = MathHelper.Clamp(_pitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);
    }
Exemplo n.º 12
0
        private void UpdateAcceleration(float deltaTime)
        {
            const float MaxForce         = 2000;
            const float AccelerationRate = 10000;

            // We limit the amount of change per frame.
            float change = AccelerationRate * deltaTime;

            float direction = 0;

            if (_inputService.IsDown(Keys.W))
            {
                direction += 1;
            }
            if (_inputService.IsDown(Keys.S))
            {
                direction -= 1;
            }

            GamePadState gamePadState = _inputService.GetGamePadState(LogicalPlayerIndex.One);

            direction += gamePadState.Triggers.Right - gamePadState.Triggers.Left;

            if (direction != 0)
            {
                // Increase motor force.
                _motorForce = MathHelper.Clamp(_motorForce + direction * change, -MaxForce, +MaxForce);
            }
            else
            {
                // No acceleration. Bring motor force down to 0.
                if (_motorForce > 0)
                {
                    _motorForce = MathHelper.Clamp(_motorForce - change, 0, +MaxForce);
                }
                else if (_motorForce < 0)
                {
                    _motorForce = MathHelper.Clamp(_motorForce + change, -MaxForce, 0);
                }
            }

            // We can decide which wheels are motorized. Here we use an all wheel drive:
            Vehicle.Wheels[0].MotorForce = _motorForce;
            Vehicle.Wheels[1].MotorForce = _motorForce;
            Vehicle.Wheels[2].MotorForce = _motorForce;
            Vehicle.Wheels[3].MotorForce = _motorForce;
        }
Exemplo n.º 13
0
        // In this method, a vector is rotated with a quaternion and a matrix. The result
        // of the two vector rotations are compared.
        private void RotateVector()
        {
            var debugRenderer = GraphicsScreen.DebugRenderer2D;

            debugRenderer.DrawText("----- RotateVector Example:");

            // Create a vector. We will rotate this vector.
            Vector3 v = new Vector3(1, 2, 3);

            // Create another vector which defines the axis of a rotation.
            Vector3 rotationAxis = Vector3.UnitZ;

            // The rotation angle in radians. We want to rotate 50°.
            float rotationAngle = MathHelper.ToRadians(50);

            // ----- Part 1: Rotate a vector with a quaternion.

            // Create a quaternion that represents a 50° rotation around the axis given
            // by rotationAxis.
            Quaternion rotation = Quaternion.CreateFromRotationMatrix(rotationAxis, rotationAngle);

            // Rotate the vector v using the rotation quaternion.
            Vector3 vRotated = rotation.Rotate(v);

            // ----- Part 2: Rotate a vector with a matrix.

            // Create a matrix that represents a 50° rotation around the axis given by
            // rotationAxis.
            Matrix rotationMatrix = Matrix.CreateRotation(rotationAxis, rotationAngle);

            // Rotate the vector v using the rotation matrix.
            Vector3 vRotated2 = rotationMatrix * v;

            // ----- Part 3: Compare the results.
            // The result of both rotations should be identical.
            // Because of numerical errors there can be minor differences in the results.
            // Therefore we use Vector3.AreNumericallyEqual() two check if the results
            // are equal (within a sensible numerical tolerance).
            if (Vector3.AreNumericallyEqual(vRotated, vRotated2))
            {
                debugRenderer.DrawText("Vectors are equal.\n"); // This message is written.
            }
            else
            {
                debugRenderer.DrawText("Vectors are not equal.\n");
            }
        }
Exemplo n.º 14
0
        // Returns the flow vector for a given position.
        // x and y are in the range [0, 1].
        private static void GetFlow(Vector2F position, out Vector2F direction, out float speed)
        {
            // Create a circular movement around (0.5, 0.5).

            // Vector from center to position is:
            var radius = position - new Vector2F(0.5f, 0.5f);

            // The flow direction is orthogonal to the radius vector.
            direction = new Vector2F(radius.Y, -radius.X);
            direction.TryNormalize();

            // The speed is max in the center and is 0 at the texture border.
            speed = 1;
            if (!Numeric.IsZero(radius.Length))
            {
                speed = 1 - InterpolationHelper.HermiteSmoothStep(MathHelper.Clamp((radius.Length - 0.1f) / 0.4f, 0, 1));
            }
        }
Exemplo n.º 15
0
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            // <1> / <Shift> + <1> --> Decrease / Increase saturation.
            if (InputService.IsDown(Keys.D1))
            {
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float sign        = isShiftDown ? +1 : -1;
                float time        = (float)gameTime.ElapsedGameTime.TotalSeconds;
                float delta       = sign * time * 0.5f;
                _sepiaFilter.Strength = MathHelper.Clamp(_sepiaFilter.Strength + delta, 0, 1);
            }

            GraphicsScreen.DebugRenderer.DrawText(
                "\n\nHold <1> or <Shift>+<1> to decrease or increase the effect: "
                + _sepiaFilter.Strength);
        }
Exemplo n.º 16
0
        /// <overloads>
        /// <summary>
        /// Initializes a new instance of the <see cref="TerrainMaterialLayer"/> class.
        /// </summary>
        /// </overloads>
        ///
        /// <summary>
        /// Initializes a new instance of the <see cref="TerrainMaterialLayer"/> class with the default
        /// material.
        /// </summary>
        /// <param name="graphicService">The graphic service.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="graphicService"/> is <see langword="null"/>.
        /// </exception>
        public TerrainMaterialLayer(IGraphicsService graphicService)
        {
            if (graphicService == null)
            {
                throw new ArgumentNullException("graphicService");
            }

            var effect = graphicService.Content.Load <Effect>("DigitalRune/Terrain/TerrainMaterialLayer");

            Material = new Material
            {
                { "Detail", new EffectBinding(graphicService, effect, null, EffectParameterHint.Material) }
            };

            FadeOutStart            = int.MaxValue;
            FadeOutEnd              = int.MaxValue;
            TileSize                = 1;
            DiffuseColor            = new Vector3(1, 1, 1);
            SpecularColor           = new Vector3(1, 1, 1);
            SpecularPower           = 10;
            Alpha                   = 1;
            DiffuseTexture          = graphicService.GetDefaultTexture2DWhite();
            SpecularTexture         = graphicService.GetDefaultTexture2DBlack();
            NormalTexture           = graphicService.GetDefaultNormalTexture();
            HeightTextureScale      = 1;
            HeightTextureBias       = 0;
            HeightTexture           = graphicService.GetDefaultTexture2DBlack();
            TriplanarTightening     = -1;
            TintStrength            = 1;
            TintTexture             = graphicService.GetDefaultTexture2DWhite();
            BlendThreshold          = 0.5f;
            BlendRange              = 1f;
            BlendHeightInfluence    = 0;
            BlendNoiseInfluence     = 0;
            BlendTextureChannel     = 0;
            BlendTexture            = graphicService.GetDefaultTexture2DWhite();
            NoiseTileSize           = 1;
            TerrainHeightMin        = -1e20f;
            TerrainHeightMax        = +1e20f;
            TerrainHeightBlendRange = 1f;
            TerrainSlopeMin         = -ConstantsF.Pi;
            TerrainSlopeMax         = ConstantsF.Pi;
            TerrainSlopeBlendRange  = MathHelper.ToRadians(10);
        }
Exemplo n.º 17
0
        private Vector3 GetBaseColor(Vector3 direction)
        {
            // 0 = zenith, 1 = horizon
            float p = 1 - MathHelper.Clamp(
                (float)Math.Acos(direction.Y) / ConstantsF.Pi * 2,
                0,
                1);

            var colorAverage = (BaseHorizonColor + BaseZenithColor) / 2;

            if (p < BaseColorShift)
            {
                return(InterpolationHelper.Lerp(BaseHorizonColor, colorAverage, p / BaseColorShift));
            }
            else
            {
                return(InterpolationHelper.Lerp(colorAverage, BaseZenithColor, (p - BaseColorShift) / (1 - BaseColorShift)));
            }
        }
Exemplo n.º 18
0
        protected override void OnUpdate(TimeSpan deltaTime)
        {
            // Mouse centering (controlled by the MenuComponent) is disabled if the game
            // is inactive or if the GUI is active. In these cases, we do not want to move
            // the player.
            if (!_inputService.EnableMouseCentering)
            {
                return;
            }

            if (_inputService.IsPressed(Keys.Enter, true))
            {
                // Toggle between player camera and spectator view.
                _useSpectatorView = !_useSpectatorView;
            }
            else
            {
                float deltaTimeF = (float)deltaTime.TotalSeconds;

                // Compute new yaw and pitch from mouse movement.
                float deltaYaw = 0;
                deltaYaw -= _inputService.MousePositionDelta.X;
                deltaYaw -= _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.X * 10;
                _yaw     += deltaYaw * deltaTimeF * 0.1f;

                float deltaPitch = 0;
                deltaPitch -= _inputService.MousePositionDelta.Y;
                deltaPitch += _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.Y * 10;
                _pitch     += deltaPitch * deltaTimeF * 0.1f;

                // Limit the pitch angle to less than +/- 90°.
                float limit = ConstantsF.PiOver2 - 0.01f;
                _pitch = MathHelper.Clamp(_pitch, -limit, limit);
            }

            // Update SceneNode.LastPoseWorld - this is required for some effects, like
            // camera motion blur.
            CameraNode.LastPoseWorld = CameraNode.PoseWorld;

            SetCameraPose();
        }
Exemplo n.º 19
0
        public void UnprojectTest()
        {
            Viewport viewport = new Viewport(0, 0, 640, 480);
            PerspectiveProjection projection = new PerspectiveProjection();

            projection.SetFieldOfView(MathHelper.ToRadians(60), viewport.AspectRatio, 10, 1000);
            Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 0), new Vector3(0, 0, -1), Vector3.Up);

            Assert.IsTrue(Vector3.AreNumericallyEqual(new Vector3(0, 0, -10), viewport.Unproject(new Vector3(320, 240, 0), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual(new Vector3(projection.Left, projection.Top, -10), viewport.Unproject(new Vector3(0, 0, 0), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual(new Vector3(projection.Right, projection.Top, -10), viewport.Unproject(new Vector3(640, 0, 0), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual(new Vector3(projection.Left, projection.Bottom, -10), viewport.Unproject(new Vector3(0, 480, 0), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual(new Vector3(projection.Right, projection.Bottom, -10), viewport.Unproject(new Vector3(640, 480, 0), projection, view)));

            Vector3[] farCorners = new Vector3[4];
            GraphicsHelper.GetFrustumFarCorners(projection, farCorners);
            Assert.IsTrue(Vector3.AreNumericallyEqual((Vector3)farCorners[0], viewport.Unproject(new Vector3(0, 0, 1), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual((Vector3)farCorners[1], viewport.Unproject(new Vector3(640, 0, 1), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual((Vector3)farCorners[2], viewport.Unproject(new Vector3(0, 480, 1), projection, view)));
            Assert.IsTrue(Vector3.AreNumericallyEqual((Vector3)farCorners[3], viewport.Unproject(new Vector3(640, 480, 1), projection, view)));
        }
Exemplo n.º 20
0
        // This method shows how to safely compare vectors.
        private void CompareVectors()
        {
            var debugRenderer = GraphicsScreen.DebugRenderer2D;

            debugRenderer.DrawText("----- CompareVectors Example:");

            // Define a vector.
            Vector3 v0 = new Vector3(1000, 2000, 3000);

            // Define a rotation quaternion that rotates 360° around the x axis.
            Quaternion rotation = Quaternion.CreateRotationX(MathHelper.ToRadians(360));

            // Rotate v0.
            Vector3 v1 = rotation.Rotate(v0);

            // The rotated vector v1 should be identical to v0 because a 360° rotation
            // should not change the vector. - But due to numerical errors v0 and v1 are
            // not equal.
            if (v0 == v1)
            {
                debugRenderer.DrawText("Vectors are equal.");
            }
            else
            {
                debugRenderer.DrawText("Vectors are not equal."); // This message is written.
            }
            // With Vector3.AreNumericallyEqual() we can check if two vectors are equal
            // when we allow a small numeric tolerance. The tolerance that is applied is
            // Numeric.EpsilonF, e.g. 10^-5.
            if (Vector3.AreNumericallyEqual(v0, v1))
            {
                debugRenderer.DrawText("Vectors are numerically equal.\n"); // This message is written.
            }
            else
            {
                debugRenderer.DrawText("Vectors are not numerically equal.\n");
            }
        }
Exemplo n.º 21
0
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            var oldMode = _mode;
            var oldUseHardwareFiltering = _useHardwareFiltering;

            // <1> / <Shift> + <1> --> Change mode.
            if (InputService.IsPressed(Keys.D1, true))
            {
                bool isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                if (isShiftDown)
                {
                    _mode++;
                }
                else
                {
                    _mode--;
                }
            }

            // <2> / <Shift> + <2> --> Change number of passes.
            if (InputService.IsPressed(Keys.D2, true))
            {
                bool isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                if (isShiftDown)
                {
                    _blur.NumberOfPasses++;
                }
                else
                {
                    _blur.NumberOfPasses = Math.Max(1, _blur.NumberOfPasses - 1);
                }
            }

            // <3> / <Shift> + <3> --> Change hardware filtering.
            if (InputService.IsPressed(Keys.D3, true))
            {
                _useHardwareFiltering = !_useHardwareFiltering;
            }

            // <4> / <Shift> + <4> --> Change scale.
            if (InputService.IsDown(Keys.D4))
            {
                // Increase or decrease value by a factor of 1.01 every frame (1/60 s).
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float factor      = isShiftDown ? 1.01f : 1.0f / 1.01f;
                float time        = (float)gameTime.ElapsedGameTime.TotalSeconds;
                _blur.Scale *= (float)Math.Pow(factor, time * 60);
            }

            // Update blur mode.
            _mode = MathHelper.Clamp(_mode, 0, 2);
            if (oldMode != _mode || oldUseHardwareFiltering != _useHardwareFiltering)
            {
                if (_mode == 0)
                {
                    _modeName = "15-tap Box Blur";
                    _blur.InitializeBoxBlur(15, _useHardwareFiltering);
                }
                else if (_mode == 1)
                {
                    _modeName = "15-tap Gaussian Blur";
                    _blur.InitializeGaussianBlur(15, 15.0f / 6, _useHardwareFiltering);
                }
                else if (_mode == 2)
                {
                    _modeName = "13-tap Poisson Blur";
                    _blur.InitializePoissonBlur();
                }
            }

            GraphicsScreen.DebugRenderer.DrawText(
                "\n\nPress <1> or <Shift>+<1> to change the blur kernel: " + _modeName
                + "\nPress <2> or <Shift>+<2> to decrease or increase the number of passes: " + _blur.NumberOfPasses
                + "\nPress <3> toggle hardware filtering: " + _useHardwareFiltering
                + "\nPress <4> or <Shift>+<4> to decrease or increase the blur scale: " + _blur.Scale);
        }
Exemplo n.º 22
0
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        /// <summary>
        /// Computes the intersection of <see cref="MeshNode"/>s.
        /// </summary>
        /// <param name="meshNodePairs">
        /// A collection of <see cref="MeshNode"/> pairs.The renderer computes the intersection volume
        /// of each pair.
        /// </param>
        /// <param name="color">The diffuse color used for the intersection.</param>
        /// <param name="alpha">The opacity of the intersection.</param>
        /// <param name="maxConvexity">
        /// The maximum convexity of the submeshes. A convex mesh has a convexity of 1. A concave mesh
        /// has a convexity greater than 1. Convexity is the number of layers required for depth peeling
        /// (= the number of front face layers when looking at the object).
        /// </param>
        /// <param name="context">The render context.</param>
        /// <remarks>
        /// <para>
        /// This method renders an off-screen image (color and depth) of the intersection volume. This
        /// operation destroys the currently set render target and depth/stencil buffer.
        /// </para>
        /// </remarks>
        /// <exception cref="ObjectDisposedException">
        /// The <see cref="IntersectionRenderer"/> has already been disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="meshNodePairs"/> or <see cref="context"/> is
        /// <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// The convexity must be greater than 0.
        /// </exception>
        /// <exception cref="GraphicsException">
        /// Invalid render context: Graphics service is not set.
        /// </exception>
        /// <exception cref="GraphicsException">
        /// Invalid render context: Wrong graphics device.
        /// </exception>
        /// <exception cref="GraphicsException">
        /// Invalid render context: Scene is not set.
        /// </exception>
        /// <exception cref="GraphicsException">
        /// Invalid render context: Camera node needs to be set in render context.
        /// </exception>
        public void ComputeIntersection(IEnumerable <Pair <MeshNode> > meshNodePairs,
                                        Vector3F color, float alpha, float maxConvexity, RenderContext context)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException("IntersectionRenderer has already been disposed.");
            }
            if (meshNodePairs == null)
            {
                throw new ArgumentNullException("meshNodePairs");
            }
            if (maxConvexity < 1)
            {
                throw new ArgumentOutOfRangeException("maxConvexity", "The max convexity must be greater than 0.");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (context.GraphicsService == null)
            {
                throw new GraphicsException("Invalid render context: Graphics service is not set.");
            }
            if (_graphicsService != context.GraphicsService)
            {
                throw new GraphicsException("Invalid render context: Wrong graphics service.");
            }
            if (context.CameraNode == null)
            {
                throw new GraphicsException("Camera node needs to be set in render context.");
            }
            if (context.Scene == null)
            {
                throw new GraphicsException("A scene needs to be set in the render context.");
            }

            // Create 2 ordered pairs for each unordered pair.
            _pairs.Clear();
            foreach (var pair in meshNodePairs)
            {
                if (pair.First == null || pair.Second == null)
                {
                    continue;
                }

                // Frustum culling.
                if (!context.Scene.HaveContact(pair.First, context.CameraNode))
                {
                    continue;
                }
                if (!context.Scene.HaveContact(pair.Second, context.CameraNode))
                {
                    continue;
                }

                _pairs.Add(new Pair <MeshNode, MeshNode>(pair.First, pair.Second));
                _pairs.Add(new Pair <MeshNode, MeshNode>(pair.Second, pair.First));
            }

            var renderTargetPool = _graphicsService.RenderTargetPool;

            if (_pairs.Count == 0)
            {
                renderTargetPool.Recycle(_intersectionImage);
                _intersectionImage = null;
                return;
            }

            // Color and alpha are applied in RenderIntersection().
            _color = color;
            _alpha = alpha;

            var graphicsDevice = _graphicsService.GraphicsDevice;

            // Save original render states.
            var originalBlendState        = graphicsDevice.BlendState;
            var originalDepthStencilState = graphicsDevice.DepthStencilState;
            var originalRasterizerState   = graphicsDevice.RasterizerState;
            var originalScissorRectangle  = graphicsDevice.ScissorRectangle;

            // Get offscreen render targets.
            var viewport = context.Viewport;

            viewport.X      = 0;
            viewport.Y      = 0;
            viewport.Width  = (int)(viewport.Width / DownsampleFactor);
            viewport.Height = (int)(viewport.Height / DownsampleFactor);
            var renderTargetFormat = new RenderTargetFormat(viewport.Width, viewport.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);

            // Try to reuse any existing render targets.
            // (Usually they are recycled in RenderIntersection()).
            var currentScene = _intersectionImage;

            if (currentScene == null || !renderTargetFormat.IsCompatibleWith(currentScene))
            {
                currentScene.SafeDispose();
                currentScene = renderTargetPool.Obtain2D(renderTargetFormat);
            }
            var lastScene = renderTargetPool.Obtain2D(renderTargetFormat);

            // Set shared effect parameters.
            var cameraNode = context.CameraNode;
            var view       = (Matrix)cameraNode.View;
            var projection = cameraNode.Camera.Projection;
            var near       = projection.Near;
            var far        = projection.Far;

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

            // The DepthEpsilon has to be tuned if depth peeling does not work because
            // of numerical problems equality z comparisons.
            _parameterCameraParameters.SetValue(new Vector3(near, far - near, 0.0000001f));
            _parameterView.SetValue(view);
            _parameterProjection.SetValue((Matrix)projection);

            var defaultTexture = _graphicsService.GetDefaultTexture2DBlack();

            // Handle all pairs.
            bool isFirstPass = true;

            while (true)
            {
                // Find a mesh node A and all mesh nodes to which it needs to be clipped.
                MeshNode meshNodeA = null;
                _partners.Clear();
                for (int i = 0; i < _pairs.Count; i++)
                {
                    var pair = _pairs[i];

                    if (pair.First == null)
                    {
                        continue;
                    }

                    if (meshNodeA == null)
                    {
                        meshNodeA = pair.First;
                    }

                    if (pair.First == meshNodeA)
                    {
                        _partners.Add(pair.Second);

                        //  Remove this pair.
                        _pairs[i] = new Pair <MeshNode, MeshNode>();
                    }
                }

                // Abort if we have handled all pairs.
                if (meshNodeA == null)
                {
                    break;
                }

                var worldTransformA = (Matrix)(meshNodeA.PoseWorld * Matrix44F.CreateScale(meshNodeA.ScaleWorld));

                if (EnableScissorTest)
                {
                    // Scissor rectangle of A.
                    var scissorA = GraphicsHelper.GetScissorRectangle(context.CameraNode, viewport, meshNodeA);

                    // Union of scissor rectangles of partners.
                    Rectangle partnerRectangle = GraphicsHelper.GetScissorRectangle(context.CameraNode, viewport, _partners[0]);
                    for (int i = 1; i < _partners.Count; i++)
                    {
                        var a = GraphicsHelper.GetScissorRectangle(context.CameraNode, viewport, _partners[i]);
                        partnerRectangle = Rectangle.Union(partnerRectangle, a);
                    }

                    // Use intersection of A and partners.
                    graphicsDevice.ScissorRectangle = Rectangle.Intersect(scissorA, partnerRectangle);

                    // We store the union of all scissor rectangles for use in RenderIntersection().
                    if (isFirstPass)
                    {
                        _totalScissorRectangle = graphicsDevice.ScissorRectangle;
                    }
                    else
                    {
                        _totalScissorRectangle = Rectangle.Union(_totalScissorRectangle, graphicsDevice.ScissorRectangle);
                    }
                }

                // Depth peeling of A.
                for (int layer = 0; layer < maxConvexity; layer++)
                {
                    // Set and clear render target.
                    graphicsDevice.SetRenderTarget(currentScene);
                    graphicsDevice.Clear(new Color(1, 1, 1, 0)); // RGB = "a large depth", A = "empty area"

                    // Render a depth layer of A.
                    graphicsDevice.DepthStencilState = DepthStencilStateWriteLess;
                    graphicsDevice.BlendState        = BlendState.Opaque;
                    graphicsDevice.RasterizerState   = EnableScissorTest ? CullCounterClockwiseScissor : RasterizerState.CullCounterClockwise;
                    _parameterWorld.SetValue(worldTransformA);
                    _parameterTexture.SetValue((layer == 0) ? defaultTexture : lastScene);
                    _passPeel.Apply();
                    foreach (var submesh in meshNodeA.Mesh.Submeshes)
                    {
                        submesh.Draw();
                    }

                    // Render partners to set stencil.
                    graphicsDevice.DepthStencilState = DepthStencilStateOnePassStencilFail;
                    graphicsDevice.BlendState        = BlendStateNoWrite;
                    graphicsDevice.RasterizerState   = EnableScissorTest ? CullNoneScissor : RasterizerState.CullNone;
                    foreach (var partner in _partners)
                    {
                        _parameterWorld.SetValue((Matrix)(partner.PoseWorld * Matrix44F.CreateScale(partner.ScaleWorld)));
                        _passMark.Apply();
                        foreach (var submesh in partner.Mesh.Submeshes)
                        {
                            submesh.Draw();
                        }
                    }

                    // Clear depth buffer. Leave stencil buffer unchanged.
                    graphicsDevice.Clear(ClearOptions.DepthBuffer, new Color(0, 1, 0), 1, 0);

                    // Render A to compute lighting.
                    graphicsDevice.DepthStencilState = DepthStencilStateStencilNotEqual0;
                    graphicsDevice.BlendState        = BlendState.Opaque;
                    graphicsDevice.RasterizerState   = EnableScissorTest ? CullCounterClockwiseScissor :  RasterizerState.CullCounterClockwise;
                    _parameterWorld.SetValue(worldTransformA);
                    _passDraw.Apply();
                    foreach (var submesh in meshNodeA.Mesh.Submeshes)
                    {
                        submesh.Draw();
                    }

                    // Combine last intersection image with current.
                    if (!isFirstPass)
                    {
                        graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
                        graphicsDevice.BlendState        = BlendState.Opaque;
                        graphicsDevice.RasterizerState   = EnableScissorTest ? CullNoneScissor : RasterizerState.CullNone;
                        _parameterTexture.SetValue(lastScene);
                        _passCombine.Apply();
                        graphicsDevice.DrawFullScreenQuad();
                    }

                    isFirstPass = false;

                    // ----- Swap render targets.
                    MathHelper.Swap(ref lastScene, ref currentScene);
                }
            }

            // Store final images for RenderIntersection.
            _intersectionImage = lastScene;

            // Scale scissor rectangle back to full-screen resolution.
            if (DownsampleFactor > 1)
            {
                _totalScissorRectangle.X      = (int)(_totalScissorRectangle.X * DownsampleFactor);
                _totalScissorRectangle.Y      = (int)(_totalScissorRectangle.Y * DownsampleFactor);
                _totalScissorRectangle.Width  = (int)(_totalScissorRectangle.Width * DownsampleFactor);
                _totalScissorRectangle.Height = (int)(_totalScissorRectangle.Height * DownsampleFactor);
            }


            // Restore original render state.
            graphicsDevice.BlendState        = originalBlendState ?? BlendState.Opaque;
            graphicsDevice.DepthStencilState = originalDepthStencilState ?? DepthStencilState.Default;
            graphicsDevice.RasterizerState   = originalRasterizerState ?? RasterizerState.CullCounterClockwise;
            graphicsDevice.ScissorRectangle  = originalScissorRectangle;

            renderTargetPool.Recycle(currentScene);
            _partners.Clear();
            _pairs.Clear();
        }
Exemplo n.º 23
0
    // Creates a lot of random objects.
    private void CreateRandomObjects()
    {
      var random = new Random();

      var isFirstHeightField = true;

      int currentShape = 0;
      int numberOfObjects = 0;
      while (true)
      {
        numberOfObjects++;
        if (numberOfObjects > ObjectsPerType)
        {
          currentShape++;
          numberOfObjects = 0;
        }

        Shape shape;
        switch (currentShape)
        {
          case 0:
            // Box
            shape = new BoxShape(ObjectSize, ObjectSize * 2, ObjectSize * 3);
            break;
          case 1:
            // Capsule
            shape = new CapsuleShape(0.3f * ObjectSize, 2 * ObjectSize);
            break;
          case 2:
            // Cone
            shape = new ConeShape(1 * ObjectSize, 2 * ObjectSize);
            break;
          case 3:
            // Cylinder
            shape = new CylinderShape(0.4f * ObjectSize, 2 * ObjectSize);
            break;
          case 4:
            // Sphere
            shape = new SphereShape(ObjectSize);
            break;
          case 5:
            // Convex hull of several points.
            ConvexHullOfPoints hull = new ConvexHullOfPoints();
            hull.Points.Add(new Vector3(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize));
            hull.Points.Add(new Vector3(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize));
            hull.Points.Add(new Vector3(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
            hull.Points.Add(new Vector3(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
            hull.Points.Add(new Vector3(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize));
            shape = hull;
            break;
          case 6:
            // A composite shape: two boxes that form a "T" shape.
            var composite = new CompositeShape();
            composite.Children.Add(
              new GeometricObject(
                new BoxShape(ObjectSize, 3 * ObjectSize, ObjectSize),
                new Pose(new Vector3(0, 0, 0))));
            composite.Children.Add(
              new GeometricObject(
                new BoxShape(2 * ObjectSize, ObjectSize, ObjectSize),
                new Pose(new Vector3(0, 2 * ObjectSize, 0))));
            shape = composite;
            break;
          case 7:
            shape = new CircleShape(ObjectSize);
            break;
          case 8:
            {
              var compBvh = new CompositeShape();
              compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3(0, 0.5f, 0), Matrix.Identity)));
              compBvh.Children.Add(new GeometricObject(new BoxShape(0.8f, 0.5f, 0.5f), new Pose(new Vector3(0.5f, 0.7f, 0), Matrix.CreateRotationZ(-MathHelper.ToRadians(15)))));
              compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3(0, 1.15f, 0), Matrix.Identity)));
              compBvh.Children.Add(new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3(0.6f, 1.15f, 0), Matrix.CreateRotationX(0.3f))));
              compBvh.Partition = new AabbTree<int>();
              shape = compBvh;
              break;
            }
          case 9:
            CompositeShape comp = new CompositeShape();
            comp.Children.Add(new GeometricObject(new BoxShape(0.5f * ObjectSize, 1 * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3(0, 0.5f * ObjectSize, 0), Quaternion.Identity)));
            comp.Children.Add(new GeometricObject(new BoxShape(0.8f * ObjectSize, 0.5f * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3(0.3f * ObjectSize, 0.7f * ObjectSize, 0), Quaternion.CreateRotationZ(-MathHelper.ToRadians(45)))));
            comp.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3(0, 1.15f * ObjectSize, 0), Quaternion.Identity)));
            shape = comp;
            break;
          case 10:
            shape = new ConvexHullOfPoints(new[]
            {
              new Vector3(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
              new Vector3(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
              new Vector3(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)
            });
            break;
          case 11:
            ConvexHullOfShapes shapeHull = new ConvexHullOfShapes();
            shapeHull.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3(0, 2 * ObjectSize, 0), Matrix.Identity)));
            shapeHull.Children.Add(new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize), Pose.Identity));
            shape = shapeHull;
            break;
          case 12:
            shape = Shape.Empty;
            break;
          case 13:
            var numberOfSamplesX = 10;
            var numberOfSamplesZ = 10;
            var samples = new float[numberOfSamplesX * numberOfSamplesZ];
            for (int z = 0; z < numberOfSamplesZ; z++)
              for (int x = 0; x < numberOfSamplesX; x++)
                samples[z * numberOfSamplesX + x] = (float)(Math.Cos(z / 3f) * Math.Sin(x / 2f) * BoxSize / 6);
            HeightField heightField = new HeightField(0, 0, 2 * BoxSize, 2 * BoxSize, samples, numberOfSamplesX, numberOfSamplesZ);
            shape = heightField;
            break;
          //case 14:
          //shape = new LineShape(new Vector3(0.1f, 0.2f, 0.3f), new Vector3(0.1f, 0.2f, -0.3f).Normalized);
          //break;            
          case 15:
            shape = new LineSegmentShape(
              new Vector3(0.1f, 0.2f, 0.3f), new Vector3(0.1f, 0.2f, 0.3f) + 3 * ObjectSize * new Vector3(0.1f, 0.2f, -0.3f));
            break;
          case 16:
            shape = new MinkowskiDifferenceShape
            {
              ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)),
              ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize))
            };
            break;
          case 17:
            shape = new MinkowskiSumShape
            {
              ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)),
              ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize)),
            };
            break;
          case 18:
            shape = new OrthographicViewVolume(0, ObjectSize, 0, ObjectSize, ObjectSize / 2, ObjectSize * 2);
            break;
          case 19:
            shape = new PerspectiveViewVolume(MathHelper.ToRadians(60f), 16f / 10, ObjectSize / 2, ObjectSize * 3);
            break;
          case 20:
            shape = new PointShape(0.1f, 0.3f, 0.2f);
            break;
          case 21:
            shape = new RayShape(new Vector3(0.2f, 0, -0.12f), new Vector3(1, 2, 3).Normalized, ObjectSize * 2);
            break;
          case 22:
            shape = new RayShape(new Vector3(0.2f, 0, -0.12f), new Vector3(1, 2, 3).Normalized, ObjectSize * 2)
            {
              StopsAtFirstHit = true
            };
            break;
          case 23:
            shape = new RectangleShape(ObjectSize, ObjectSize * 2);
            break;
          case 24:
            shape = new TransformedShape(
              new GeometricObject(
                new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize),
                new Pose(new Vector3(0.1f, 1, -0.2f))));
            break;
          case 25:
            shape = new TriangleShape(
              new Vector3(ObjectSize, 0, 0), new Vector3(0, ObjectSize, 0), new Vector3(ObjectSize, ObjectSize, ObjectSize));
            break;
          //case 26:
          //  {
          //    // Create a composite object from which we get the mesh.
          //    CompositeShape compBvh = new CompositeShape();
          //    compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3(0, 0.5f, 0), Matrix.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(
          //        new BoxShape(0.8f, 0.5f, 0.5f),
          //        new Pose(new Vector3(0.5f, 0.7f, 0), Matrix.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
          //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3(0, 1.15f, 0), Matrix.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3(0.6f, 1.15f, 0), Matrix.CreateRotationX(0.3f))));

          //    TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) };
          //    meshBvhShape.Partition = new AabbTree<int>();
          //    shape = meshBvhShape;
          //    break;
          //  }
          //case 27:
          //  {
          //    // Create a composite object from which we get the mesh.
          //    CompositeShape compBvh = new CompositeShape();
          //    compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3(0, 0.5f, 0), Quaternion.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(
          //        new BoxShape(0.8f, 0.5f, 0.5f),
          //        new Pose(new Vector3(0.5f, 0.7f, 0), Quaternion.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
          //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3(0, 1.15f, 0), Quaternion.Identity)));
          //    compBvh.Children.Add(
          //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3(0.6f, 1.15f, 0), Quaternion.CreateRotationX(0.3f))));

          //    TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) };
          //    meshBvhShape.Partition = new AabbTree<int>();
          //    shape = meshBvhShape;
          //    break;
          //  }
          case 28:
            shape = new ConvexPolyhedron(new[]
            {
              new Vector3(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
              new Vector3(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
              new Vector3(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
              new Vector3(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)
            });
            break;
          case 29:
            return;
          default:
            currentShape++;
            continue;
        }

        // Create an object with the random shape, pose, color and velocity.
        Pose randomPose = new Pose(
          random.NextVector3(-BoxSize + ObjectSize * 2, BoxSize - ObjectSize * 2),
          random.NextQuaternion());
        var newObject = new MovingGeometricObject
        {
          Pose = randomPose,
          Shape = shape,
          LinearVelocity = random.NextQuaternion().Rotate(new Vector3(MaxLinearVelocity, 0, 0)),
          AngularVelocity = random.NextQuaternion().Rotate(Vector3.Forward)
                            * RandomHelper.Random.NextFloat(0, MaxAngularVelocity),
        };

        if (RandomHelper.Random.NextBool())
          newObject.LinearVelocity = Vector3.Zero;
        if (RandomHelper.Random.NextBool())
          newObject.AngularVelocity = Vector3.Zero;

        if (shape is LineShape || shape is HeightField)
        {
          // Do not move lines or the height field.
          newObject.LinearVelocity = Vector3.Zero;
          newObject.AngularVelocity = Vector3.Zero;
        }

        // Create only 1 heightField!
        if (shape is HeightField)
        {
          if (isFirstHeightField)
          {
            isFirstHeightField = true;
            newObject.Pose = new Pose(new Vector3(-BoxSize, -BoxSize, -BoxSize));
          }
          else
          {
            currentShape++;
            numberOfObjects = 0;
            continue;
          }
        }

        // Add collision object to collision domain.
        _domain.CollisionObjects.Add(new CollisionObject(newObject));

        //co.Type = CollisionObjectType.Trigger;
        //co.Name = "Object" + shape.GetType().Name + "_" + i;
      }
    }
Exemplo n.º 24
0
        private void InitializeGaussianBlur(Vector2F viewportSize, bool useHardwareFiltering)
        {
            if (_horizontalOffsets != null && _lastViewportSize == viewportSize)
            {
                return;
            }

            _lastViewportSize = viewportSize;

            int   numberOfSamples   = _offsetsParameter.Elements.Count;
            float standardDeviation = numberOfSamples / 3.0f * BlurStrength;

            if (_horizontalOffsets == null)
            {
                _horizontalOffsets = new Vector2[numberOfSamples];
                _verticalOffsets   = new Vector2[numberOfSamples];
                _weights           = new float[numberOfSamples];
            }

            // Define the Gaussian function coefficient that we use.
            float coefficient = 1 / (float)Math.Sqrt(ConstantsF.TwoPi) / standardDeviation;

            float weightSum;

            if (useHardwareFiltering)
            {
                // We sample 2 pixels per tap, so we can sample twice as wide.
                standardDeviation = standardDeviation * 2;

                // Sample the center pixel in the middle and then between pixel.
                _horizontalOffsets[0] = new Vector2(0, 0);
                _verticalOffsets[0]   = new Vector2(0, 0);
                _weights[0]           = (BlurStrength > 0) ? MathHelper.Gaussian(0, coefficient, 0, standardDeviation) : 1;
                weightSum             = _weights[0];
                for (int i = 1; i < numberOfSamples; i += 2)
                {
                    // Get an offset between two pixels.
                    var offset = new Vector2(1.5f + (i - 1), 0); // = 1.5 + k * 2

                    // Get the offsets of the neighboring pixel centers.
                    var o0 = offset.X - 0.5f;
                    var o1 = offset.X + 0.5f;

                    // Compute the weights of the pixel centers.
                    var w0 = (BlurStrength > 0) ? MathHelper.Gaussian(o0, coefficient, 0, standardDeviation) : 0;
                    var w1 = (BlurStrength > 0) ? MathHelper.Gaussian(o1, coefficient, 0, standardDeviation) : 0;
                    _weights[i]     = (w0 + w1);
                    _weights[i + 1] = _weights[i];
                    weightSum      += (_weights[i] * 2);

                    // Shift the offset to the pixel center that has the higher weight.
                    offset.X = (o0 * w0 + o1 * w1) / (w0 + w1);

                    _horizontalOffsets[i]     = offset / viewportSize.X;
                    _horizontalOffsets[i + 1] = -_horizontalOffsets[i];
                    _verticalOffsets[i]       = new Vector2(0, offset.X) / viewportSize.Y;
                    _verticalOffsets[i + 1]   = -_verticalOffsets[i];
                }
            }
            else
            {
                // Same as above but: Sample in the middle of pixels.
                _horizontalOffsets[0] = new Vector2(0, 0);
                _verticalOffsets[0]   = new Vector2(0, 0);
                _weights[0]           = (BlurStrength > 0) ? MathHelper.Gaussian(0, coefficient, 0, standardDeviation) : 1;
                weightSum             = _weights[0];
                for (int i = 1; i < numberOfSamples; i += 2)
                {
                    var offset = new Vector2(1 + i / 2, 0);

                    _weights[i]     = (BlurStrength > 0) ? MathHelper.Gaussian(offset.X, coefficient, 0, standardDeviation) : 0;
                    _weights[i + 1] = _weights[i];
                    weightSum      += (_weights[i] * 2);

                    _horizontalOffsets[i]     = offset / viewportSize.X;
                    _horizontalOffsets[i + 1] = -_horizontalOffsets[i];
                    _verticalOffsets[i]       = new Vector2(0, offset.X) / viewportSize.Y;
                    _verticalOffsets[i + 1]   = -_verticalOffsets[i];
                }
            }

            // Normalize weights.
            for (int i = 0; i < numberOfSamples; i++)
            {
                _weights[i] /= weightSum;
            }
        }
        private void DoScatteredInterpolation()
        {
            // Create random points for a height field.
            // The height field is in the x/z plane. Height is along the y axis.
            var points = new List <Vector3>();

            for (int i = 0; i < 9; i++)
            {
                float x = i * 10;
                float y = RandomHelper.Random.NextFloat(0, 20);
                float z = RandomHelper.Random.NextInteger(0, 44) * 2;

                points.Add(new Vector3(x, y, z));
            }

            // Now we setup scattered interpolation.
            // The RadialBasisRegression class does one form of scattered interpolation:
            // Multiple regression analysis with radial basis functions.
            RadialBasisRegressionF rbf = new RadialBasisRegressionF();

            // We must define a basis function which will be used to determine the influence
            // of each input data pair. The Gaussian bell curve is a good candidate for most
            // applications.
            // We set the standard deviation to 10. Choosing a higher standard deviation makes
            // the Gaussian bell curve wider and increases the influence of the data points.
            // If we choose a lower standard deviation, we limit the influence of the data points.
            rbf.BasisFunction = (x, i) => MathHelper.Gaussian(x, 1, 0, 10);

            // Feed the data points into the scattered interpolation instance.
            foreach (var point in points)
            {
                // For each random point we add a data pair (X, Y), where X is a 2D position
                // in the height field, and Y is the observed height.
                VectorF X        = new VectorF(new[] { point.X, point.Z });
                VectorF Y        = new VectorF(new[] { point.Y });
                var     dataPair = new Pair <VectorF, VectorF>(X, Y);
                rbf.Add(dataPair);
            }

            // These were all data points. Now, we perform some precomputations.
            rbf.Setup();

            // Finally, we create a height field.
            var heightField = new float[100, 100];

            for (int x = 0; x < 100; x++)
            {
                for (int z = 0; z < 100; z++)
                {
                    // The scattered interpolation instance can compute a height for
                    // any 2D input vector.
                    float y = rbf.Compute(new VectorF(new float[] { x, z }))[0];
                    heightField[x, z] = y;
                }
            }

            var debugRenderer = GraphicsScreen.DebugRenderer;

            debugRenderer.Clear();

            // Draw the random data points.
            const float scale  = 0.04f;
            Vector3     offset = new Vector3(-2, 0, -2);

            foreach (var point in points)
            {
                debugRenderer.DrawPoint(scale * point + offset, Color.Black, false);
            }

            // Draw the height field.
            const int stepSize = 2;

            for (int x = 0; x < 100; x += stepSize)
            {
                for (int z = 0; z < 100; z += stepSize)
                {
                    float y0 = heightField[x, z];

                    if (x + stepSize < 100)
                    {
                        float y1 = heightField[x + stepSize, z];
                        debugRenderer.DrawLine(
                            scale * new Vector3(x, y0, z) + offset,
                            scale * new Vector3(x + stepSize, y1, z) + offset,
                            Color.Black,
                            false);
                    }

                    if (z + stepSize < 100)
                    {
                        float y2 = heightField[x, z + stepSize];
                        debugRenderer.DrawLine(
                            scale * new Vector3(x, y0, z) + offset,
                            scale * new Vector3(x, y2, z + stepSize) + offset,
                            Color.Black,
                            false);
                    }
                }
            }
        }
Exemplo n.º 26
0
    private void Stroke(FigureNode node, ArrayList<Vector3> strokeVertices, ArrayList<int> strokeIndices)
    {
      if (_mode != RenderMode.Stroke)
      {
        Flush();
        _strokeEffect.CurrentTechnique.Passes[0].Apply();
        _mode = RenderMode.Stroke;
      }

      // Use cached vertex buffer if available.
      var nodeRenderData = node.RenderData as FigureNodeRenderData;
      if (nodeRenderData != null && nodeRenderData.IsValid)
      {
        Flush();
        var graphicsDevice = _graphicsService.GraphicsDevice;
        graphicsDevice.SetVertexBuffer(nodeRenderData.StrokeVertexBuffer);
        graphicsDevice.Indices = nodeRenderData.StrokeIndexBuffer;
        int primitiveCount = nodeRenderData.StrokeIndexBuffer.IndexCount / 3;

        graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, primitiveCount);
#else
        int vertexCount = nodeRenderData.StrokeVertexBuffer.VertexCount;
        graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexCount, 0, primitiveCount);

        return;
      }

      var batchVertices = _strokeBatch.Vertices;

      var world = node.PoseWorld * Matrix.CreateScale(node.ScaleWorld);
      var worldView = _view * world;

      var thickness = node.StrokeThickness;
      var color3F = node.StrokeColor * node.StrokeAlpha;
      var color = new HalfVector4(color3F.X, color3F.Y, color3F.Z, node.StrokeAlpha);
      var dash = node.StrokeDashPattern * node.StrokeThickness;
      bool usesDashPattern = (dash.Y + dash.Z) != 0;
      var dashSum = new HalfVector4(
        dash.X,
        dash.X + dash.Y,
        dash.X + dash.Y + dash.Z,
        dash.X + dash.Y + dash.Z + dash.W);

      // Convert to vertices.
      float lastDistance = 0;
      Vector3 lastPosition = new Vector3(float.NaN);
      Vector3 lastWorld = new Vector3();
      Vector3 lastView = new Vector3();
      Vector3 lastProjected = new Vector3();

      var data0 = new HalfVector4(0, 1, thickness, 0);
      var data1 = new HalfVector4(0, 0, thickness, 0);
      var data2 = new HalfVector4(1, 0, thickness, 0);
      var data3 = new HalfVector4(1, 1, thickness, 0);

      Vector3[] figurePoints = strokeVertices.Array;
      int[] figureIndices = strokeIndices.Array;
      int numberOfLineSegments = strokeIndices.Count / 2;

      for (int i = 0; i < numberOfLineSegments; i++)
      {
        var startIndex = figureIndices[i * 2 + 0];
        var endIndex = figureIndices[i * 2 + 1];
        var start = figurePoints[startIndex];
        var end = figurePoints[endIndex];

        var notConnectedWithLast = start != lastPosition;
        lastPosition = end;

        Vector3 startWorld = notConnectedWithLast ? world.TransformPosition(start) : lastWorld;
        Vector3 endWorld = world.TransformPosition(end);
        lastWorld = endWorld;

        // Compute start/end distances of lines from beginning of line strip
        // for dash patterns.
        float startDistance = 0;
        float endDistance = 1;
        if (usesDashPattern)
        {
          if (!node.DashInWorldSpace)
          {
            Vector3 startView = notConnectedWithLast ? worldView.TransformPosition(start) : lastView;
            var endView = worldView.TransformPosition(end);
            lastView = endView;

            // Clip to near plane - otherwise lines which end near the camera origin
            // (where planar z == 0) will disappear. (Projection singularity!)
            float deltaZ = Math.Abs(startView.Z - endView.Z);
            float pStart = MathHelper.Clamp((startView.Z - (-_cameraNear)) / deltaZ, 0, 1);
            startView = InterpolationHelper.Lerp(startView, endView, pStart);
            float pEnd = MathHelper.Clamp((endView.Z - (-_cameraNear)) / deltaZ, 0, 1);
            endView = InterpolationHelper.Lerp(endView, startView, pEnd);

            Vector3 startProjected;
            if (notConnectedWithLast)
            {
              lastDistance = 0;
              startProjected = _viewport.ProjectToViewport(startView, _projection);
            }
            else
            {
              startProjected = lastProjected;
            }
            var endProjected = _viewport.ProjectToViewport(endView, _projection);
            lastProjected = endProjected;

            startDistance = lastDistance;
            endDistance = startDistance + (endProjected - startProjected).Length;
            lastDistance = endDistance;
          }
          else
          {
            if (notConnectedWithLast)
              lastDistance = 0;

            startDistance = lastDistance;
            endDistance = startDistance + (endWorld - startWorld).Length;
            lastDistance = endDistance;

            // The shader needs to know that DashInWorldSpace is true. To avoid
            // effect parameter changes, we store the value in the sign of the distance!
            startDistance = -startDistance;
            endDistance = -endDistance;
          }
        }

        var s = new Vector4(startWorld.X, startWorld.Y, startWorld.Z, startDistance);
        var e = new Vector4(endWorld.X, endWorld.Y, endWorld.Z, endDistance);

        int index, dummy;
        _strokeBatch.Submit(PrimitiveType.TriangleList, 4, 6, out index, out dummy);

        batchVertices[index + 0].Start = s;
        batchVertices[index + 0].End = e;
        batchVertices[index + 0].Data = data0;
        batchVertices[index + 0].Color = color;
        batchVertices[index + 0].Dash = dashSum;

        batchVertices[index + 1].Start = s;
        batchVertices[index + 1].End = e;
        batchVertices[index + 1].Data = data1;
        batchVertices[index + 1].Color = color;
        batchVertices[index + 1].Dash = dashSum;

        batchVertices[index + 2].Start = s;
        batchVertices[index + 2].End = e;
        batchVertices[index + 2].Data = data2;
        batchVertices[index + 2].Color = color;
        batchVertices[index + 2].Dash = dashSum;

        batchVertices[index + 3].Start = s;
        batchVertices[index + 3].End = e;
        batchVertices[index + 3].Data = data3;
        batchVertices[index + 3].Color = color;
        batchVertices[index + 3].Dash = dashSum;
      }
    }
Exemplo n.º 27
0
        private void CreateGuiControls()
        {
            var panel = SampleFramework.AddOptions("Shadows");

            // ----- Light node controls
            var lightNodePanel = SampleHelper.AddGroupBox(panel, "Light Nodes");

            SampleHelper.AddDropDown(
                lightNodePanel,
                "Light type",
                new[] { "Spotlight", "PointLight" },
                0,
                selectedItem =>
            {
                bool enableSpotlight      = (selectedItem == "Spotlight");
                _spotlightNode.IsEnabled  = enableSpotlight;
                _pointLightNode.IsEnabled = !enableSpotlight;
            });

            SampleHelper.AddSlider(
                lightNodePanel,
                "Range",
                "F2",
                1,
                30,
                10,
                value =>
            {
                _spotlight.Range  = value;
                _pointLight.Range = value;
            });

            SampleHelper.AddSlider(
                lightNodePanel,
                "Y position",
                "F2",
                0,
                10,
                1,
                value =>
            {
                foreach (var node in new[] { _spotlightNode, _pointLightNode })
                {
                    var pose        = node.PoseWorld;
                    pose.Position.Y = value;
                    node.PoseWorld  = pose;
                }
            });

            SampleHelper.AddSlider(
                lightNodePanel,
                "X rotation",
                "F0",
                -90,
                90,
                1,
                value =>
            {
                var pose                 = _spotlightNode.PoseWorld;
                pose.Orientation         = Matrix.CreateRotationX(MathHelper.ToRadians(value));
                _spotlightNode.PoseWorld = pose;
            });

            SampleHelper.AddSlider(
                lightNodePanel,
                "Spotlight angle",
                "F2",
                1,
                89,
                MathHelper.ToDegrees(_spotlight.CutoffAngle),
                value =>
            {
                float angle             = MathHelper.ToRadians(value);
                _spotlight.FalloffAngle = 0.8f * angle;
                _spotlight.CutoffAngle  = angle;
            });

            // ----- Shadow controls
            var shadowPanel = SampleHelper.AddGroupBox(panel, "Shadow");

            SampleHelper.AddSlider(
                shadowPanel,
                "Shadow map resolution",
                "F0",
                16,
                1024,
                _standardShadow.PreferredSize,
                value =>
            {
                _standardShadow.PreferredSize = (int)value;
                _cubeMapShadow.PreferredSize  = (int)value;
            });

            SampleHelper.AddCheckBox(
                shadowPanel,
                "Prefer 16 bit",
                _standardShadow.Prefer16Bit,
                isChecked =>
            {
                _standardShadow.Prefer16Bit = isChecked;
                _cubeMapShadow.Prefer16Bit  = isChecked;
            });

            SampleHelper.AddSlider(
                shadowPanel,
                "Depth bias",
                "F2",
                0,
                10,
                _standardShadow.DepthBias,
                value =>
            {
                _standardShadow.DepthBias = value;
                _cubeMapShadow.DepthBias  = value;
            });

            SampleHelper.AddSlider(
                shadowPanel,
                "Normal offset",
                "F2",
                0,
                10,
                _standardShadow.NormalOffset,
                value =>
            {
                _standardShadow.NormalOffset = value;
                _cubeMapShadow.NormalOffset  = value;
            });

            SampleHelper.AddSlider(
                shadowPanel,
                "Number of samples",
                "F0",
                -1,
                32,
                _standardShadow.NumberOfSamples,
                value =>
            {
                _standardShadow.NumberOfSamples = (int)value;
                _cubeMapShadow.NumberOfSamples  = (int)value;
            });

            SampleHelper.AddSlider(
                shadowPanel,
                "Filter radius",
                "F2",
                0,
                10,
                _standardShadow.FilterRadius,
                value =>
            {
                _standardShadow.FilterRadius = value;
                _cubeMapShadow.FilterRadius  = value;
            });

            SampleHelper.AddSlider(
                shadowPanel,
                "Jitter resolution",
                "F0",
                1,
                10000,
                _standardShadow.JitterResolution,
                value =>
            {
                _standardShadow.JitterResolution = value;
                _cubeMapShadow.JitterResolution  = value;
            });

            SampleFramework.ShowOptionsWindow("Shadows");
        }
Exemplo n.º 28
0
        public override void Render(IList <SceneNode> nodes, RenderContext context, RenderOrder order)
        {
            ThrowIfDisposed();

            if (nodes == null)
            {
                throw new ArgumentNullException("nodes");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            int numberOfNodes = nodes.Count;

            if (nodes.Count == 0)
            {
                return;
            }

            context.Validate(_effect);

            var originalRenderTarget = context.RenderTarget;
            var originalViewport     = context.Viewport;

            var graphicsDevice   = context.GraphicsService.GraphicsDevice;
            var savedRenderState = new RenderStateSnapshot(graphicsDevice);

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

            int   frame     = context.Frame;
            float deltaTime = (float)context.DeltaTime.TotalSeconds;

            for (int nodeIndex = 0; nodeIndex < numberOfNodes; nodeIndex++)
            {
                var cloudNode = nodes[nodeIndex] as CloudLayerNode;
                if (cloudNode == null)
                {
                    continue;
                }

                var cloudMap = cloudNode.CloudMap as LayeredCloudMap;
                if (cloudMap == null)
                {
                    continue;
                }

                // We update the cloud map only once per frame.
                if (cloudMap.LastFrame == frame)
                {
                    continue;
                }

                cloudMap.LastFrame = frame;

                var layers         = cloudMap.Layers;
                var animationTimes = cloudMap.AnimationTimes;
                var sources        = cloudMap.SourceLayers;
                var targets        = cloudMap.TargetLayers;
                var renderTargets  = cloudMap.LayerTextures;

                // Animate the cloud map layers.
                for (int i = 0; i < LayeredCloudMap.NumberOfTextures; i++)
                {
                    if (layers[i] == null || layers[i].Texture != null)
                    {
                        continue;
                    }

                    if (cloudMap.Random == null)
                    {
                        cloudMap.Random = new Random(cloudMap.Seed);
                    }

                    // Make sure there is a user-defined texture or data for procedural textures.
                    if (sources[i] == null)
                    {
                        // Each octave is 128 x 128 (= 1 / 4 of the 512 * 512 noise texture).
                        sources[i]       = new PackedTexture(null, _noiseTexture, cloudMap.Random.NextVector2F(0, 1), new Vector2F(0.25f));
                        targets[i]       = new PackedTexture(null, _noiseTexture, cloudMap.Random.NextVector2F(0, 1), new Vector2F(0.25f));
                        renderTargets[i] = new RenderTarget2D(graphicsDevice, 128, 128, false, SurfaceFormat.Alpha8, DepthFormat.None);
                    }

                    // Update animation time.
                    animationTimes[i] += deltaTime * layers[i].AnimationSpeed;

                    // Update source and target if animation time is beyond 1.
                    if (animationTimes[i] > 1)
                    {
                        // Wrap animation time.
                        animationTimes[i] = animationTimes[i] % 1;

                        // Swap source and target.
                        MathHelper.Swap(ref sources[i], ref targets[i]);

                        // Set target to a new random part of the noise texture.
                        targets[i].Offset = cloudMap.Random.NextVector2F(0, 1);
                    }

                    // Lerp source and target together to get the final noise texture.
                    graphicsDevice.SetRenderTarget(renderTargets[i]);
                    _parameterViewportSize.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
                    _parameterTextures[0].SetValue(sources[i].TextureAtlas);
                    _parameterTextures[1].SetValue(targets[i].TextureAtlas);
                    _parameterTexture0Parameters.SetValue(new Vector4(sources[i].Scale.X, sources[i].Scale.Y, sources[i].Offset.X, sources[i].Offset.Y));
                    _parameterTexture1Parameters.SetValue(new Vector4(targets[i].Scale.X, targets[i].Scale.Y, targets[i].Offset.X, targets[i].Offset.Y));
                    _parameterLerp.SetValue(animationTimes[i]);
                    _passLerp.Apply();
                    graphicsDevice.DrawFullScreenQuad();
                }

                // Initialize the cloud map.
                if (cloudMap.Texture == null || cloudMap.Size != cloudMap.Texture.Width)
                {
                    cloudMap.Texture.SafeDispose();

                    var cloudTexture = new RenderTarget2D(
                        graphicsDevice,
                        cloudMap.Size,
                        cloudMap.Size,
                        false,
                        SurfaceFormat.Alpha8,
                        DepthFormat.None);

                    cloudMap.SetTexture(cloudTexture);
                }

                // Combine the layers.
                graphicsDevice.SetRenderTarget((RenderTarget2D)cloudMap.Texture);
                _parameterViewportSize.SetValue(new Vector2(cloudMap.Texture.Width, cloudMap.Texture.Height));
                for (int i = 0; i < LayeredCloudMap.NumberOfTextures; i++)
                {
                    var layer = layers[i] ?? EmptyLayer;
                    _parameterTextures[i].SetValue(layer.Texture ?? renderTargets[i]);
                    _parameterMatrices[i].SetValue((Matrix) new Matrix44F(layer.TextureMatrix, Vector3F.Zero));
                    _parameterDensities[i].SetValue(new Vector2(layer.DensityScale, layer.DensityOffset));
                }
                _parameterCoverage.SetValue(cloudMap.Coverage);
                _parameterDensity.SetValue(cloudMap.Density);
                _passDensity.Apply();
                graphicsDevice.DrawFullScreenQuad();
            }

            savedRenderState.Restore();
            graphicsDevice.SetRenderTarget(null);
            context.RenderTarget = originalRenderTarget;
            context.Viewport     = originalViewport;
        }
Exemplo n.º 29
0
        protected override void OnProcess(RenderContext context)
        {
            context.ThrowIfCameraMissing();
            context.ThrowIfGBuffer0Missing();

            var graphicsDevice   = GraphicsService.GraphicsDevice;
            var renderTargetPool = GraphicsService.RenderTargetPool;

            var source   = context.SourceTexture;
            var target   = context.RenderTarget;
            var viewport = context.Viewport;

            // Get temporary render targets.
            var sourceSize            = new Vector2F(source.Width, source.Height);
            var isFloatingPointFormat = TextureHelper.IsFloatingPointFormat(source.Format);

            var sceneFormat = new RenderTargetFormat(source.Width, source.Height, false, source.Format, DepthFormat.None);
            var maskedScene = renderTargetPool.Obtain2D(sceneFormat);

            var rayFormat = new RenderTargetFormat(
                Math.Max(1, (int)(sourceSize.X / DownsampleFactor)),
                Math.Max(1, (int)(sourceSize.Y / DownsampleFactor)),
                false,
                source.Format,
                DepthFormat.None);
            var rayImage0 = renderTargetPool.Obtain2D(rayFormat);
            var rayImage1 = renderTargetPool.Obtain2D(rayFormat);

            // Get view and view-projection transforms.
            var       cameraNode     = context.CameraNode;
            Matrix44F projection     = cameraNode.Camera.Projection.ToMatrix44F();
            Matrix44F view           = cameraNode.View;
            Matrix44F viewProjection = projection * view;

            // We simply place the light source "far away" in opposite light ray direction.
            Vector4F lightPositionWorld = new Vector4F(-LightDirection * 10000, 1);

            // Convert to clip space.
            Vector4F lightPositionProj = viewProjection * lightPositionWorld;
            Vector3F lightPositionClip = Vector4F.HomogeneousDivide(lightPositionProj);

            // Convert from clip space [-1, 1] to texture space [0, 1].
            Vector2 lightPosition = new Vector2(lightPositionClip.X * 0.5f + 0.5f, -lightPositionClip.Y * 0.5f + 0.5f);

            // We use dot²(forward, -LightDirection) as a smooth S-shaped attenuation
            // curve to reduce the god ray effect when we look orthogonal or away from the sun.
            var   lightDirectionView = view.TransformDirection(LightDirection);
            float z           = Math.Max(0, lightDirectionView.Z);
            float attenuation = z * z;

            // Common effect parameters.
            _parameters0Parameter.SetValue(new Vector4(lightPosition.X, lightPosition.Y, LightRadius * LightRadius, Scale));
            _parameters1Parameter.SetValue(new Vector2(Softness, graphicsDevice.Viewport.AspectRatio));
            _intensityParameter.SetValue((Vector3)Intensity * attenuation);
            _numberOfSamplesParameter.SetValue(NumberOfSamples);
            _gBuffer0Parameter.SetValue(context.GBuffer0);

            // First, create a scene image where occluders are black.
            graphicsDevice.SetRenderTarget(maskedScene);
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sourceTextureParameter.SetValue(source);
            graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            graphicsDevice.SamplerStates[1] = SamplerState.PointClamp; // G-Buffer 0.
            _createMaskPass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Downsample image.
            context.SourceTexture = maskedScene;
            context.RenderTarget  = rayImage0;
            context.Viewport      = new Viewport(0, 0, rayImage0.Width, rayImage0.Height);
            _downsampleFilter.Process(context);

            // Compute light shafts.
            _viewportSizeParameter.SetValue(new Vector2(context.Viewport.Width, context.Viewport.Height));
            graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            for (int i = 0; i < NumberOfPasses; i++)
            {
                graphicsDevice.SetRenderTarget(rayImage1);
                _sourceTextureParameter.SetValue(rayImage0);
                _blurPass.Apply();
                graphicsDevice.DrawFullScreenQuad();

                // Put the current result in variable rayImage0.
                MathHelper.Swap(ref rayImage0, ref rayImage1);
            }

            // Combine light shaft image with scene.
            graphicsDevice.SetRenderTarget(target);
            graphicsDevice.Viewport = viewport;
            _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height));
            _sourceTextureParameter.SetValue(source);
            _rayTextureParameter.SetValue(rayImage0);
            graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            graphicsDevice.SamplerStates[1] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp;
            _combinePass.Apply();
            graphicsDevice.DrawFullScreenQuad();

            // Clean-up
            _sourceTextureParameter.SetValue((Texture2D)null);
            _gBuffer0Parameter.SetValue((Texture2D)null);
            _rayTextureParameter.SetValue((Texture2D)null);
            renderTargetPool.Recycle(maskedScene);
            renderTargetPool.Recycle(rayImage0);
            renderTargetPool.Recycle(rayImage1);
            context.SourceTexture = source;
            context.RenderTarget  = target;
            context.Viewport      = viewport;
        }
        /// <inheritdoc/>
        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");
            }
            if (order != RenderOrder.UserDefined)
            {
                throw new NotImplementedException("Render order must be 'UserDefined'.");
            }
            if (context.CameraNode == null)
            {
                throw new GraphicsException("Camera node needs to be set in render context.");
            }
            if (context.GBuffer0 == null)
            {
                throw new GraphicsException("GBuffer0 needs to be set in render context.");
            }

            int numberOfNodes = nodes.Count;

            if (numberOfNodes == 0)
            {
                return;
            }

            var   graphicsService  = context.GraphicsService;
            var   graphicsDevice   = graphicsService.GraphicsDevice;
            var   viewport         = context.Viewport;
            int   width            = viewport.Width;
            int   height           = viewport.Height;
            var   renderTargetPool = graphicsService.RenderTargetPool;
            var   cameraNode       = context.CameraNode;
            var   projection       = cameraNode.Camera.Projection;
            Pose  view             = cameraNode.PoseWorld.Inverse;
            Pose  cameraPose       = cameraNode.PoseWorld;
            float near             = projection.Near;
            float far = projection.Far;

            int frame = context.Frame;

            cameraNode.LastFrame = frame;

            // Save render state.
            var originalRasterizerState   = graphicsDevice.RasterizerState;
            var originalDepthStencilState = graphicsDevice.DepthStencilState;
            var originalBlendState        = graphicsDevice.BlendState;

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

            RenderTarget2D offscreenBuffer = null;
            Texture        depthBufferHalf = null;

            if (!EnableOffscreenRendering || context.RenderTarget == null)
            {
                graphicsDevice.BlendState = BlendState.AlphaBlend;
                _parameterGBuffer0.SetValue(context.GBuffer0);
            }
            else
            {
                // Render at half resolution into off-screen buffer.
                width  = Math.Max(1, width / 2);
                height = Math.Max(1, height / 2);

                graphicsDevice.BlendState = BlendStateOffscreen;

                offscreenBuffer = renderTargetPool.Obtain2D(
                    new RenderTargetFormat(width, height, false, context.RenderTarget.Format, DepthFormat.None));
                graphicsDevice.SetRenderTarget(offscreenBuffer);
                graphicsDevice.Clear(Color.Black);

                // Get half-res depth buffer.
                object obj;
                if (context.Data.TryGetValue(RenderContextKeys.DepthBufferHalf, out obj) &&
                    obj is Texture2D)
                {
                    depthBufferHalf = (Texture2D)obj;
                    _parameterGBuffer0.SetValue(depthBufferHalf);
                }
                else
                {
                    string message = "Downsampled depth buffer is not set in render context. (The downsampled "
                                     + "depth buffer (half width and height) is required by the VolumetricLightRenderer "
                                     + "to use half-res off-screen rendering. It needs to be stored in "
                                     + "RenderContext.Data[RenderContextKeys.DepthBufferHalf].)";
                    throw new GraphicsException(message);
                }
            }

            // Set global effect parameters.
            _parameterViewportSize.SetValue(new Vector2(width, height));

            var isHdrEnabled = context.RenderTarget != null && context.RenderTarget.Format == SurfaceFormat.HdrBlendable;

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

                // VolumetricLightNode is visible in current frame.
                node.LastFrame = frame;

                // Effect parameters for volumetric light properties.
                _parameterColor.SetValue((Vector3)node.Color / node.NumberOfSamples);
                _parameterNumberOfSamples.SetValue(node.NumberOfSamples);
                _parameterLightTextureMipMap.SetValue((float)node.MipMapBias);

                // The volumetric light effect is created for the parent light node.
                var lightNode = node.Parent as LightNode;
                if (lightNode == null)
                {
                    continue;
                }

                Pose lightPose = lightNode.PoseWorld;

                // Get start and end depth values of light AABB in view space.
                var lightAabbView = lightNode.Shape.GetAabb(lightNode.ScaleWorld, view * lightPose);
                var startZ        = Math.Max(-lightAabbView.Maximum.Z, near) / far;
                var endZ          = Math.Min(-lightAabbView.Minimum.Z / far, 1);
                _parameterDepthInterval.SetValue(new Vector2(startZ, endZ));

                // Get a rectangle that covers the light in screen space.
                var rectangle           = GraphicsHelper.GetScissorRectangle(cameraNode, new Viewport(0, 0, width, height), lightNode);
                var texCoordTopLeft     = new Vector2F(rectangle.Left / (float)width, rectangle.Top / (float)height);
                var texCoordBottomRight = new Vector2F(rectangle.Right / (float)width, rectangle.Bottom / (float)height);

                GraphicsHelper.GetFrustumFarCorners(cameraNode.Camera.Projection, texCoordTopLeft, texCoordBottomRight, _frustumFarCorners);

                // Convert frustum far corners from view space to world space.
                for (int j = 0; j < _frustumFarCorners.Length; j++)
                {
                    _frustumFarCorners[j] = (Vector3)cameraPose.ToWorldDirection((Vector3)_frustumFarCorners[j]);
                }

                _parameterFrustumCorners.SetValue(_frustumFarCorners);

                Vector2 randomSeed = AnimateNoise ? new Vector2((float)MathHelper.Frac(context.Time.TotalSeconds))
                                          : new Vector2(0);
                _parameterRandomSeed.SetValue(randomSeed);

                // Set light parameters and apply effect pass.
                if (lightNode.Light is PointLight)
                {
                    var light = (PointLight)lightNode.Light;

                    float hdrScale = isHdrEnabled ? light.HdrScale : 1;
                    _parameterLightDiffuse.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
                    _parameterLightPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));
                    _parameterLightRange.SetValue(light.Range);
                    _parameterLightAttenuation.SetValue(light.Attenuation);

                    bool hasTexture = (light.Texture != null);
                    if (hasTexture)
                    {
                        _parameterLightTexture.SetValue(light.Texture);

                        // Cube maps are left handed --> Sample with inverted z. (Otherwise, the
                        // cube map and objects or texts in it are mirrored.)
                        var mirrorZ = Matrix.CreateScale(1, 1, -1);
                        _parameterLightTextureMatrix.SetValue((Matrix)(mirrorZ * lightPose.Inverse));
                    }

                    if (hasTexture)
                    {
                        if (light.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passPointLightTextureAlpha.Apply();
                        }
                        else
                        {
                            _passPointLightTextureRgb.Apply();
                        }
                    }
                    else
                    {
                        _passPointLight.Apply();
                    }
                }
                else if (lightNode.Light is Spotlight)
                {
                    var light = (Spotlight)lightNode.Light;

                    float hdrScale = isHdrEnabled ? light.HdrScale : 1;
                    _parameterLightDiffuse.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
                    _parameterLightPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));
                    _parameterLightRange.SetValue(light.Range);
                    _parameterLightAttenuation.SetValue(light.Attenuation);
                    _parameterLightDirection.SetValue((Vector3)lightPose.ToWorldDirection(Vector3.Forward));
                    _parameterLightAngles.SetValue(new Vector2(light.FalloffAngle, light.CutoffAngle));

                    bool hasTexture = (light.Texture != null);
                    if (hasTexture)
                    {
                        _parameterLightTexture.SetValue(light.Texture);

                        var proj = Matrix.CreatePerspectiveFieldOfView(light.CutoffAngle * 2, 1, 0.1f, 100);
                        _parameterLightTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * proj * (lightPose.Inverse * new Pose(cameraPose.Position))));
                    }

                    if (hasTexture)
                    {
                        if (light.Texture.Format == SurfaceFormat.Alpha8)
                        {
                            _passSpotlightTextureAlpha.Apply();
                        }
                        else
                        {
                            _passSpotlightTextureRgb.Apply();
                        }
                    }
                    else
                    {
                        _passSpotlight.Apply();
                    }
                }
                else if (lightNode.Light is ProjectorLight)
                {
                    var light = (ProjectorLight)lightNode.Light;

                    float hdrScale = isHdrEnabled ? light.HdrScale : 1;
                    _parameterLightDiffuse.SetValue((Vector3)light.Color * light.DiffuseIntensity * hdrScale);
                    _parameterLightPosition.SetValue((Vector3)(lightPose.Position - cameraPose.Position));
                    _parameterLightRange.SetValue(light.Projection.Far);
                    _parameterLightAttenuation.SetValue(light.Attenuation);

                    _parameterLightTexture.SetValue(light.Texture);

                    _parameterLightTextureMatrix.SetValue((Matrix)(GraphicsHelper.ProjectorBiasMatrix * light.Projection * (lightPose.Inverse * new Pose(cameraPose.Position))));

                    if (light.Texture.Format == SurfaceFormat.Alpha8)
                    {
                        _passProjectorLightTextureAlpha.Apply();
                    }
                    else
                    {
                        _passProjectorLightTextureRgb.Apply();
                    }
                }
                else
                {
                    continue;
                }

                // Draw a screen space quad covering the light.
                graphicsDevice.DrawQuad(rectangle);
            }

            _parameterGBuffer0.SetValue((Texture)null);
            _parameterLightTexture.SetValue((Texture)null);

            if (offscreenBuffer != null)
            {
                // ----- Combine off-screen buffer with scene.
                graphicsDevice.BlendState = BlendState.Opaque;

                // The previous scene render target is bound as texture.
                // --> Switch scene render targets!
                var sceneRenderTarget = context.RenderTarget;
                var renderTarget      = renderTargetPool.Obtain2D(new RenderTargetFormat(sceneRenderTarget));
                context.SourceTexture = offscreenBuffer;
                context.RenderTarget  = renderTarget;

                // Use the UpsampleFilter, which supports "nearest-depth upsampling".
                // (Nearest-depth upsampling is an "edge-aware" method that tries to
                // maintain the original geometry and prevent blurred edges.)
                if (_upsampleFilter == null)
                {
                    _upsampleFilter                = new UpsampleFilter(graphicsService);
                    _upsampleFilter.Mode           = UpsamplingMode.NearestDepth;
                    _upsampleFilter.RebuildZBuffer = true;
                }

                _upsampleFilter.DepthThreshold = DepthThreshold;
                context.SceneTexture           = sceneRenderTarget;

                _upsampleFilter.Process(context);

                context.SceneTexture  = null;
                context.SourceTexture = null;
                renderTargetPool.Recycle(offscreenBuffer);
                renderTargetPool.Recycle(sceneRenderTarget);
            }

            // Restore render states.
            graphicsDevice.RasterizerState   = originalRasterizerState;
            graphicsDevice.DepthStencilState = originalDepthStencilState;
            graphicsDevice.BlendState        = originalBlendState;
        }