Beispiel #1
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);
        }
        public Vector3F 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(Vector3F.Zero);
            }

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

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

            Vector3F horizonSunlight = GetTransmittance(direction) * SunIntensity;

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

            return(horizonSunlight * f);
        }
Beispiel #3
0
        public bool GetDisplacement(float x, float z, out Vector3F displacement, out Vector3F normal)
        {
            if (!EnableCpuQueries)
            {
                throw new InvalidOperationException("OceanWaves.GetDisplacement() can only be called if EnableCpuQueries is set to true.");
            }

            displacement = new Vector3F(0);
            normal       = new Vector3F(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:
#if false
            // 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);
#endif

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

            normal   = new Vector3F(-n.X, 0, -n.Y);
            normal.Y = (float)Math.Sqrt(1 - normal.X * normal.X - normal.Y * normal.Y);
            return(true);
        }
Beispiel #4
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,
                                      Vector3F diffuse, Vector3F 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);
        }
Beispiel #5
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 Vector3F(123, 456, -789), Matrix33F.CreateRotation(new Vector3F(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 Vector3F(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 Vector3F(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 Vector3F(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));
        }
Beispiel #6
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?)
            }

            Vehicle.SetCarSteeringAngle(_steeringAngle, Vehicle.Wheels[0], Vehicle.Wheels[1], Vehicle.Wheels[2], Vehicle.Wheels[3]);
        }
        private void UpdateOrientation(float deltaTime)
        {
            // Compute new yaw and pitch from mouse movement and gamepad.
            float deltaYaw = -_inputService.MousePositionDelta.X;

            deltaYaw -= _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.X *ThumbStickFactor;
            _yaw     += deltaYaw * deltaTime * AngularVelocityMagnitude;

            float deltaPitch = -_inputService.MousePositionDelta.Y;

            deltaPitch += _inputService.GetGamePadState(LogicalPlayerIndex.One).ThumbSticks.Right.Y *ThumbStickFactor;
            _pitch     += deltaPitch * deltaTime * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _pitch = MathHelper.Clamp(_pitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);
        }
Beispiel #8
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;
            }

            var 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;
        }
        // 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.
            Vector3F v = new Vector3F(1, 2, 3);

            // Create another vector which defines the axis of a rotation.
            Vector3F rotationAxis = Vector3F.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.
            QuaternionF rotation = QuaternionF.CreateRotation(rotationAxis, rotationAngle);

            // Rotate the vector v using the rotation quaternion.
            Vector3F 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.
            Matrix33F rotationMatrix = Matrix33F.CreateRotation(rotationAxis, rotationAngle);

            // Rotate the vector v using the rotation matrix.
            Vector3F 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 Vector3F.AreNumericallyEqual() two check if the results
            // are equal (within a sensible numerical tolerance).
            if (Vector3F.AreNumericallyEqual(vRotated, vRotated2))
            {
                debugRenderer.DrawText("Vectors are equal.\n"); // This message is written.
            }
            else
            {
                debugRenderer.DrawText("Vectors are not equal.\n");
            }
        }
Beispiel #10
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));
            }
        }
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        /// <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 Vector3F(1, 1, 1);
            SpecularColor           = new Vector3F(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);
        }
        private Vector3F GetBaseColor(Vector3F 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)));
            }
        }
        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();
        }
Beispiel #14
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);
            Matrix44F view = Matrix44F.CreateLookAt(new Vector3F(0, 0, 0), new Vector3F(0, 0, -1), Vector3F.Up);

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

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

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

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

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

            // Rotate v0.
            Vector3F 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 Vector3F.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 (Vector3F.AreNumericallyEqual(v0, v1))
            {
                debugRenderer.DrawText("Vectors are numerically equal.\n"); // This message is written.
            }
            else
            {
                debugRenderer.DrawText("Vectors are not numerically equal.\n");
            }
        }
 public override void Update(GameTime gameTime)
 {
     if (_avatarPose == null)
     {
         if (_avatarRenderer.State == AvatarRendererState.Ready)
         {
             _avatarPose = new AvatarPose(_avatarRenderer);
             AnimationService.StartAnimation(_walkAnimation, _avatarPose).AutoRecycle();
         }
     }
     else
     {
         // Update pose of attached baseball bat.
         // The offset of the baseball bat origin to the bone origin (in bone space)
         Pose offset = new Pose(new Vector3F(0.01f, 0.05f, 0.0f), Matrix33F.CreateRotationY(MathHelper.ToRadians(-20)));
         // The bone position in model space
         SrtTransform bonePose = _avatarPose.SkeletonPose.GetBonePoseAbsolute((int)AvatarBone.SpecialRight);
         // The baseball bat matrix in world space
         _baseballBatMeshNode.PoseWorld = _pose * (Pose)bonePose * offset;
     }
 }
Beispiel #17
0
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        /// <summary>
        /// Initializes a new instance of the <see cref="SsaoFilter"/> class.
        /// </summary>
        /// <param name="graphicsService">The graphics service.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="graphicsService"/> is <see langword="null"/>.
        /// </exception>
        public SsaoFilter(IGraphicsService graphicsService)
            : base(graphicsService)
        {
            _effect                    = GraphicsService.Content.Load <Effect>("DigitalRune/PostProcessing/SsaoFilter");
            _farParameter              = _effect.Parameters["Far"];
            _radiusParameter           = _effect.Parameters["Radius"];
            _strengthParameter         = _effect.Parameters["Strength"];
            _maxDistancesParameter     = _effect.Parameters["MaxDistances"];
            _viewportSizeParameter     = _effect.Parameters["ViewportSize"];
            _sourceTextureParameter    = _effect.Parameters["SourceTexture"];
            _gBuffer0Parameter         = _effect.Parameters["GBuffer0"];
            _occlusionTextureParameter = _effect.Parameters["OcclusionTexture"];
            _createLinesAPass          = _effect.CurrentTechnique.Passes["CreateLinesA"];
            _createLinesBPass          = _effect.CurrentTechnique.Passes["CreateLinesB"];
            _blurHorizontalPass        = _effect.CurrentTechnique.Passes["BlurHorizontal"];
            _blurVerticalPass          = _effect.CurrentTechnique.Passes["BlurVertical"];
            _combinePass               = _effect.CurrentTechnique.Passes["Combine"];
            _copyPass                  = _effect.CurrentTechnique.Passes["Copy"];

            Radii              = new Vector2F(0.01f, 0.02f);
            MaxDistances       = new Vector2F(0.5f, 1.0f);
            Strength           = 1f;
            NumberOfBlurPasses = 1;
            DownsampleFactor   = 2;
            Quality            = 2;
            Scale              = new Vector2F(0.5f, 2f);
            CombineWithSource  = true;

            _blur = new Blur(graphicsService);
            _blur.InitializeGaussianBlur(7, 7 / 3, true);

            _copyFilter       = PostProcessHelper.GetCopyFilter(graphicsService);
            _downsampleFilter = PostProcessHelper.GetDownsampleFilter(graphicsService);

            Random random = new Random(123456);

            Vector3[] vectors = new Vector3[9];

            // 16 random vectors for Crytek-style point samples.
            //for (int i = 0; i < vectors.Length; i++)
            //  vectors[i] = (Vector3)random.NextQuaternionF().Rotate(Vector3F.One).Normalized;
            //    //* random.NextFloat(0.5f, 1) // Note: StarCraft 2 uses varying length to vary the sample offset length.

            // We create rotated random vectors with uniform distribution in 360°. Each random vector
            // is further rotated with small random angle.
            float jitterAngle = ConstantsF.TwoPi / vectors.Length / 4;

            for (int i = 0; i < vectors.Length; i++)
            {
                vectors[i] = (Vector3)(Matrix33F.CreateRotationZ(ConstantsF.TwoPi * i / vectors.Length + random.NextFloat(-jitterAngle, jitterAngle)) * new Vector3F(1, 0, 0)).Normalized;
            }

            // Permute randomVectors.
            for (int i = 0; i < vectors.Length; i++)
            {
                MathHelper.Swap(ref vectors[i], ref vectors[random.Next(i, vectors.Length - 1)]);
            }

            // Scale random vectors.
            for (int i = 0; i < vectors.Length; i++)
            {
                vectors[i].Z = random.NextFloat(Scale.X, Scale.Y);
            }

            _effect.Parameters["RandomVectors"].SetValue(vectors);
        }
