// 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); }
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); }
/// <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); }
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)); }
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); }
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"); } }
// 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(); }
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; } }
//-------------------------------------------------------------- #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); }
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 }
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; } } }
/// <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)); } } }); }
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); } }
// 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; } }
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; } }
// 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() }; }
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, }; }