Beispiel #18
0
        protected override void OnHandleInput(InputContext context)
        {
#if !WP7 && !XBOX
#if PORTABLE
            if (GlobalSettings.PlatformID != PlatformID.WindowsPhone8)
#endif
            {
                ContinueDraggingSelection(context);
            }
#endif

            base.OnHandleInput(context);

            if (!IsLoaded)
            {
                return;
            }

            var inputService = InputService;

#if !WP7 && !XBOX
#if PORTABLE
            if (GlobalSettings.PlatformID != PlatformID.WindowsStore &&
                GlobalSettings.PlatformID != PlatformID.WindowsPhone8 &&
                GlobalSettings.PlatformID != PlatformID.Android &&
                GlobalSettings.PlatformID != PlatformID.iOS)
#endif
            {
                var  screen      = Screen;
                bool isMouseOver = IsMouseOver;
                if (isMouseOver && !inputService.IsMouseOrTouchHandled)
                {
                    if (inputService.IsDoubleClick(MouseButtons.Left) &&
                        !_mouseDownPosition.IsNaN &&
                        (_mouseDownPosition - context.MousePosition).LengthSquared < MinDragDistanceSquared)
                    {
                        // Double-click with left mouse button --> Select word or white-space.
                        inputService.IsMouseOrTouchHandled = true;
                        int index = GetIndex(context.MousePosition, screen);
                        SelectWordOrWhiteSpace(index);
                        StartDraggingSelection(context);
                    }
                    else if (inputService.IsPressed(MouseButtons.Left, false))
                    {
                        // Left mouse button pressed --> Position caret.
                        inputService.IsMouseOrTouchHandled = true;
                        int index = GetIndex(context.MousePosition, screen);
                        _selectionStart = index;
                        CaretIndex      = index;
                        StartDraggingSelection(context);
                    }
                    else
                    {
                        // Check for other mouse interactions.
                        _isDraggingSelection = false;
                        if (inputService.MouseWheelDelta != 0 && IsMultiline)
                        {
                            // Mouse wheel over the text box --> Scroll vertically.
                            inputService.IsMouseOrTouchHandled = true;

                            float delta = inputService.MouseWheelDelta / screen.MouseWheelScrollDelta * screen.MouseWheelScrollLines;
                            delta                   *= _verticalScrollBar.SmallChange;
                            VisualOffset             = MathHelper.Clamp(VisualOffset - delta, 0, _verticalScrollBar.Maximum);
                            _verticalScrollBar.Value = VisualOffset;
                            InvalidateArrange();
                        }
                    }
                }

                if (!_isDraggingSelection && IsFocusWithin)
                {
                    HandleKeyboardInput();
                }
            }
#endif
#if WP7 || PORTABLE
#if PORTABLE
            else
#endif
            {
                // Windows phone: The guide is shown when the touch is released over the box.
                bool isMouseOver = IsMouseOver;
                if (inputService.IsMouseOrTouchHandled)
                {
                    _isPressed = false;
                }
                else if (_isPressed && isMouseOver && inputService.IsReleased(MouseButtons.Left))
                {
                    ShowGuide(inputService.GetLogicalPlayer(context.AllowedPlayer));
                    inputService.IsMouseOrTouchHandled = true;
                    _isPressed = false;
                }
                else if (_isPressed && (!isMouseOver || inputService.IsUp(MouseButtons.Left)))
                {
                    _isPressed = false;
                }
                else if (isMouseOver && inputService.IsPressed(MouseButtons.Left, false))
                {
                    _isPressed = true;
                    inputService.IsMouseOrTouchHandled = true;
                }
            }
#endif

#if XBOX
            // Xbox: Guide is shown when gamepad A is pressed.
            if (IsFocusWithin)
            {
                if (!inputService.IsGamePadHandled(context.AllowedPlayer) && inputService.IsPressed(Buttons.A, false, context.AllowedPlayer))
                {
                    ShowGuide(inputService.GetLogicalPlayer(context.AllowedPlayer));
                    inputService.SetGamePadHandled(context.AllowedPlayer, true);
                }
            }
#endif
        }
Beispiel #19
0
        public override void Update(GameTime gameTime)
        {
            float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

            var debugRenderer = _graphicsScreen.DebugRenderer;

            debugRenderer.Clear();

            // Change wave height.
            if (InputService.IsDown(Keys.H))
            {
                bool  isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0;
                float sign        = isShiftDown ? +1 : -1;
                float delta       = sign * deltaTime * 0.01f;
                var   oceanWaves  = ((OceanWaves)_waterNode.Waves);
                oceanWaves.HeightScale = Math.Max(0, oceanWaves.HeightScale + delta);
            }

            // Switch water color.
            if (InputService.IsPressed(Keys.J, true))
            {
                if (_waterColorType == 0)
                {
                    _waterColorType = 1;
                    _waterNode.Water.UnderwaterFogDensity = new Vector3F(12, 8, 8) * 0.04f;
                    _waterNode.Water.WaterColor           = new Vector3F(10, 30, 79) * 0.002f;
                }
                else
                {
                    _waterColorType = 0;
                    _waterNode.Water.UnderwaterFogDensity = new Vector3F(1, 0.8f, 0.6f);
                    _waterNode.Water.WaterColor           = new Vector3F(0.2f, 0.4f, 0.5f);
                }
            }

            // Toggle reflection.
            if (InputService.IsPressed(Keys.K, true))
            {
                _waterNode.PlanarReflection.IsEnabled = !_waterNode.PlanarReflection.IsEnabled;
            }

            // Switch caustics.
            if (InputService.IsPressed(Keys.L, true))
            {
                if (_causticType == 0)
                {
                    _causticType = 1;
                    _waterNode.Water.CausticsSampleCount = 5;
                    _waterNode.Water.CausticsIntensity   = 10;
                    _waterNode.Water.CausticsPower       = 200;
                }
                else if (_causticType == 1)
                {
                    // Disable caustics
                    _causticType = 2;
                    _waterNode.Water.CausticsIntensity = 0;
                }
                else
                {
                    _causticType = 0;
                    _waterNode.Water.CausticsSampleCount = 3;
                    _waterNode.Water.CausticsIntensity   = 3;
                    _waterNode.Water.CausticsPower       = 100;
                }
            }

            // Move rigid bodies with the waves:
            // The Buoyancy force effect is only designed for a flat water surface.
            // This code applies some impulses to move the bodies. It is not physically
            // correct but looks ok.
            // The code tracks 3 arbitrary positions on each body. Info for the positions
            // are stored in RigidBody.UserData. The wave displacements of the previous
            // frame and the current frame are compared an impulse proportional to the
            // displacement change is applied.
            foreach (var body in Simulation.RigidBodies)
            {
                if (body.MotionType != MotionType.Dynamic)
                {
                    continue;
                }

                // Check how much the body penetrates the water using a simple AABB check.
                Aabb  aabb             = body.Aabb;
                float waterPenetration = (float)Math.Pow(
                    MathHelper.Clamp((_waterNode.PoseWorld.Position.Y - aabb.Minimum.Y) / aabb.Extent.Y, 0, 1),
                    3);

                if (waterPenetration < 0)
                {
                    body.UserData = null;
                    continue;
                }

                // 3 displacement vectors are stored in the UserData.
                var previousDisplacements = body.UserData as Vector3F[];
                if (previousDisplacements == null)
                {
                    previousDisplacements = new Vector3F[3];
                    body.UserData         = previousDisplacements;
                }

                for (int i = 0; i < 3; i++)
                {
                    // Get an arbitrary position on or near the body.
                    Vector3F position = new Vector3F(
                        (i < 2) ? aabb.Minimum.X : aabb.Maximum.X,
                        aabb.Minimum.Y,
                        (i % 2 == 0) ? aabb.Minimum.Z : aabb.Maximum.Z);

                    // Get wave displacement of this position.
                    var      waves = (OceanWaves)_waterNode.Waves;
                    Vector3F displacement, normal;
                    waves.GetDisplacement(position.X, position.Z, out displacement, out normal);

                    // Compute velocity from displacement change.
                    Vector3F currentVelocity = body.GetVelocityOfWorldPoint(position);
                    Vector3F desiredVelocity = (displacement - previousDisplacements[i]) / deltaTime;

                    // Apply impulse proportional to the velocity change of the water.
                    Vector3F velocityDelta = desiredVelocity - currentVelocity;
                    body.ApplyImpulse(
                        velocityDelta * body.MassFrame.Mass * waterPenetration * 0.1f,
                        position);

                    previousDisplacements[i] = displacement;
                }
            }
        }
Beispiel #20
0
        /// <summary>
        /// Computes sample offsets and weights for Gaussian blur filter kernel.
        /// </summary>
        /// <param name="numberOfSamples">
        /// The number of samples. This value must be an odd number (e.g. 3, 5, 7, ...).
        /// </param>
        /// <param name="standardDeviation">The standard deviation.</param>
        /// <param name="useHardwareFiltering">
        /// If set to <see langword="true"/> hardware filtering is used to increase the blur effect;
        /// otherwise, hardware filtering is not used. Use <see langword="false"/> if you are filtering
        /// floating-point textures.
        /// </param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="numberOfSamples"/> is zero or negative.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="numberOfSamples"/> is an even number. A Gaussian blur requires an odd number of
        /// samples.
        /// </exception>
        public void InitializeGaussianBlur(int numberOfSamples, float standardDeviation, bool useHardwareFiltering)
        {
            if (numberOfSamples < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfSamples", "The numberOfSamples must be greater than 0.");
            }
            if (numberOfSamples % 2 == 0)
            {
                throw new ArgumentException("Gaussian blur expects an odd number of samples.");
            }

            // Initialize weights with 0.
            for (int i = 0; i < MaxNumberOfSamples; i++)
            {
                Weights[i] = 0;
            }

            NumberOfSamples = numberOfSamples;
            Scale           = 1;
            IsSeparable     = true;

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

            if (useHardwareFiltering)
            {
                // Sample the center pixel in the middle and then between pixel.
                // We sample 2 pixels per tap, so we can sample twice as wide.
                standardDeviation = standardDeviation * 2;

                /*
                 * // ----- Unordered samples
                 * Offsets[0] = new Vector2(0, 0);
                 * Weights[0] = MathHelper.Gaussian(0, coefficient, 0, standardDeviation);
                 * float 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 = MathHelper.Gaussian(o0, coefficient, 0, standardDeviation);
                 *  var w1 = MathHelper.Gaussian(o1, coefficient, 0, standardDeviation);
                 *  // Shift the offset to the pixel center that has the higher weight.
                 *  offset.X = (o0 * w0 + o1 * w1) / (w0 + w1);
                 *
                 *  Offsets[i] = offset;
                 *  Offsets[i + 1] = -offset;
                 *  Weights[i] = w0 + w1;
                 *  Weights[i + 1] = Weights[i];
                 *  weightSum += Weights[i] * 2;
                 * }
                 *
                 * // Normalize weights.
                 * for (int i = 0; i < numberOfSamples; i++)
                 *  Weights[i] /= weightSum;
                 */

                // ----- Ordered samples
                int left  = (numberOfSamples - 1) / 2; // Number of samples on the left.
                int right = numberOfSamples / 2;       // Number of samples on the right.
                int count = 0;                         // Number of samples generated.

                Debug.Assert(left + right + 1 == numberOfSamples, "Wrong number of samples?");

                float weight;        // The weight of the current sample.
                float weightSum = 0; // The sum of all weights (for normalization).

                // Samples on the left.
                for (int i = -left; i <= -1; i++)
                {
                    Vector2 offset = new Vector2(2 * i + 0.5f, 0);

                    // Get the offsets and weights of the neighboring pixel centers.
                    var o0 = offset.X - 0.5f;
                    var o1 = offset.X + 0.5f;
                    var w0 = MathHelper.Gaussian(o0, coefficient, 0, standardDeviation);
                    var w1 = MathHelper.Gaussian(o1, coefficient, 0, standardDeviation);

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

                    Offsets[count] = offset;
                    weight         = w0 + w1;
                    Weights[count] = weight;
                    weightSum     += weight;
                    count++;
                }

                // Center sample.
                Offsets[count] = new Vector2(0, 0);
                weight         = MathHelper.Gaussian(0, coefficient, 0, standardDeviation);
                Weights[count] = weight;
                weightSum     += weight;
                count++;

                // Samples on the right.
                for (int i = 1; i <= right; i++)
                {
                    Vector2 offset = new Vector2(2 * i - 0.5f, 0);

                    // Get the offsets and weights of the neighboring pixel centers.
                    var o0 = offset.X - 0.5f;
                    var o1 = offset.X + 0.5f;
                    var w0 = MathHelper.Gaussian(o0, coefficient, 0, standardDeviation);
                    var w1 = MathHelper.Gaussian(o1, coefficient, 0, standardDeviation);

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

                    Offsets[count] = offset;
                    weight         = w0 + w1;
                    Weights[count] = weight;
                    weightSum     += weight;
                    count++;
                }

                // Normalize weights.
                for (int i = 0; i < numberOfSamples; i++)
                {
                    Weights[i] /= weightSum;
                }

                Debug.Assert(count == numberOfSamples, "Wrong number of samples generated?");
                Debug.Assert(Numeric.AreEqual(Weights.Take(numberOfSamples).Sum(), 1.0f), "Invalid sample weights.");
            }
            else
            {
                // Sample in the middle of pixels.

                /*
                 * // ----- Unordered samples
                 * Offsets[0] = new Vector2(0, 0);
                 * Weights[0] = MathHelper.Gaussian(0, coefficient, 0, standardDeviation);
                 * float weightSum = Weights[0];
                 * for (int i = 1; i < numberOfSamples; i += 2)
                 * {
                 *  var offset = new Vector2(1 + i / 2, 0);
                 *  Offsets[i] = offset;
                 *  Offsets[i + 1] = -offset;
                 *  Weights[i] = MathHelper.Gaussian(offset.X, coefficient, 0, standardDeviation);
                 *  Weights[i + 1] = Weights[i];
                 *  weightSum += (Weights[i] * 2);
                 * }
                 *
                 * // Normalize weights.
                 * for (int i = 0; i < numberOfSamples; i++)
                 *  Weights[i] /= weightSum;
                 */

                // ----- Ordered samples
                int left  = (numberOfSamples - 1) / 2; // Number of samples on the left.
                int right = numberOfSamples / 2;       // Number of samples on the right.
                int count = 0;                         // Number of samples generated.

                Debug.Assert(left + right + 1 == numberOfSamples, "Wrong number of samples?");

                float weight;        // The weight of the current sample.
                float weightSum = 0; // The sum of all weights (for normalization).

                // Samples on the left.
                for (int i = -left; i <= -1; i++)
                {
                    Offsets[count] = new Vector2(i, 0);
                    weight         = MathHelper.Gaussian(i, coefficient, 0, standardDeviation);
                    Weights[count] = weight;
                    weightSum     += weight;
                    count++;
                }

                // Center sample.
                Offsets[count] = new Vector2(0, 0);
                weight         = MathHelper.Gaussian(0, coefficient, 0, standardDeviation);
                Weights[count] = weight;
                weightSum     += weight;
                count++;

                // Samples on the right.
                for (int i = 1; i <= right; i++)
                {
                    Offsets[count] = new Vector2(i, 0);
                    weight         = MathHelper.Gaussian(i, coefficient, 0, standardDeviation);
                    Weights[count] = weight;
                    weightSum     += weight;
                    count++;
                }

                // Normalize weights.
                for (int i = 0; i < numberOfSamples; i++)
                {
                    Weights[i] /= weightSum;
                }

                Debug.Assert(count == numberOfSamples, "Wrong number of samples generated?");
                Debug.Assert(Numeric.AreEqual(Weights.Take(numberOfSamples).Sum(), 1.0f), "Invalid sample weights.");
            }
        }
        private static void ClampHeightsToLineSegments(HeightField terrain, Aabb aabb, List <Vector4F> segments, float padding)
        {
            // TODO: Optimize this (see software rasterizers).

            float originX          = terrain.OriginX;
            float originZ          = terrain.OriginZ;
            int   numberOfSamplesX = terrain.NumberOfSamplesX;
            int   numberOfSamplesZ = terrain.NumberOfSamplesZ;
            int   numberOfCellsX   = numberOfSamplesX - 1;
            int   numberOfCellsZ   = numberOfSamplesZ - 1;
            float widthX           = terrain.WidthX;
            float cellSizeX        = widthX / numberOfCellsX;
            float widthZ           = terrain.WidthZ;
            float cellSizeZ        = widthZ / numberOfCellsZ;

            float[] heights = terrain.Samples;

            // Get min and max indices (inclusive).
            float minX = aabb.Minimum.X;
            float maxX = aabb.Maximum.X;
            float minZ = aabb.Minimum.Z;
            float maxZ = aabb.Maximum.Z;

            // Get min and max indices (inclusive).
            int indexXMin = Math.Max(0, (int)Math.Floor((minX - originX) / cellSizeX));
            int indexZMin = Math.Max(0, (int)Math.Floor((minZ - originZ) / cellSizeZ));
            int indexXMax = Math.Min(numberOfSamplesX - 1, (int)Math.Ceiling((maxX - originX) / cellSizeX));
            int indexZMax = Math.Min(numberOfSamplesZ - 1, (int)Math.Ceiling((maxZ - originZ) / cellSizeZ));

            Parallel.For(indexZMin, indexZMax + 1, indexZ =>
                         //for (int indexZ = indexZMin; indexZ <= indexZMax; indexZ++)
            {
                for (int indexX = indexXMin; indexX <= indexXMax; indexX++)
                {
                    Vector3F terrainPointFlat = new Vector3F(originX + cellSizeX * indexX, 0, originZ + cellSizeZ * indexZ);

                    float bestSegmentInfluence = 0;
                    float bestSegmentHeight    = 0;
                    for (int segmentIndex = 0; segmentIndex < segments.Count / 2; segmentIndex++)
                    {
                        var segmentStartFlat = new Vector3F(segments[segmentIndex * 2].X, 0, segments[segmentIndex * 2].Z);
                        var segmentEndFlat   = new Vector3F(segments[segmentIndex * 2 + 1].X, 0, segments[segmentIndex * 2 + 1].Z);
                        var segment          = new LineSegment(segmentStartFlat, segmentEndFlat);
                        float parameter;
                        GetLineParameter(ref segment, ref terrainPointFlat, out parameter);
                        Vector4F closestPoint     = segments[segmentIndex * 2] + parameter * (segments[segmentIndex * 2 + 1] - segments[segmentIndex * 2]);
                        Vector3F closestPointFlat = new Vector3F(closestPoint.X, 0, closestPoint.Z);
                        float distance            = (closestPointFlat - terrainPointFlat).Length - padding;
                        float influence           = MathHelper.Clamp(1 - distance / (closestPoint.W - padding), 0, 1);
                        if (influence > bestSegmentInfluence)
                        {
                            bestSegmentInfluence = influence;
                            bestSegmentHeight    = closestPoint.Y;
                        }
                    }

                    if (bestSegmentInfluence > 0)
                    {
                        heights[indexZ * numberOfSamplesX + indexX] = InterpolationHelper.Lerp(
                            heights[indexZ * numberOfSamplesX + indexX],
                            bestSegmentHeight,
                            InterpolationHelper.HermiteSmoothStep(bestSegmentInfluence));
                    }
                }
            });
        }
Beispiel #22
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;

            var vehiclePose = _vehicle.Pose;

            if (_useSpectatorView)
            {
                // Spectator Mode:
                // Camera is looking at the car from a fixed location in the level.
                Vector3F position = new Vector3F(10, 8, 10);
                Vector3F target   = vehiclePose.Position;
                Vector3F up       = Vector3F.UnitY;

                // Set the new camera view matrix. (Setting the View matrix changes the Pose.
                // The pose is simply the inverse of the view matrix).
                CameraNode.View = Matrix44F.CreateLookAt(position, target, up);
            }
            else
            {
                // Player Camera:
                // Camera moves with the car. The look direction can be changed by moving the mouse.
                Matrix33F yaw         = Matrix33F.CreateRotationY(_yaw);
                Matrix33F pitch       = Matrix33F.CreateRotationX(_pitch);
                Matrix33F orientation = vehiclePose.Orientation * yaw * pitch;
                Vector3F  forward     = orientation * -Vector3F.UnitZ;
                Vector3F  up          = Vector3F.UnitY;
                Vector3F  position    = vehiclePose.Position - 10 * forward + 5 * up;
                Vector3F  target      = vehiclePose.Position + 1 * up;

                CameraNode.View = Matrix44F.CreateLookAt(position, target, up);
            }
        }
Beispiel #23
0
        // OnUpdate() is called once per frame.
        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 (!IsEnabled)
            {
                return;
            }

            float deltaTimeF = (float)deltaTime.TotalSeconds;

            // Compute new orientation from mouse movement, gamepad and touch.
            Vector2F     mousePositionDelta = _inputService.MousePositionDelta;
            GamePadState gamePadState       = _inputService.GetGamePadState(LogicalPlayerIndex.One);
            Vector2F     touchDelta         = Vector2F.Zero;

#if MONOGAME || WINDOWS_PHONE
            foreach (var gesture in _inputService.Gestures)
            {
                if (gesture.GestureType == GestureType.FreeDrag)
                {
                    touchDelta += (Vector2F)gesture.Delta;

                    // If we have touch input, we ignore the mouse movement
                    mousePositionDelta = Vector2F.Zero;
                }
            }
#endif

#if WINDOWS_PHONE || IOS
            // On Windows Phone touch input also sets the mouse input. --> Ignore mouse data.
            mousePositionDelta = Vector2F.Zero;
#endif

            float deltaYaw = -mousePositionDelta.X - touchDelta.X - gamePadState.ThumbSticks.Right.X * ThumbStickFactor;
            _currentYaw += deltaYaw * deltaTimeF * AngularVelocityMagnitude;

            float deltaPitch = -mousePositionDelta.Y - touchDelta.Y + gamePadState.ThumbSticks.Right.Y * ThumbStickFactor;
            _currentPitch += deltaPitch * deltaTimeF * AngularVelocityMagnitude;

            // Limit the pitch angle to +/- 90°.
            _currentPitch = MathHelper.Clamp(_currentPitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Reset camera position if <Home> or <Right Stick> is pressed.
            if (_inputService.IsPressed(Keys.Home, false) ||
                _inputService.IsPressed(Buttons.RightStick, false, LogicalPlayerIndex.One))
            {
                ResetPose();
            }

            // Compute new orientation of the camera.
            QuaternionF orientation = QuaternionF.CreateRotationY(_currentYaw) * QuaternionF.CreateRotationX(_currentPitch);

            // Create velocity from <W>, <A>, <S>, <D> and <R>, <F> keys.
            // <R> or DPad up is used to move up ("rise").
            // <F> or DPad down is used to move down ("fall").
            Vector3F      velocity      = Vector3F.Zero;
            KeyboardState keyboardState = _inputService.KeyboardState;
            if (keyboardState.IsKeyDown(Keys.W))
            {
                velocity.Z--;
            }
            if (keyboardState.IsKeyDown(Keys.S))
            {
                velocity.Z++;
            }
            if (keyboardState.IsKeyDown(Keys.A))
            {
                velocity.X--;
            }
            if (keyboardState.IsKeyDown(Keys.D))
            {
                velocity.X++;
            }
            if (keyboardState.IsKeyDown(Keys.R) || gamePadState.DPad.Up == ButtonState.Pressed)
            {
                velocity.Y++;
            }
            if (keyboardState.IsKeyDown(Keys.F) || gamePadState.DPad.Down == ButtonState.Pressed)
            {
                velocity.Y--;
            }

            // Add velocity from gamepad sticks.
            velocity.X += gamePadState.ThumbSticks.Left.X;
            velocity.Z -= gamePadState.ThumbSticks.Left.Y;

            // Rotate the velocity vector from view space to world space.
            velocity = orientation.Rotate(velocity);

            if (keyboardState.IsKeyDown(Keys.LeftShift))
            {
                velocity *= SpeedBoost;
            }

            // Multiply the velocity by time to get the translation for this frame.
            Vector3F translation = velocity * LinearVelocityMagnitude * deltaTimeF;

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

            // Set the new camera pose.
            CameraNode.PoseWorld = new Pose(
                CameraNode.PoseWorld.Position + translation,
                orientation);
        }
        public FacialAnimationSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            _graphicsScreen = new DeferredGraphicsScreen(Services)
            {
                DrawReticle = false
            };
            GraphicsService.Screens.Insert(0, _graphicsScreen);
            Services.Register(typeof(DebugRenderer), null, _graphicsScreen.DebugRenderer);
            Services.Register(typeof(IScene), null, _graphicsScreen.Scene);

            // Add a game object which adds some GUI controls for the deferred graphics
            // screen to the Options window.
            GameObjectService.Objects.Add(new DeferredGraphicsOptionsObject(Services));

            // Use a fixed camera.
            var projection = new PerspectiveProjection();

            projection.SetFieldOfView(
                ConstantsF.PiOver4,
                GraphicsService.GraphicsDevice.Viewport.AspectRatio,
                0.1f,
                10);
            var cameraNode = new CameraNode(new Camera(projection));

            cameraNode.LookAt(new Vector3F(0.15f, 0.15f, 0.5f), new Vector3F(0.1f, 0.15f, 0), Vector3F.Up);
            _graphicsScreen.Scene.Children.Add(cameraNode);
            _graphicsScreen.ActiveCameraNode = cameraNode;

            // Lighting setup:
            var keyLight = new LightNode(new Spotlight {
                DiffuseIntensity = 0.6f, SpecularIntensity = 0.4f
            });

            keyLight.LookAt(new Vector3F(-2, 2, 2), new Vector3F(), Vector3F.Up);
            _graphicsScreen.Scene.Children.Add(keyLight);

            var backLight = new LightNode(new Spotlight {
                DiffuseIntensity = 0.3f, SpecularIntensity = 0.3f
            });

            backLight.LookAt(new Vector3F(1, 0.5f, -2), new Vector3F(), Vector3F.Up);
            _graphicsScreen.Scene.Children.Add(backLight);

            var fillLight = new LightNode(new AmbientLight {
                HemisphericAttenuation = 1, Intensity = 0.1f
            });

            _graphicsScreen.Scene.Children.Add(fillLight);

            // The scene does not have a proper background. That's why the exposure is a
            // bit off. --> Reduce the max exposure.
            var hdrFilter = _graphicsScreen.PostProcessors.OfType <HdrFilter>().First();

            hdrFilter.MaxExposure = 6;

            // Load the customized "Sintel" model (original: Durian Open Movie Project - http://www.sintel.org/).
            var model = ContentManager.Load <ModelNode>("Sintel/Sintel-Head").Clone();

            model.PoseWorld = new Pose(new Vector3F(0, 0, 0), Matrix33F.CreateRotationY(MathHelper.ToRadians(10)) * Matrix33F.CreateRotationX(-MathHelper.ToRadians(90)));
            _graphicsScreen.Scene.Children.Add(model);

            // The model consists of a root node and a mesh node.
            //  ModelNode "Sintel-Head"
            //    MeshNode "Sintel"
            _sintel = (MeshNode)model.Children[0];

            // The model contains two skeletal animations:
            // - "MOUTH-open" is just a single frame.
            // - "Test" is a short animation (250 frames).

            // In the Options window, we will add a slider to move the jaw.
            // Slider.Value = 0 ... mouth closed (default)
            _mouthClosedPose = SkeletonPose.Create(_sintel.Mesh.Skeleton);
            // Slider.Value = 1 ... mouth open (copied from the "MOUTH-open" animation)
            SkeletonKeyFrameAnimation mouthOpen = _sintel.Mesh.Animations["MOUTH-open"];

            _mouthOpenPose = SkeletonPose.Create(_sintel.Mesh.Skeleton);
            mouthOpen.GetValue(TimeSpan.Zero, ref _mouthOpenPose, ref _mouthOpenPose, ref _mouthOpenPose);

            // Turn the "Test" animation into an endless loop.
            _skeletalAnimation = new AnimationClip <SkeletonPose>(_sintel.Mesh.Animations["Test"])
            {
                Duration     = TimeSpan.MaxValue,
                LoopBehavior = LoopBehavior.Cycle
            };

            // Mesh has several morph targets for facial animation, which are imported
            // automatically via the content pipeline. Unfortunately, the XNA content
            // pipeline cannot import morph target animations automatically.
            // In this demo, we will create a morph target animation in code.
            _morphingAnimation = CreateMorphingAnimation();

            CreateGuiControls();
        }
        protected override void OnDrawBillboard(ref BillboardArgs b, PackedTexture texture, VertexPositionColorTexture[] vertices, int index)
        {
            #region ----- Billboarding -----

            // The billboard orientation is defined by three vectors: normal (pointing to the camera),
            // up and right (both lying in the billboard plane).
            // normal and up are given. right is computed using the cross product up x normal.
            // normal and up should be perpendicular, but usually they are not. Therefore, one vector
            // must be corrected. For spherical billboards, the normal is fixed and the up vector
            // is corrected. For cylindrical billboards (= axial billboards), the up vector is fixed
            // and the b.Normal is corrected.

            // Normal
            if (b.Orientation.Normal == BillboardNormal.ViewpointOriented)
            {
                Vector3F normal = _cameraPose.Position - b.Position;
                if (normal.TryNormalize())
                {
                    b.Normal = normal;
                }
            }

            // Axis = up vector
            if (b.Orientation.IsAxisInViewSpace)
            {
                b.Axis = _cameraPose.ToWorldDirection(b.Axis);
            }

            if (1 - Vector3F.Dot(b.Normal, b.Axis) < Numeric.EpsilonF)
            {
                // Normal and axis are parallel.
                // --> Bend normal by adding a fraction of the camera down vector.
                b.Normal += _cameraDown * 0.001f;
                b.Normal.Normalize();
            }

            // Compute right.
            //Vector3F right = Vector3F.Cross(b.Axis, b.Normal);
            // Inlined:
            Vector3F right;
            right.X = b.Axis.Y * b.Normal.Z - b.Axis.Z * b.Normal.Y;
            right.Y = b.Axis.Z * b.Normal.X - b.Axis.X * b.Normal.Z;
            right.Z = b.Axis.X * b.Normal.Y - b.Axis.Y * b.Normal.X;
            if (!right.TryNormalize())
            {
                right = b.Normal.Orthonormal1; // Normal and axis are parallel --> Choose random perpendicular vector.
            }
            if (b.Orientation.IsAxisFixed)
            {
                // Make sure normal is perpendicular to right and up.
                //normal = Vector3F.Cross(right, b.Axis);
                // Inlined:
                b.Normal.X = right.Y * b.Axis.Z - right.Z * b.Axis.Y;
                b.Normal.Y = right.Z * b.Axis.X - right.X * b.Axis.Z;
                b.Normal.Z = right.X * b.Axis.Y - right.Y * b.Axis.X;

                // No need to normalize because right and up are normalized and perpendicular.
            }
            else
            {
                // Make sure axis is perpendicular to normal and right.
                //b.Axis = Vector3F.Cross(b.Normal, right);
                // Inlined:
                b.Axis.X = b.Normal.Y * right.Z - b.Normal.Z * right.Y;
                b.Axis.Y = b.Normal.Z * right.X - b.Normal.X * right.Z;
                b.Axis.Z = b.Normal.X * right.Y - b.Normal.Y * right.X;

                // No need to normalize because normal and right are normalized and perpendicular.
            }
            #endregion

            #region ----- Rotate up and right vectors -----

            Vector3F upRotated;
            Vector3F rightRotated;

            if (b.Angle != 0.0f)
            {
                // Rotate up and right.
                // Here is the readable code.
                //Matrix33F rotation = Matrix33F.CreateRotation(b.Normal, b.Angle);
                //Vector3F upRotated = rotation * b.Axis;
                //Vector3F rightRotated = rotation * right;

                // Inlined code:
                float x           = b.Normal.X;
                float y           = b.Normal.Y;
                float z           = b.Normal.Z;
                float x2          = x * x;
                float y2          = y * y;
                float z2          = z * z;
                float xy          = x * y;
                float xz          = x * z;
                float yz          = y * z;
                float cos         = (float)Math.Cos(b.Angle);
                float sin         = (float)Math.Sin(b.Angle);
                float xsin        = x * sin;
                float ysin        = y * sin;
                float zsin        = z * sin;
                float oneMinusCos = 1.0f - cos;
                float m00         = x2 + cos * (1.0f - x2);
                float m01         = xy * oneMinusCos - zsin;
                float m02         = xz * oneMinusCos + ysin;
                float m10         = xy * oneMinusCos + zsin;
                float m11         = y2 + cos * (1.0f - y2);
                float m12         = yz * oneMinusCos - xsin;
                float m20         = xz * oneMinusCos - ysin;
                float m21         = yz * oneMinusCos + xsin;
                float m22         = z2 + cos * (1.0f - z2);

                upRotated.X = m00 * b.Axis.X + m01 * b.Axis.Y + m02 * b.Axis.Z;
                upRotated.Y = m10 * b.Axis.X + m11 * b.Axis.Y + m12 * b.Axis.Z;
                upRotated.Z = m20 * b.Axis.X + m21 * b.Axis.Y + m22 * b.Axis.Z;

                rightRotated.X = m00 * right.X + m01 * right.Y + m02 * right.Z;
                rightRotated.Y = m10 * right.X + m11 * right.Y + m12 * right.Z;
                rightRotated.Z = m20 * right.X + m21 * right.Y + m22 * right.Z;
            }
            else
            {
                // Angle is 0 - no rotation.
                upRotated    = b.Axis;
                rightRotated = right;
            }
            #endregion

            #region ----- Handle texture information and size -----

            Vector2F texCoordTopLeft     = texture.GetTextureCoordinates(Vector2F.Zero, b.AnimationTime);
            Vector2F texCoordBottomRight = texture.GetTextureCoordinates(Vector2F.One, b.AnimationTime);

            // Handle mirroring.
            if (b.Size.X < 0)
            {
                b.Size.X = -b.Size.X;
                MathHelper.Swap(ref texCoordTopLeft.X, ref texCoordBottomRight.X);
            }
            if (b.Size.Y < 0)
            {
                b.Size.Y = -b.Size.Y;
                MathHelper.Swap(ref texCoordTopLeft.Y, ref texCoordBottomRight.Y);
            }

            b.Size.X /= 2.0f;
            b.Size.Y /= 2.0f;

            // Offset from billboard center to right edge.
            Vector3F hOffset;
            hOffset.X = rightRotated.X * b.Size.X;
            hOffset.Y = rightRotated.Y * b.Size.X;
            hOffset.Z = rightRotated.Z * b.Size.X;

            // Offset from reference point to top edge.
            Vector3F vOffset;
            vOffset.X = upRotated.X * b.Size.Y;
            vOffset.Y = upRotated.Y * b.Size.Y;
            vOffset.Z = upRotated.Z * b.Size.Y;
            #endregion

            #region ----- Get Color -----

            // Premultiply alpha.
            Vector4 color4 = new Vector4
            {
                X = b.Color.X * b.Alpha,
                Y = b.Color.Y * b.Alpha,
                Z = b.Color.Z * b.Alpha,

                // Apply blend mode (0 = additive, 1 = alpha blend).
                W = b.Alpha * b.BlendMode
            };

            var color = new Color(color4);
            #endregion

            #region ----- Initializes vertices in vertex array -----

            // Bottom left vertex
            vertices[index].Position.X          = b.Position.X - hOffset.X - vOffset.X;
            vertices[index].Position.Y          = b.Position.Y - hOffset.Y - vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z - hOffset.Z - vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordTopLeft.X;
            vertices[index].TextureCoordinate.Y = texCoordBottomRight.Y;
            index++;

            // Top left vertex
            vertices[index].Position.X          = b.Position.X - hOffset.X + vOffset.X;
            vertices[index].Position.Y          = b.Position.Y - hOffset.Y + vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z - hOffset.Z + vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordTopLeft.X;
            vertices[index].TextureCoordinate.Y = texCoordTopLeft.Y;
            index++;

            // Top right vertex
            vertices[index].Position.X          = b.Position.X + hOffset.X + vOffset.X;
            vertices[index].Position.Y          = b.Position.Y + hOffset.Y + vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z + hOffset.Z + vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordBottomRight.X;
            vertices[index].TextureCoordinate.Y = texCoordTopLeft.Y;
            index++;

            // Bottom right vertex
            vertices[index].Position.X          = b.Position.X + hOffset.X - vOffset.X;
            vertices[index].Position.Y          = b.Position.Y + hOffset.Y - vOffset.Y;
            vertices[index].Position.Z          = b.Position.Z + hOffset.Z - vOffset.Z;
            vertices[index].Color               = color;
            vertices[index].TextureCoordinate.X = texCoordBottomRight.X;
            vertices[index].TextureCoordinate.Y = texCoordBottomRight.Y;
            #endregion
        }
        // 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 Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize));
                    hull.Points.Add(new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize));
                    hull.Points.Add(new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
                    hull.Points.Add(new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize));
                    hull.Points.Add(new Vector3F(-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 Vector3F(0, 0, 0))));
                    composite.Children.Add(
                        new GeometricObject(
                            new BoxShape(2 * ObjectSize, ObjectSize, ObjectSize),
                            new Pose(new Vector3F(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 Vector3F(0, 0.5f, 0), Matrix33F.Identity)));
                    compBvh.Children.Add(new GeometricObject(new BoxShape(0.8f, 0.5f, 0.5f), new Pose(new Vector3F(0.5f, 0.7f, 0), Matrix33F.CreateRotationZ(-MathHelper.ToRadians(15)))));
                    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), Matrix33F.Identity)));
                    compBvh.Children.Add(new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), Matrix33F.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 Vector3F(0, 0.5f * ObjectSize, 0), QuaternionF.Identity)));
                    comp.Children.Add(new GeometricObject(new BoxShape(0.8f * ObjectSize, 0.5f * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3F(0.3f * ObjectSize, 0.7f * ObjectSize, 0), QuaternionF.CreateRotationZ(-MathHelper.ToRadians(45)))));
                    comp.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3F(0, 1.15f * ObjectSize, 0), QuaternionF.Identity)));
                    shape = comp;
                    break;

                case 10:
                    shape = new ConvexHullOfPoints(new[]
                    {
                        new Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
                        new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
                        new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
                        new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
                        new Vector3F(-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 Vector3F(0, 2 * ObjectSize, 0), Matrix33F.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 Vector3F(0.1f, 0.2f, 0.3f), new Vector3F(0.1f, 0.2f, -0.3f).Normalized);
                //break;
                case 15:
                    shape = new LineSegmentShape(
                        new Vector3F(0.1f, 0.2f, 0.3f), new Vector3F(0.1f, 0.2f, 0.3f) + 3 * ObjectSize * new Vector3F(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 Vector3F(0.2f, 0, -0.12f), new Vector3F(1, 2, 3).Normalized, ObjectSize * 2);
                    break;

                case 22:
                    shape = new RayShape(new Vector3F(0.2f, 0, -0.12f), new Vector3F(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 Vector3F(0.1f, 1, -0.2f))));
                    break;

                case 25:
                    shape = new TriangleShape(
                        new Vector3F(ObjectSize, 0, 0), new Vector3F(0, ObjectSize, 0), new Vector3F(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 Vector3F(0, 0.5f, 0), Matrix33F.Identity)));
                //    compBvh.Children.Add(
                //      new GeometricObject(
                //        new BoxShape(0.8f, 0.5f, 0.5f),
                //        new Pose(new Vector3F(0.5f, 0.7f, 0), Matrix33F.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
                //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), Matrix33F.Identity)));
                //    compBvh.Children.Add(
                //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), Matrix33F.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 Vector3F(0, 0.5f, 0), QuaternionF.Identity)));
                //    compBvh.Children.Add(
                //      new GeometricObject(
                //        new BoxShape(0.8f, 0.5f, 0.5f),
                //        new Pose(new Vector3F(0.5f, 0.7f, 0), QuaternionF.CreateRotationZ(-(float)MathHelper.ToRadians(15)))));
                //    compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3F(0, 1.15f, 0), QuaternionF.Identity)));
                //    compBvh.Children.Add(
                //      new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3F(0.6f, 1.15f, 0), QuaternionF.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 Vector3F(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize),
                        new Vector3F(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize),
                        new Vector3F(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
                        new Vector3F(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize),
                        new Vector3F(-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.NextVector3F(-BoxSize + ObjectSize * 2, BoxSize - ObjectSize * 2),
                    random.NextQuaternionF());
                var newObject = new MovingGeometricObject
                {
                    Pose            = randomPose,
                    Shape           = shape,
                    LinearVelocity  = random.NextQuaternionF().Rotate(new Vector3F(MaxLinearVelocity, 0, 0)),
                    AngularVelocity = random.NextQuaternionF().Rotate(Vector3F.Forward)
                                      * RandomHelper.Random.NextFloat(0, MaxAngularVelocity),
                };

                if (RandomHelper.Random.NextBool())
                {
                    newObject.LinearVelocity = Vector3F.Zero;
                }
                if (RandomHelper.Random.NextBool())
                {
                    newObject.AngularVelocity = Vector3F.Zero;
                }

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

                // Create only 1 heightField!
                if (shape is HeightField)
                {
                    if (isFirstHeightField)
                    {
                        isFirstHeightField = true;
                        newObject.Pose     = new Pose(new Vector3F(-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;
            }
        }
Beispiel #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         = Matrix33F.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");
        }
        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;
            }
        }
Beispiel #29
0
        // Handle character-related input and move the character.
        private void ControlCharacter(float deltaTime)
        {
            // Compute new orientation from mouse movement.
            float deltaYaw = -InputService.MousePositionDelta.X;

            _yaw += deltaYaw * deltaTime * 0.1f;
            float deltaPitch = -InputService.MousePositionDelta.Y;

            _pitch += deltaPitch * deltaTime * 0.1f;

            // Limit the pitch angle.
            _pitch = MathHelper.Clamp(_pitch, -ConstantsF.PiOver2, ConstantsF.PiOver2);

            // Compute new orientation of the camera.
            QuaternionF cameraOrientation = QuaternionF.CreateRotationY(_yaw) * QuaternionF.CreateRotationX(_pitch);

            // Create velocity from WASD keys.
            // TODO: Diagonal movement is faster ;-). Fix this.
            Vector3F velocityVector = Vector3F.Zero;

            if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                velocityVector.Z--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                velocityVector.Z++;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.A))
            {
                velocityVector.X--;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                velocityVector.X++;
            }
            velocityVector *= 10 * deltaTime;

            // Velocity vector is currently in view space. -z is the forward direction.
            // We have to convert this vector to world space by rotating it.
            velocityVector = QuaternionF.CreateRotationY(_yaw).Rotate(velocityVector);

            // New compute desired character controller position in world space:
            Vector3F targetPosition = _character.Position + velocityVector;

            // Check if user wants to jump.
            bool jump = Keyboard.GetState().IsKeyDown(Keys.Space);

            // Call character controller to compute a new valid position. The character
            // controller slides along obstacles, handles stepping up/down, etc.
            _character.Move(targetPosition, deltaTime, jump);

            // ----- Set view matrix for graphics.
            // For third person we move the eye position back, behind the body (+z direction is
            // the "back" direction).
            Vector3F thirdPersonDistance = cameraOrientation.Rotate(new Vector3F(0, 0, 6));

            // Compute camera pose (= position + orientation).
            _cameraNode.PoseWorld = new Pose
            {
                Position = _character.Position        // Floor position of character
                           + new Vector3F(0, 1.6f, 0) // + Eye height
                           + thirdPersonDistance,
                Orientation = cameraOrientation.ToRotationMatrix33()
            };
        }
Beispiel #30
0
        public LdrSkySample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            var delegateGraphicsScreen = new DelegateGraphicsScreen(GraphicsService)
            {
                RenderCallback = Render,
            };

            GraphicsService.Screens.Insert(0, delegateGraphicsScreen);

            // Add a custom game object which controls the camera.
            _cameraObject = new CameraObject(Services);
            GameObjectService.Objects.Add(_cameraObject);


            var spriteFont = UIContentManager.Load <SpriteFont>("UI Themes/BlendBlue/Default");

            _debugRenderer = new DebugRenderer(GraphicsService, spriteFont);

            _cieSkyFilter          = new CieSkyFilter(GraphicsService);
            _cieSkyFilter.Exposure = 5;
            _cieSkyFilter.Strength = 0.9f;

            _gradientSky = new GradientSkyNode();
            //_gradientSky.GroundColor = new Vector4F(0, 0, 1, 1);
            //_gradientSky.ZenithColor = new Vector4F(0, 0, 1, 1);
            //_gradientSky.FrontColor = new Vector4F(0, 0, 1, 1);
            //_gradientSky.BackColor = new Vector4F(0, 0, 1, 1);
            //_gradientSky.FrontZenithShift = 0.3f;
            //_gradientSky.FrontGroundShift = 0.1f;
            //_gradientSky.BackGroundShift = 0.1f;
            _gradientSky.CieSkyStrength = 0;

            _gradientTextureSky                = new GradientTextureSkyNode();
            _gradientTextureSky.TimeOfDay      = _time.TimeOfDay;
            _gradientTextureSky.Color          = new Vector4F(1);
            _gradientTextureSky.FrontTexture   = ContentManager.Load <Texture2D>("Sky/GradientSkyFront");
            _gradientTextureSky.BackTexture    = ContentManager.Load <Texture2D>("Sky/GradientSkyBack");
            _gradientTextureSky.CieSkyStrength = 1;

            _scatteringSky = new ScatteringSkyNode();
            _scatteringSky.SunIntensity *= 2;
            _scatteringSky.BetaMie      *= 2;
            _scatteringSky.GMie          = 0.75f;
            _scatteringSky.ScaleHeight   = _scatteringSky.AtmosphereHeight * 0.25f;

            InitializeStarfield();

            _cloudMapRenderer = new CloudMapRenderer(GraphicsService);
            _skyRenderer      = new SkyRenderer(GraphicsService);

            _milkyWay       = ContentManager.Load <TextureCube>("Sky/MilkyWay");
            _milkyWaySkybox = new SkyboxNode(_milkyWay)
            {
                Color = new Vector3F(0.05f)
            };

            _sun = new SkyObjectNode
            {
                GlowColor0    = new Vector3F(1, 1, 1) * 5,
                GlowExponent0 = 4000,

                //GlowColor1 = new Vector3F(0.4f) * 0.1f,
                //GlowExponent1 = 100
            };

            _moon = new SkyObjectNode
            {
                Texture         = new PackedTexture(ContentManager.Load <Texture2D>("Sky/Moon")),
                SunLight        = new Vector3F(1, 1, 1) * 1,
                AmbientLight    = new Vector3F(0.001f) * 1,
                LightWrap       = 0.1f,
                LightSmoothness = 1,
                AngularDiameter = new Vector2F(MathHelper.ToRadians(5)),

                GlowColor0          = new Vector3F(0.005f * 0),
                GlowCutoffThreshold = 0.001f,
                GlowExponent0       = 100
            };

            var cloudMap = new LayeredCloudMap
            {
                Density  = 10,
                Coverage = 0.5f,
                Size     = 1024,
            };
            var scale = CreateScale(0.2f);

            cloudMap.Layers[0] = new CloudMapLayer(null, scale * CreateScale(1), -0.5f, 1, 0.011f * 0);
            cloudMap.Layers[1] = new CloudMapLayer(null, scale * CreateScale(1.7f), -0.5f, 1f / 2f, 0.017f * 0);
            cloudMap.Layers[2] = new CloudMapLayer(null, scale * CreateScale(3.97f), -0.5f, 1f / 4f, 0.033f * 0);
            cloudMap.Layers[3] = new CloudMapLayer(null, scale * CreateScale(8.1f), -0.5f, 1f / 8f, 0.043f * 0);
            cloudMap.Layers[4] = new CloudMapLayer(null, scale * CreateScale(16, 17), -0.5f, 1f / 16f, 0.051f * 0);
            cloudMap.Layers[5] = new CloudMapLayer(null, scale * CreateScale(32, 31), -0.5f, 1f / 32f, 0.059f * 0);
            cloudMap.Layers[6] = new CloudMapLayer(null, scale * CreateScale(64, 67), -0.5f, 1f / 64f, 0.067f * 0);
            cloudMap.Layers[7] = new CloudMapLayer(null, scale * CreateScale(128, 127), -0.5f, 1f / 128f, 0.081f * 0);
            _cloudLayerNode    = new CloudLayerNode(cloudMap)
            {
                ForwardScatterScale  = 2.5f,
                ForwardScatterOffset = 0.3f,
                TextureMatrix        = CreateScale(0.5f),
                SkyCurvature         = 0.9f,
                NumberOfSamples      = 16,
            };

            _ephemeris = new Ephemeris();
            // Approx. location of Ternberg: Latitude = 48, Longitude = 15, Altitude = 300
            _ephemeris.Latitude  = 0;
            _ephemeris.Longitude = 15;
            _ephemeris.Altitude  = 300;
#if XBOX
            //_time = new DateTime(2013, 5, 1, 17, 17, 0, 0);
            _time = DateTime.Now;
#else
            _time = new DateTimeOffset(2013, 5, 1, 12, 0, 0, 0, TimeSpan.Zero);
            //_time = DateTimeOffset.UtcNow;
#endif
            UpdateEphemeris();

            _milkyWaySkybox.DrawOrder     = 0;
            _starfield.DrawOrder          = 1;
            _sun.DrawOrder                = 2;
            _moon.DrawOrder               = 3;
            _scatteringSky.DrawOrder      = 4;
            _gradientSky.DrawOrder        = 4;
            _gradientTextureSky.DrawOrder = 4;
            _cloudLayerNode.DrawOrder     = 5;

            _skyNodes = new SceneNode[]
            {
                _milkyWaySkybox,
                _starfield,
                _sun,
                _moon,
                _scatteringSky,
                //_gradientSky,
                //_gradientTextureSky,
                _cloudLayerNode,
            };

            var graphicsDevice = GraphicsService.GraphicsDevice;
            _skybox = new SkyboxNode(
                new RenderTargetCube(graphicsDevice, 512, false, SurfaceFormat.Color, DepthFormat.None))
            {
                Encoding = ColorEncoding.Rgbm,
            };

            _hdrFilter = new HdrFilter(GraphicsService)
            {
                MinExposure    = 0.5f,
                MaxExposure    = 2,
                BloomIntensity = 1,
                BloomThreshold = 0.6f,
                AdaptionSpeed  = 100,
            };

            _colorEncoder = new ColorEncoder(GraphicsService)
            {
                SourceEncoding = ColorEncoding.Rgb,
                TargetEncoding = _skybox.Encoding,
            };
        }