// Add a chain-like figure using TransformedFigure and CompositeFigure. private void CreateChain() { var ellipse = new EllipseFigure { IsFilled = false, RadiusX = 1f, RadiusY = 1f, }; var compositeFigure = new CompositeFigure(); for (int i = 0; i < 9; i++) { var transformedEllipse = new TransformedFigure(ellipse) { Scale = new Vector3F(0.4f, 0.2f, 1), Pose = new Pose(new Vector3F(-2 + i * 0.5f, 0, 0), Matrix33F.CreateRotationX(ConstantsF.PiOver2 * (i % 2))) }; compositeFigure.Children.Add(transformedEllipse); } _scene.Children.Add(new FigureNode(compositeFigure) { Name = "Chain", StrokeThickness = 2, StrokeColor = new Vector3F(0.1f), StrokeAlpha = 1, PoseLocal = new Pose(new Vector3F(0, 3, 0)), }); }
//-------------------------------------------------------------- #region Creation & Cleanup //-------------------------------------------------------------- /// <overloads> /// <summary> /// Initializes a new instance of the <see cref="TerrainDecalLayer"/> class. /// </summary> /// </overloads> /// /// <summary> /// Initializes a new instance of the <see cref="TerrainDecalLayer"/> 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 TerrainDecalLayer(IGraphicsService graphicService) { if (graphicService == null) { throw new ArgumentNullException("graphicService"); } // Use a down orientation per default. Pose = new Pose(Matrix33F.CreateRotationX(-ConstantsF.PiOver2)); var effect = graphicService.Content.Load <Effect>("DigitalRune/Terrain/TerrainDecalLayer"); Material = new Material { { "Detail", new EffectBinding(graphicService, effect, null, EffectParameterHint.Material) } }; FadeOutStart = int.MaxValue; FadeOutEnd = int.MaxValue; Width = 1; Height = 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; HeightTexture = graphicService.GetDefaultTexture2DBlack(); UpdateAabb(); }
private void SetCameraPose() { 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); } }
public void CreateRotationX() { float angle = (float)MathHelper.ToRadians(30.0f); Matrix33F m = Matrix33F.CreateRotationX(angle); Assert.IsTrue(Vector3F.AreNumericallyEqual(new Vector3F(0, (float)Math.Cos(angle), (float)Math.Sin(angle)), m * Vector3F.UnitY)); QuaternionF q = QuaternionF.CreateRotation(Vector3F.UnitX, angle); Assert.IsTrue(Vector3F.AreNumericallyEqual(q.Rotate(Vector3F.One), m * Vector3F.One)); Assert.IsTrue(Matrix33F.AreNumericallyEqual(Matrix33F.CreateRotation(Vector3F.UnitX, angle), m)); }
/// <summary> /// Initializes a new instance of the <see cref="TerrainDecalLayer"/> class with a custom /// material. /// </summary> /// <param name="material">The material.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="material"/> is <see langword="null"/>. /// </exception> public TerrainDecalLayer(Material material) { if (material == null) { throw new ArgumentNullException("material"); } // Use a down orientation per default. Pose = new Pose(Matrix33F.CreateRotationX(-ConstantsF.PiOver2)); Material = material; UpdateAabb(); }
public override void Update(GameTime gameTime) { // Update the poses of the animated scene nodes. var frontWheelSteeringRotation = Matrix33F.CreateRotationY(_frontWheelSteeringAngle.Value); _frontWheelLeft.PoseLocal = _frontWheelLeftRestPose * new Pose(frontWheelSteeringRotation); _frontWheelRight.PoseLocal = _frontWheelRightRestPose * new Pose(frontWheelSteeringRotation); _hatch.PoseLocal = _hatchRestPose * new Pose(Matrix33F.CreateRotationX(_hatchAngle.Value)); _turret.PoseLocal = _turretRestPose * new Pose(Matrix33F.CreateRotationY(_turretAngle.Value)); _cannon.PoseLocal = _cannonRestPose * new Pose(Matrix33F.CreateRotationX(_cannonAngle.Value)); base.Update(gameTime); }
private void UpdateEphemeris() { #if XBOX _ephemeris.Time = new DateTimeOffset(_time.Ticks, TimeSpan.Zero); #else _ephemeris.Time = _time; #endif _ephemeris.Update(); var sunDirection = (Vector3F)_ephemeris.SunDirectionRefracted; var sunUp = sunDirection.Orthonormal1; var moonDirection = (Vector3F)_ephemeris.MoonPosition.Normalized; var moonUp = (Vector3F)_ephemeris.EquatorialToWorld.TransformDirection(Vector3D.Up); #if true _starfield.PoseWorld = new Pose((Matrix33F)_ephemeris.EquatorialToWorld.Minor); _sun.LookAt((Vector3F)_ephemeris.SunDirectionRefracted, sunUp); _moon.SunDirection = (Vector3F)_ephemeris.SunPosition.Normalized; #else Vector3F sunRotationAxis = new Vector3F(0, -0.1f, 1).Normalized; float hour = (float)_time.TimeOfDay.TotalHours / 24; Matrix33F sunRotation = Matrix33F.CreateRotation(sunRotationAxis, hour * ConstantsF.TwoPi - ConstantsF.PiOver2); _starfield.Orientation = sunRotation; _sun.Direction = sunRotation * new Vector3F(1, 0, 0); _moon.SunDirection = _sun.Direction; #endif _milkyWaySkybox.PoseWorld = new Pose( (Matrix33F)_ephemeris.EquatorialToWorld.Minor * Matrix33F.CreateRotationZ(ConstantsF.PiOver2) * Matrix33F.CreateRotationX(ConstantsF.PiOver2)); _moon.LookAt(moonDirection, moonUp); _cieSkyFilter.SunDirection = sunDirection; _gradientSky.SunDirection = sunDirection; _gradientTextureSky.SunDirection = sunDirection; _gradientTextureSky.TimeOfDay = _time.TimeOfDay; _scatteringSky.SunDirection = sunDirection; _cloudLayerNode.SunDirection = _scatteringSky.SunDirection; _cloudLayerNode.SunLight = ChangeSaturation(_scatteringSky.GetSunlight() / 5f, 1); //_cloudPlaneRenderer.Color = new Vector4F(ChangeSaturation(_scatteringSky.GetFogColor(128), 0.9f) * 1.0f, 1); //Vector3F c = (_scatteringSky.GetFogColor(128) + _scatteringSky.GetSunlight() / 10) / 2; //_cloudPlaneRenderer.Color = new Vector4F(c, 1); _cloudLayerNode.AmbientLight = _scatteringSky.GetAmbientLight(1024) / 6f; //_cloudLayerNode.AmbientLight = _scatteringSky.GetFogColor(128) * _scatteringSky.GetAmbientLight(256).Length / 6f; }
public override void Update(GameTime gameTime) { base.Update(gameTime); // ----- Animate the 2 cubes. _animationTime += (float)gameTime.ElapsedGameTime.TotalSeconds * 10; // Before updating the positions and orientations, store the previous poses of // the scene nodes. (The property SceneNode.LastPoseWorld is read by certain // post-processing effects, such as motion blur.) _movingCube.SetLastPose(true); _rotatingCube.SetLastPose(true); _movingCube.PoseWorld = new Pose(new Vector3F(-6, 1, -3 + (float)Math.Sin(_animationTime) * 2f)); _rotatingCube.PoseWorld = new Pose(new Vector3F(-4, 1, -1), Matrix33F.CreateRotationX(_animationTime)); // <1> / <Shift> + <1> --> Change number of samples. if (InputService.IsPressed(Keys.D1, true)) { bool isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0; float delta = isShiftDown ? +1 : -1; _objectMotionBlur.NumberOfSamples = MathHelper.Max(_objectMotionBlur.NumberOfSamples + delta, 1); } // <2> / <Shift> + <2> --> Change max blur radius. if (InputService.IsDown(Keys.D2)) { // Increase or decrease value by a factor of 1.01 every frame (1/60 s). bool isShiftDown = (InputService.ModifierKeys & ModifierKeys.Shift) != 0; float factor = isShiftDown ? 1.01f : 1.0f / 1.01f; float time = (float)gameTime.ElapsedGameTime.TotalSeconds; _objectMotionBlur.MaxBlurRadius = MathHelper.Max(_objectMotionBlur.MaxBlurRadius * (float)Math.Pow(factor, time * 60), 1); } // <3> / <Shift> + <3> --> Toggle soft edges. if (InputService.IsPressed(Keys.D3, false)) { _objectMotionBlur.SoftenEdges = !_objectMotionBlur.SoftenEdges; } GraphicsScreen.DebugRenderer.DrawText( "\n\nHold <1> or <Shift>+<1> to decrease or increase the number of samples: " + _objectMotionBlur.NumberOfSamples + "\nHold <2> or <Shift>+<2> to decrease or increase the max blur radius: " + _objectMotionBlur.MaxBlurRadius + "\nPress <3> to toggle soft edges: " + _objectMotionBlur.SoftenEdges); }
private static Pose GetRandomPose() { // Get a random position. const float decalAreaSize = 20; var randomPosition = new Vector3F( RandomHelper.Random.NextFloat(-decalAreaSize, decalAreaSize), 0, RandomHelper.Random.NextFloat(-decalAreaSize, 0)); // Decals are project along the forward (-z) direction. // To project onto the terrain we have to point the decal down. var downOrientation = Matrix33F.CreateRotationX(-ConstantsF.PiOver2); // Get a random rotation around z. var randomOrientation = Matrix33F.CreateRotationZ(RandomHelper.Random.NextFloat(0, ConstantsF.TwoPi)); return(new Pose(randomPosition, downOrientation * randomOrientation)); }
public CampfireSample(Microsoft.Xna.Framework.Game game) : base(game) { var particleSystem = Campfire.CreateCampfire(ContentManager); // Add a smoke effect as a child to the campfire. particleSystem.Children = new ParticleSystemCollection(); particleSystem.Children.Add(CampfireSmoke.CreateCampfireSmoke(ContentManager)); // Position the campfire (including its child) in the level. // (The fire effect lies in the xy plane and shoots into the forward direction (= -z axis). // Therefore, we rotate the particle system to shoot upwards.) particleSystem.Pose = new Pose(new Vector3F(0, 0.2f, 0), Matrix33F.CreateRotationX(ConstantsF.PiOver2)); ParticleSystemService.ParticleSystems.Add(particleSystem); _particleSystemNode = new ParticleSystemNode(particleSystem); GraphicsScreen.Scene.Children.Add(_particleSystemNode); }
public void Test1() { Pose p = Pose.Identity; Assert.AreEqual(Matrix44F.Identity, p.ToMatrix44F()); Assert.AreEqual(Matrix33F.Identity, p.Orientation); Assert.AreEqual(Vector3F.Zero, p.Position); p.Position = new Vector3F(1, 2, 3); p.Orientation = Matrix33F.CreateRotation(new Vector3F(3, -4, 9), 0.49f); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldDirection(Vector3F.UnitX), 0), p * new Vector4F(1, 0, 0, 0))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldDirection(Vector3F.UnitY), 0), p * new Vector4F(0, 1, 0, 0))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldDirection(Vector3F.UnitZ), 0), p * new Vector4F(0, 0, 1, 0))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldPosition(Vector3F.UnitX), 1), p * new Vector4F(1, 0, 0, 1))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldPosition(Vector3F.UnitY), 1), p * new Vector4F(0, 1, 0, 1))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToWorldPosition(Vector3F.UnitZ), 1), p * new Vector4F(0, 0, 1, 1))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalDirection(Vector3F.UnitX), 0), p.Inverse * new Vector4F(1, 0, 0, 0))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalDirection(Vector3F.UnitY), 0), p.Inverse * new Vector4F(0, 1, 0, 0))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalDirection(Vector3F.UnitZ), 0), p.Inverse * new Vector4F(0, 0, 1, 0))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalPosition(Vector3F.UnitX), 1), p.Inverse * new Vector4F(1, 0, 0, 1))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalPosition(Vector3F.UnitY), 1), p.Inverse * new Vector4F(0, 1, 0, 1))); Assert.IsTrue(Vector4F.AreNumericallyEqual(new Vector4F(p.ToLocalPosition(Vector3F.UnitZ), 1), p.Inverse * new Vector4F(0, 0, 1, 1))); Pose p2 = Pose.FromMatrix(new Matrix44F(p.Orientation, Vector3F.Zero)); Assert.IsTrue(Matrix33F.AreNumericallyEqual(p.Orientation, p2.Orientation)); Assert.IsTrue(Vector3F.AreNumericallyEqual(p2.Position, Vector3F.Zero)); Matrix44F m = p2; m.SetColumn(3, new Vector4F(p.Position, 1)); p2 = Pose.FromMatrix(m); Assert.IsTrue(Matrix33F.AreNumericallyEqual(p.Orientation, p2.Orientation)); Assert.AreEqual(p.Position, p2.Position); //Assert.IsTrue(Vector3F.AreNumericallyEqual(p.Position, p2.Position)); // Test other constructors. Assert.AreEqual(Vector3F.Zero, new Pose(QuaternionF.CreateRotationX(0.3f)).Position); Assert.AreEqual(Matrix33F.CreateRotationX(0.3f), new Pose(Matrix33F.CreateRotationX(0.3f)).Orientation); Assert.AreEqual(new Vector3F(1, 2, 3), new Pose(new Vector3F(1, 2, 3)).Position); Assert.AreEqual(Matrix33F.Identity, new Pose(new Vector3F(1, 2, 3)).Orientation); }
private void UpdateOrientation(Vector delta) { Pose pose = _cameraNode.PoseWorld; // Get previous yaw and pitch angles. float yaw, pitch; GetYawPitch(pose.Orientation, out yaw, out pitch); // Apply delta. float speed = (float)Speed; yaw -= (float)delta.X * speed; pitch -= (float)delta.Y * speed; // Set new camera orientation. pose.Orientation = Matrix33F.CreateRotationY(yaw) * Matrix33F.CreateRotationX(pitch); _cameraNode.PoseWorld = pose; }
public void Orthogonalize() { var m = Matrix33F.CreateRotationX(0.1f) * Matrix33F.CreateRotationY(20) * Matrix33F.CreateRotationZ(1000); // Introduce error. m.M01 += 0.1f; m.M22 += 0.1f; Assert.IsFalse(m.IsOrthogonal); Assert.IsFalse(m.IsRotation); m.Orthogonalize(); Assert.IsTrue(m.IsOrthogonal); Assert.IsTrue(m.IsRotation); // Orthogonalizing and orthogonal matrix does not change the matrix. var n = m; n.Orthogonalize(); Assert.IsTrue(Matrix33F.AreNumericallyEqual(m, n)); }
public BrownOut(ContentManager contentManager) { Pose = new Pose(Matrix33F.CreateRotationX(-ConstantsF.PiOver2)); // Smoke on a ring. var outerRingSmoke = CreateSmoke(contentManager); outerRingSmoke.Effectors.Add(new StreamEmitter { DefaultEmissionRate = 30 }); outerRingSmoke.Effectors.Add(new StartPositionEffector { Distribution = new CircleDistribution { OuterRadius = 5, InnerRadius = 4 } }); // Smoke in the area inside the ring. var innerCircleSmoke = CreateSmoke(contentManager); innerCircleSmoke.Effectors.Add(new StreamEmitter { DefaultEmissionRate = 10 }); innerCircleSmoke.Effectors.Add(new StartPositionEffector { Distribution = new CircleDistribution { OuterRadius = 4, InnerRadius = 0 } }); // Uniform particle parameter that are the same for all child particle systems. Parameters.AddUniform <float>(ParticleParameterNames.Lifetime).DefaultValue = 5; _isDepthSortedParameter = Parameters.AddUniform <bool>(ParticleParameterNames.IsDepthSorted); _isDepthSortedParameter.DefaultValue = true; Children = new ParticleSystemCollection { outerRingSmoke, innerCircleSmoke }; }
private void OnMouseMove(object sender, MouseEventArgs eventArgs) { var mousePosition = eventArgs.GetPosition(AssociatedObject); if (eventArgs.LeftButton == MouseButtonState.Pressed) { var target = CameraTarget; float speed = (float)Speed; Vector delta = mousePosition - _lastMousePosition; // Rotation around y-axis in world space float angle0 = (float)delta.X * speed * _upDirection; Pose rotation0 = new Pose(Matrix33F.CreateRotationY(angle0)); // Rotation around x-axis in view space. float angle1 = (float)delta.Y * speed; Pose rotation1 = new Pose(Matrix33F.CreateRotationX(angle1)); float distance = (CameraTarget - _cameraNode.PoseWorld.Position).Length; // Variant #1: Set camera pose. var pose = new Pose(target) * rotation0.Inverse * new Pose(-target) * _cameraNode.PoseWorld * new Pose(new Vector3F(0, 0, -distance)) * rotation1.Inverse * new Pose(new Vector3F(0, 0, distance)); // Re-orthogonalize to remove numerical errors which could add up. var orientation = pose.Orientation; orientation.Orthogonalize(); pose.Orientation = orientation; CameraNode.PoseWorld = pose; } _lastMousePosition = mousePosition; }
public static void Load(CollisionDomain collisionDomain) { // Create a box for the ground. AddObject("Ground", new Pose(new Vector3F(0, -5, 0)), new BoxShape(60, 10, 60), collisionDomain); // Create a small flying sphere to visualize the approx. head height. - This is just // for debugging so that we have a feeling for heights. AddObject("Sphere", new Pose(new Vector3F(0, 1.5f, 0)), new SphereShape(0.2f), collisionDomain); // Create small walls at the level boundary. AddObject("WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain); AddObject("WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), collisionDomain); AddObject("WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), collisionDomain); AddObject("WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), collisionDomain); // Create a few bigger objects. // We position the boxes so that we have a few corners we can run into. Character controllers // should be stable when the user runs into corners. AddObject("House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), collisionDomain); AddObject("House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), collisionDomain); AddObject("House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), collisionDomain); // // Create stairs with increasing step height. // // Each step is a box. With this object we can test if our character can climb up // stairs. The character controller has a step height limit. Increasing step heights // let us test if the step height limit works. float startHeight = 0; const float stepDepth = 1f; for (int i = 0; i < 10; i++) { float stepHeight = 0.1f + i * 0.05f; Pose pose = new Pose(new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth)); BoxShape shape = new BoxShape(2, stepHeight, stepDepth); AddObject("Step" + i, pose, shape, collisionDomain); startHeight += stepHeight; } // // Create a height field. // // Terrain that is uneven is best modeled with a height field. Height fields are faster // than general triangle meshes. // The height direction is the y direction. // The height field lies in the x/z plane. var numberOfSamplesX = 20; var numberOfSamplesZ = 20; var samples = new float[numberOfSamplesX * numberOfSamplesZ]; // Create arbitrary height values. for (int z = 0; z < numberOfSamplesZ; z++) { for (int x = 0; x < numberOfSamplesX; x++) { if (x == 0 || z == 0 || x == 19 || z == 19) { // Set this boundary elements to a low height, so that the height field is connected // to the ground. samples[z * numberOfSamplesX + x] = -1; } else { // A sine/cosine function that creates some interesting waves. samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f); } } } var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ); AddObject("Heightfield", new Pose(new Vector3F(10, 0, 10)), heightField, collisionDomain); // Create rubble on the floor (small random objects on the floor). // Our character should be able to move over small bumps on the ground. for (int i = 0; i < 50; i++) { Pose pose = new Pose( new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)), RandomHelper.Random.NextQuaternionF()); BoxShape shape = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.8f)); AddObject("Stone" + i, pose, shape, collisionDomain); } // Create some slopes to see how our character performs on/under sloped surfaces. // Here we can test how the character controller behaves if the head touches an inclined // ceiling. AddObject("SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain); AddObject("SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), collisionDomain); // Slopes with different tilt angles. // The character controller has a slope limit. Only flat slopes should be climbable. for (int i = 0; i < 10; i++) { float stepHeight = 0.1f + i * 0.1f; Pose pose = new Pose( new Vector3F(-10, i * 0.5f, -i * 2), Matrix33F.CreateRotationX(MathHelper.ToRadians(10) + i * MathHelper.ToRadians(10))); BoxShape shape = new BoxShape(8 * (1 - i * 0.1f), 0.5f, 30); AddObject("Slope" + i, pose, shape, collisionDomain); startHeight += stepHeight; } // Create a slope with a wall on one side. // This objects let's us test how the character controller behaves while falling and // sliding along a vertical wall. (Run up the slope and then jump down while moving into // the wall.) AddObject("LongSlope", new Pose(new Vector3F(-20, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), collisionDomain); AddObject("LongSlopeWall", new Pose(new Vector3F(-22, 5, -10)), new BoxShape(0.5f, 10f, 25), collisionDomain); // Create a mesh object to test walking on triangle meshes. // Normally, the mesh would be loaded from a file. Here, we make a composite shape and // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite // shape and use only the mesh. - We do this to test triangle meshes. Using the composite // shape instead of the triangle mesh would be a lot faster. CompositeShape compositeShape = new CompositeShape(); compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity)); compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10)))); compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15)))); compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5)))); ITriangleMesh mesh = compositeShape.GetMesh(0.01f, 3); TriangleMeshShape meshShape = new TriangleMeshShape(mesh); // Collision detection speed for triangle meshes can be improved by using a spatial // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is // built automatically when needed and it stores triangle indices (therefore the generic // parameter of the AabbTree is int). meshShape.Partition = new AabbTree <int>() { // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up // building is slower but produces better trees. If the tree building takes too long, // we can lower the BottomUpBuildThreshold (default is 128). BottomUpBuildThreshold = 0, }; AddObject("Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, collisionDomain); }
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); } }
public DistortionSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; _graphicsScreen = new DeferredGraphicsScreen(Services); _graphicsScreen.DrawReticle = true; GraphicsService.Screens.Insert(0, _graphicsScreen); GameObjectService.Objects.Add(new DeferredGraphicsOptionsObject(Services)); Services.Register(typeof(DebugRenderer), null, _graphicsScreen.DebugRenderer); Services.Register(typeof(IScene), null, _graphicsScreen.Scene); // Add gravity and damping to the physics simulation. Simulation.ForceEffects.Add(new Gravity()); Simulation.ForceEffects.Add(new Damping()); // Add a custom game object which controls the camera. var cameraGameObject = new CameraObject(Services); GameObjectService.Objects.Add(cameraGameObject); _graphicsScreen.ActiveCameraNode = cameraGameObject.CameraNode; GameObjectService.Objects.Add(new GrabObject(Services)); GameObjectService.Objects.Add(new StaticSkyObject(Services)); // Skybox + some lights. //GameObjectService.Objects.Add(new GroundObject(Services)); // Add a ground plane with some detail to see the water refractions. Simulation.RigidBodies.Add(new RigidBody(new PlaneShape(new Vector3F(0, 1, 0), 0))); GameObjectService.Objects.Add(new StaticObject(Services, "Gravel/Gravel", 1, new Pose(new Vector3F(0, 0.001f, 0)))); GameObjectService.Objects.Add(new DudeObject(Services)); GameObjectService.Objects.Add(new DynamicObject(Services, 1)); GameObjectService.Objects.Add(new DynamicObject(Services, 2)); GameObjectService.Objects.Add(new DynamicObject(Services, 3)); GameObjectService.Objects.Add(new DynamicObject(Services, 5)); GameObjectService.Objects.Add(new DynamicObject(Services, 6)); GameObjectService.Objects.Add(new DynamicObject(Services, 7)); GameObjectService.Objects.Add(new ObjectCreatorObject(Services)); GameObjectService.Objects.Add(new FogObject(Services)); GameObjectService.Objects.Add(new CampfireObject(Services)); GameObjectService.Objects.Add(new LavaBallsObject(Services)); // Add a few palm trees. Random random = new Random(12345); for (int i = 0; i < 10; i++) { Vector3F position = new Vector3F(random.NextFloat(-3, -8), 0, random.NextFloat(0, -5)); Matrix33F orientation = Matrix33F.CreateRotationY(random.NextFloat(0, ConstantsF.TwoPi)); float scale = random.NextFloat(0.5f, 1.2f); GameObjectService.Objects.Add(new StaticObject(Services, "PalmTree/palm_tree", scale, new Pose(position, orientation))); } // Add DistortionFilter to post-processors. _distortionFilter = new DistortionFilter(GraphicsService, ContentManager); _graphicsScreen.PostProcessors.Add(_distortionFilter); // Add 3 particle systems. // The ParticleSystems are added to the IParticleSystemService. // The ParticleSystemNodes are added to the Scene of the DistortionFilter - not the usual Scene! _fireDistortionParticleSystemNode = new ParticleSystemNode(CreateFireDistortionParticleSystem()) { PoseLocal = new Pose(new Vector3F(0, 0f, -1), Matrix33F.CreateRotationX(ConstantsF.PiOver2)), }; ParticleSystemService.ParticleSystems.Add(_fireDistortionParticleSystemNode.ParticleSystem); _distortionFilter.Scene.Children.Add(_fireDistortionParticleSystemNode); _explosionDistortionParticleSystemNode = new ParticleSystemNode(CreateExplosionDistortionParticleSystem()) { PoseLocal = new Pose(new Vector3F(0, 0, -1)), }; ParticleSystemService.ParticleSystems.Add(_explosionDistortionParticleSystemNode.ParticleSystem); _distortionFilter.Scene.Children.Add(_explosionDistortionParticleSystemNode); _novaDistortionParticleSystemNode = new ParticleSystemNode(CreateNovaDistortionParticleSystem()) { PoseLocal = new Pose(new Vector3F(0, 0.5f, -1), Matrix33F.CreateRotationX(ConstantsF.PiOver2)), }; ParticleSystemService.ParticleSystems.Add(_novaDistortionParticleSystemNode.ParticleSystem); _distortionFilter.Scene.Children.Add(_novaDistortionParticleSystemNode); }
protected override void OnLoad() { var contentManager = _services.GetInstance <ContentManager>(); _lights.Add(new LightNode(new AmbientLight { Color = new Vector3F(0.9f, 0.9f, 1f), Intensity = 0.05f, HemisphericAttenuation = 1, }) { Name = "AmbientLight", // This ambient light is "infinite", the pose is irrelevant for the lighting. It is only // used for the debug rendering below. PoseWorld = new Pose(new Vector3F(0, 4, 0)), }); _lights.Add(new LightNode(new DirectionalLight { Color = new Vector3F(0.6f, 0.8f, 1f), DiffuseIntensity = 0.1f, SpecularIntensity = 0.1f, }) { Name = "DirectionalLightWithShadow", Priority = 10, // This is the most important light. PoseWorld = new Pose(new Vector3F(0, 5, 0), Matrix33F.CreateRotationY(-1.4f) * Matrix33F.CreateRotationX(-0.6f)), Shadow = new CascadedShadow { PreferredSize = 1024, DepthBiasScale = new Vector4F(0.99f), DepthBiasOffset = new Vector4F(0), FadeOutDistance = 20, MaxDistance = 30, MinLightDistance = 5, ShadowFog = 0.5f, JitterResolution = 3000, SplitDistribution = 0.7f } }); _lights.Add(new LightNode(new DirectionalLight { Color = new Vector3F(0.8f, 0.4f, 0.0f), DiffuseIntensity = 0.1f, SpecularIntensity = 0.0f, }) { Name = "DirectionalLight", PoseWorld = new Pose(new Vector3F(0, 6, 0), Matrix33F.CreateRotationY(-1.4f) * Matrix33F.CreateRotationX(-0.6f) * Matrix33F.CreateRotationX(ConstantsF.Pi)), }); _lights.Add(new LightNode(new PointLight { Color = new Vector3F(0, 1, 0), DiffuseIntensity = 2, SpecularIntensity = 2, Range = 3, Attenuation = 1f, }) { Name = "PointLight", PoseWorld = new Pose(new Vector3F(-7, 1, 0)) }); _lights.Add(new LightNode(new PointLight { DiffuseIntensity = 4, SpecularIntensity = 4, Range = 3, Attenuation = 1f, Texture = contentManager.Load <TextureCube>("LavaBall/LavaCubeMap"), }) { Name = "PointLightWithTexture", PoseWorld = new Pose(new Vector3F(-2, 1, 0)) }); _lights.Add(new LightNode(new PointLight { Color = new Vector3F(1, 1, 1), DiffuseIntensity = 2, SpecularIntensity = 2, Range = 3, Attenuation = 1f, }) { Name = "PointLightWithShadow", PoseWorld = new Pose(new Vector3F(2, 1, 0)), Shadow = new CubeMapShadow { PreferredSize = 128, DepthBiasScale = 0.9f, DepthBiasOffset = -0.01f, } }); _lights.Add(new LightNode(new PointLight { Color = new Vector3F(1, 1, 1), DiffuseIntensity = 4, SpecularIntensity = 4, Range = 3, Attenuation = 1f, Texture = contentManager.Load <TextureCube>("MagicSphere/ColorCube"), }) { Name = "PointLightWithTextureAndShadow", PoseWorld = new Pose(new Vector3F(7, 1, 0)), Shadow = new CubeMapShadow { PreferredSize = 128, DepthBiasScale = 0.9f, DepthBiasOffset = -0.01f, } }); _lights.Add(new LightNode(new ProjectorLight { Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "ProjectorLight", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(-1, 1, -6), new Vector3F(-5, 0, -6), new Vector3F(0, 1, 0))).Inverse, }); _lights.Add(new LightNode(new ProjectorLight { Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "ProjectorLightWithShadow", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(5, 1, -6), new Vector3F(1, 0, -6), new Vector3F(0, 1, 0))).Inverse, Shadow = new StandardShadow { PreferredSize = 128, } }); _lights.Add(new LightNode(new Spotlight { Color = new Vector3F(0, 1, 0), DiffuseIntensity = 2, SpecularIntensity = 2, }) { Name = "Spotlight", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(-7, 1, -12), new Vector3F(-10, 0, -12), new Vector3F(0, 1, 0))).Inverse, }); _lights.Add(new LightNode(new Spotlight { DiffuseIntensity = 2, SpecularIntensity = 2, Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "SpotlightWithTexture", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(-1, 1, -12), new Vector3F(-5, 0, -12), new Vector3F(0, 1, 0))).Inverse, }); _lights.Add(new LightNode(new Spotlight { DiffuseIntensity = 2, SpecularIntensity = 2, }) { Name = "SpotlightWithShadow", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(5, 1, -12), new Vector3F(1, 0, -12), new Vector3F(0, 1, 0))).Inverse, Shadow = new StandardShadow { PreferredSize = 128, } }); _lights.Add(new LightNode(new Spotlight { Color = new Vector3F(1, 1, 0), DiffuseIntensity = 2, SpecularIntensity = 2, Texture = contentManager.Load <Texture2D>("TVBox/TestCard"), }) { Name = "SpotlightWithTextureAndShadow", PoseWorld = Pose.FromMatrix(Matrix44F.CreateLookAt(new Vector3F(11, 1, -12), new Vector3F(5, 0, -12), new Vector3F(0, 1, 0))).Inverse, Shadow = new StandardShadow { PreferredSize = 128, } }); var scene = _services.GetInstance <IScene>(); _debugRenderer = _services.GetInstance <DebugRenderer>(); foreach (var lightNode in _lights) { scene.Children.Add(lightNode); } }
private void UpdateSky() { // Update ephemeris model. #if XBOX _ephemeris.Time = new DateTimeOffset(_time.Ticks, TimeSpan.Zero); #else _ephemeris.Time = _time; #endif _ephemeris.Update(); // Update rotation of milky way. We also need to add an offset because the // cube map texture is rotated. _milkyWayNode.PoseWorld = new Pose( (Matrix33F)_ephemeris.EquatorialToWorld.Minor * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 + -0.004f) * Matrix33F.CreateRotationX(ConstantsF.PiOver2 + -0.002f)); // Update rotation of stars. _starfieldNode.PoseWorld = new Pose((Matrix33F)_ephemeris.EquatorialToWorld.Minor); // Update direction of sun. SunDirection = (Vector3F)_ephemeris.SunDirectionRefracted; var sunUp = SunDirection.Orthonormal1; _sunNode.LookAt(SunDirection, sunUp); // Update direction of moon. var moonDirection = (Vector3F)_ephemeris.MoonPosition.Normalized; var moonUp = (Vector3F)_ephemeris.EquatorialToWorld.TransformDirection(Vector3D.Up); _moonNode.LookAt(moonDirection, moonUp); // The moon needs to know the sun position and brightness to compute the moon phase. _moonNode.SunDirection = (Vector3F)_ephemeris.SunPosition.Normalized; _moonNode.SunLight = Ephemeris.ExtraterrestrialSunlight * SunlightScale; // The ScatteringSky needs the sun direction and brightness to compute the sky colors. _scatteringSkyNode.SunDirection = SunDirection; _scatteringSkyNode.SunColor = Ephemeris.ExtraterrestrialSunlight * ScatteringSkyLightScale; // Update the light directions. _sunlightNode.LookAt(-SunDirection, sunUp); _moonlightNode.LookAt(-moonDirection, moonUp); // The ScatteringSkyNode can compute the actual sunlight. SunLight = _scatteringSkyNode.GetSunlight(); // Undo the ScatteringSkyLightScale and apply a custom scale for the sunlight. SunLight = SunLight / ScatteringSkyLightScale * SunlightScale; // The ScatteringSkyNode can also compute the ambient light by sampling the // sky hemisphere. AmbientLight = _scatteringSkyNode.GetAmbientLight(256); AmbientLight = AmbientLight / ScatteringSkyLightScale * SunlightScale; // Desaturate the ambient light to avoid very blue shadows. AmbientLight = InterpolationHelper.Lerp( new Vector3F(Vector3F.Dot(AmbientLight, GraphicsHelper.LuminanceWeights)), AmbientLight, 0.5f); // The Ephemeris model can compute the actual moonlight. Vector3F moonlight, moonAmbient; Ephemeris.GetMoonlight( _scatteringSkyNode.ObserverAltitude, 2.2f, _ephemeris.MoonPosition, (float)_ephemeris.MoonPhaseAngle, out moonlight, out moonAmbient); moonlight *= MoonlightScale; moonAmbient *= MoonlightScale; // Scale sun light to 0 at horizon. var directionalLightColor = SunLight; directionalLightColor *= MathHelper.Clamp(SunDirection.Y / 0.1f, 0, 1); var directionalLight = ((DirectionalLight)_sunlightNode.Light); directionalLight.Color = directionalLightColor; ((DirectionalLight)_moonlightNode.Light).Color = moonlight; ((AmbientLight)_ambientLightNode.Light).Color = AmbientLight + moonAmbient + LightPollution; // Use the sunlight color to create a bright sun disk. var sunDiskColor = SunLight; sunDiskColor.TryNormalize(); _sunNode.GlowColor0 = sunDiskColor * Ephemeris.ExtraterrestrialSunlight.Length * SunlightScale * 10; if (_enableClouds) { // Update lighting info of cloud layer nodes. _cloudLayerNode0.SunDirection = SunDirection; _cloudLayerNode0.SunLight = SunLight; _cloudLayerNode0.AmbientLight = AmbientLight; // The second cloud layer uses simple unlit clouds (only ambient lighting). _cloudLayerNode1.SunDirection = SunDirection; _cloudLayerNode1.SunLight = Vector3F.Zero; _cloudLayerNode1.AmbientLight = AmbientLight + SunLight; // Use the cloud map as the texture for the directional light to create cloud shadows. if (EnableCloudShadows) { directionalLight.Texture = _cloudLayerNode0.CloudMap.Texture; } else { directionalLight.Texture = null; } // Compute a texture offset so that the current sun position and the projected cloud // shadows match. // Since sky dome is always centered on the camera, position the sunlight node in // line with the camera. var cameraPosition = _cameraObject.CameraNode.PoseWorld.Position; var upVector = Vector3F.AreNumericallyEqual(SunDirection, Vector3F.UnitZ) ? Vector3F.UnitY : Vector3F.UnitZ; _sunlightNode.LookAt(cameraPosition + SunDirection, cameraPosition, upVector); // Choose a scale for the cloud shadows. directionalLight.TextureScale = new Vector2F(-1000); // Get the scaled texture offset for the sun direction. directionalLight.TextureOffset = _cloudLayerNode0.GetTextureCoordinates(SunDirection) * directionalLight.TextureScale; } // The ScatteringSkyNode can also estimate a fog color by sampling the horizon colors. Vector3F fogColor = _scatteringSkyNode.GetFogColor(256, FogSampleAngle); // Desaturate the fog color. fogColor = InterpolationHelper.Lerp( new Vector3F(Vector3F.Dot(fogColor, GraphicsHelper.LuminanceWeights)), fogColor, FogSaturation); // Find any FogNode in the scene and update its fog color. foreach (var fogNode in ((Scene)_scene).GetSubtree().OfType <FogNode>()) { var fog = fogNode.Fog; fog.Color0 = fog.Color1 = new Vector4F(fogColor, 1); fog.ScatteringSymmetry = FogScatteringSymmetry; } // TODO: If the fog is dense, reduce the direct light and increase the ambient light. }
protected override void OnLoad() { // Add rigid bodies to simulation. var simulation = _services.GetInstance <Simulation>(); // ----- Add a ground plane. AddBody(simulation, "GroundPlane", Pose.Identity, new PlaneShape(Vector3F.UnitY, 0), MotionType.Static); // ----- Create a height field. var numberOfSamplesX = 20; var numberOfSamplesZ = 20; var samples = new float[numberOfSamplesX * numberOfSamplesZ]; for (int z = 0; z < numberOfSamplesZ; z++) { for (int x = 0; x < numberOfSamplesX; x++) { if (x == 0 || z == 0 || x == 19 || z == 19) { samples[z * numberOfSamplesX + x] = -1; } else { samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f); } } } HeightField heightField = new HeightField(0, 0, 120, 120, samples, numberOfSamplesX, numberOfSamplesZ); //heightField.UseFastCollisionApproximation = true; AddBody(simulation, "HeightField", new Pose(new Vector3F(10, 0, 20)), heightField, MotionType.Static); // ----- Create rubble on the floor (small random objects on the floor). for (int i = 0; i < 60; i++) { Vector3F position = new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)); QuaternionF orientation = RandomHelper.Random.NextQuaternionF(); BoxShape shape = new BoxShape(RandomHelper.Random.NextVector3F(0.05f, 0.5f)); AddBody(simulation, "Stone" + i, new Pose(position, orientation), shape, MotionType.Static); } // ----- Slopes with different tilt angles. // Create a loop. Vector3F slopePosition = new Vector3F(-20, -0.25f, -5); BoxShape slopeShape = new BoxShape(8, 0.5f, 2); for (int i = 1; i < 33; i++) { Matrix33F oldRotation = Matrix33F.CreateRotationX((i - 1) * MathHelper.ToRadians(10)); Matrix33F rotation = Matrix33F.CreateRotationX(i * MathHelper.ToRadians(10)); slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2; AddBody(simulation, "Loop" + i, new Pose(slopePosition, rotation), slopeShape, MotionType.Static); } // Create an arched bridge. slopePosition = new Vector3F(-10, -2, -15); slopeShape = new BoxShape(8f, 0.5f, 5); for (int i = 1; i < 8; i++) { Matrix33F oldRotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - (i - 1) * MathHelper.ToRadians(10)); Matrix33F rotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - i * MathHelper.ToRadians(10)); slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2; Vector3F position = slopePosition - rotation * new Vector3F(0, slopeShape.WidthY / 2, 0); AddBody(simulation, "Bridge" + i, new Pose(position, rotation), slopeShape, MotionType.Static); } // ----- Create a mesh object. // We first build a composite shape out of several primitives and then convert the // composite shape to a triangle mesh. (Just for testing.) CompositeShape compositeShape = new CompositeShape(); compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity)); compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10)))); compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15)))); compositeShape.Children.Add(new GeometricObject(new BoxShape(1, 2, 3), new Pose(new Vector3F(15, 0, 5)))); ITriangleMesh mesh = compositeShape.GetMesh(0.01f, 3); TriangleMeshShape meshShape = new TriangleMeshShape(mesh, true); meshShape.Partition = new AabbTree <int>() { BottomUpBuildThreshold = 0 }; AddBody(simulation, "Mesh", new Pose(new Vector3F(-120, 0, 20)), meshShape, MotionType.Static); // ----- Create a seesaw. var seesawBase = AddBody(simulation, "SeesawBase", new Pose(new Vector3F(15, 0.5f, 0)), new BoxShape(0.2f, 1, 6), MotionType.Static); var seesaw = AddBody(simulation, "Seesaw", new Pose(new Vector3F(16, 1.05f, 0)), new BoxShape(15, 0.1f, 6), MotionType.Dynamic); seesaw.MassFrame.Mass = 500; seesaw.CanSleep = false; // Connect seesaw using a hinge joint. simulation.Constraints.Add(new HingeJoint { BodyA = seesaw, BodyB = seesawBase, AnchorPoseALocal = new Pose(new Vector3F(1.0f, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), AnchorPoseBLocal = new Pose(new Vector3F(0, 0.5f, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), CollisionEnabled = false, }); // ----- Distribute a few dynamic spheres and boxes across the landscape. SphereShape sphereShape = new SphereShape(0.5f); for (int i = 0; i < 40; i++) { Vector3F position = RandomHelper.Random.NextVector3F(-60, 60); position.Y = 10; AddBody(simulation, "Sphere" + i, new Pose(position), sphereShape, MotionType.Dynamic); } BoxShape boxShape = new BoxShape(1.0f, 1.0f, 1.0f); for (int i = 0; i < 40; i++) { Vector3F position = RandomHelper.Random.NextVector3F(-60, 60); position.Y = 1; AddBody(simulation, "Box" + i, new Pose(position), boxShape, MotionType.Dynamic); } }
// 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; } }
public FigurePickerObject(IGraphicsService graphicsService, Scene scene, CameraObject cameraObject, DebugRenderer debugRenderer) { _cameraObject = cameraObject; _scene = scene; _debugRenderer = debugRenderer; // Create a collision domain which manages all collision objects used for // picking: the picking object and the collision objects for figure nodes. _collisionDomain = new CollisionDomain(new CollisionDetection()); // Create the picking object: // The picking object represents the mouse cursor or the reticle. Usually // a ray is used, but in this example we want to use a cylinder/cone. This // allows to check which objects within a certain radius of the reticle. A // picking cylinder/cone is helpful for touch devices where the picking is // done with an imprecise input method like the human finger. // We want to pick objects in 10 pixel radius around the reticle. To determine // the world space size of the required cylinder/cone, we can use the projection // and the viewport. const float pickingRadius = 10; var projection = _cameraObject.CameraNode.Camera.Projection; var viewport = graphicsService.GraphicsDevice.Viewport; Shape pickingShape; if (projection is OrthographicProjection) { // Use cylinder for orthographic projections: // The cylinder is centered at the camera position and reaches from the // camera position to the camera far plane. A TransformedShape is used // to rotate and translate the cylinder. float radius = projection.Width / viewport.Width * pickingRadius; pickingShape = new TransformedShape( new GeometricObject( new CylinderShape(radius, projection.Far), new Pose(new Vector3F(0, 0, -projection.Far / 2), Matrix33F.CreateRotationX(ConstantsF.PiOver2)))); } else { // Use cone for perspective projections: // The cone tip is at the camera position and the cone base is at the // camera far plane. // Compute the radius at the far plane that projects to 10 pixels in screen space. float radius = viewport.Unproject( new Vector3(viewport.Width / 2.0f + pickingRadius, viewport.Height / 2.0f, 1), (Matrix)_cameraObject.CameraNode.Camera.Projection.ToMatrix44F(), Matrix.Identity, Matrix.Identity).X; // A transformed shape is used to rotate and translate the cone. pickingShape = new TransformedShape( new GeometricObject( new ConeShape(radius, projection.Far), new Pose(new Vector3F(0, 0, -projection.Far), Matrix33F.CreateRotationX(ConstantsF.PiOver2)))); } // Create collision object with the picking shape. _pickingObject = new CollisionObject(new GeometricObject(pickingShape, _cameraObject.CameraNode.PoseWorld)); }
//-------------------------------------------------------------- #region Methods //-------------------------------------------------------------- protected override void OnLoad() { // Add rigid bodies to simulation. var simulation = _services.GetInstance <Simulation>(); // We use a random number generator with a custom seed. RandomHelper.Random = new Random(123); // ----- Add a ground plane. AddBody(simulation, "GroundPlane", Pose.Identity, new PlaneShape(Vector3F.UnitY, 0), MotionType.Static); // ----- Create a small flying sphere. AddBody(simulation, "Sphere", new Pose(new Vector3F(0, 1f, 0)), new SphereShape(0.2f), MotionType.Static); // ----- Create small walls at the level boundary. AddBody(simulation, "WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), MotionType.Static); AddBody(simulation, "WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), MotionType.Static); AddBody(simulation, "WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), MotionType.Static); AddBody(simulation, "WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), MotionType.Static); // ----- Create a few bigger objects. // We position the boxes so that we have a few corners we can run into. Character controllers // should be stable when the user runs into corners. AddBody(simulation, "House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), MotionType.Static); AddBody(simulation, "House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), MotionType.Static); AddBody(simulation, "House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), MotionType.Static); // ----- Create stairs with increasing step height. // Each step is a box. With this object we can test if our character can climb up // stairs. The character controller has a step height limit. Increasing step heights // let us test if the step height limit works. float startHeight = 0; const float stepDepth = 1f; for (int i = 0; i < 10; i++) { float stepHeight = 0.1f + i * 0.05f; Vector3F position = new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth); AddBody(simulation, "Step" + i, new Pose(position), new BoxShape(2, stepHeight, stepDepth), MotionType.Static); startHeight += stepHeight; } // ----- V obstacle to test if we get stuck. AddBody(simulation, "V0", new Pose(new Vector3F(-5.5f, 0, 10), QuaternionF.CreateRotationZ(0.2f)), new BoxShape(1f, 2f, 2), MotionType.Static); AddBody(simulation, "V1", new Pose(new Vector3F(-4, 0, 10), QuaternionF.CreateRotationZ(-0.2f)), new BoxShape(1f, 2f, 2), MotionType.Static); // ----- Create a height field. // Terrain that is uneven is best modeled with a height field. Height fields are faster // than general triangle meshes. // The height direction is the y direction. // The height field lies in the x/z plane. var numberOfSamplesX = 20; var numberOfSamplesZ = 20; var samples = new float[numberOfSamplesX * numberOfSamplesZ]; // Create arbitrary height values. for (int z = 0; z < numberOfSamplesZ; z++) { for (int x = 0; x < numberOfSamplesX; x++) { if (x == 0 || z == 0 || x == 19 || z == 19) { // Set this boundary elements to a low height, so that the height field is connected // to the ground. samples[z * numberOfSamplesX + x] = -1; } else { // A sine/cosine function that creates some interesting waves. samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f); } } } var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ); AddBody(simulation, "HeightField", new Pose(new Vector3F(10, 0, 10)), heightField, MotionType.Static); // ----- Create rubble on the floor (small random objects on the floor). // Our character should be able to move over small bumps on the ground. for (int i = 0; i < 50; i++) { Vector3F position = new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20)); QuaternionF orientation = RandomHelper.Random.NextQuaternionF(); Vector3F size = RandomHelper.Random.NextVector3F(0.05f, 0.8f); AddBody(simulation, "Stone" + i, new Pose(position, orientation), new BoxShape(size), MotionType.Static); } // ----- Create some slopes to see how our character performs on/under sloped surfaces. // Here we can test how the character controller behaves if the head touches an inclined // ceiling. AddBody(simulation, "SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), MotionType.Static); AddBody(simulation, "SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), MotionType.Static); // Create slopes with increasing tilt angles. // The character controller has a slope limit. Only flat slopes should be climbable. // Movement between slopes should be smooth. Vector3F slopePosition = new Vector3F(-17, -0.25f, 6); BoxShape slopeShape = new BoxShape(8, 0.5f, 5); for (int i = 1; i < 8; i++) { Matrix33F oldRotation = Matrix33F.CreateRotationX((i - 1) * MathHelper.ToRadians(10)); Matrix33F rotation = Matrix33F.CreateRotationX(i * MathHelper.ToRadians(10)); slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2; AddBody(simulation, "Slope" + i, new Pose(slopePosition, rotation), slopeShape, MotionType.Static); } // Create slopes with decreasing tilt angles. slopePosition = new Vector3F(-8, -2, 5); slopeShape = new BoxShape(8f, 0.5f, 5); for (int i = 1; i < 8; i++) { Matrix33F oldRotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - (i - 1) * MathHelper.ToRadians(10)); Matrix33F rotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - i * MathHelper.ToRadians(10)); slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2; Vector3F position = slopePosition - rotation * new Vector3F(0, slopeShape.WidthY / 2, 0); AddBody(simulation, "Slope2" + i, new Pose(position, rotation), slopeShape, MotionType.Static); } // ----- Create a slope with a wall on one side. // This objects let's us test how the character controller behaves while falling and // sliding along a vertical wall. (Run up the slope and then jump down while moving into // the wall.) AddBody(simulation, "LongSlope", new Pose(new Vector3F(-24, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), MotionType.Static); AddBody(simulation, "LongSlopeWall", new Pose(new Vector3F(-26, 5, -10)), new BoxShape(0.5f, 10f, 25), MotionType.Static); // ----- Create a trigger object that represents a ladder. var ladder = AddBody(simulation, "Ladder", new Pose(new Vector3F(-25.7f, 5, 0)), new BoxShape(0.5f, 10f, 1), MotionType.Static); ladder.CollisionObject.Type = CollisionObjectType.Trigger; // ----- Create a mesh object to test walking on triangle meshes. // Normally, the mesh would be loaded from a file. Here, we make a composite shape and // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite // shape and use only the mesh. (We do this to test triangle meshes. Using the composite // shape instead of the triangle mesh would be a lot faster.) CompositeShape compositeShape = new CompositeShape(); compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity)); compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10)))); compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15)))); compositeShape.Children.Add(new GeometricObject(new BoxShape(4, 4, 3), new Pose(new Vector3F(15, 1.5f, 5)))); compositeShape.Children.Add(new GeometricObject(new BoxShape(4, 4, 3), new Pose(new Vector3F(15, 1.5f, 0)))); ITriangleMesh mesh = compositeShape.GetMesh(0.01f, 3); TriangleMeshShape meshShape = new TriangleMeshShape(mesh); // Collision detection speed for triangle meshes can be improved by using a spatial // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is // built automatically when needed and it stores triangle indices (therefore the generic // parameter of the AabbTree is int). meshShape.Partition = new AabbTree <int>() { // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up // building is slower but produces better trees. If the tree building takes too long, // we can lower the BottomUpBuildThreshold (default is 128). BottomUpBuildThreshold = 0, }; // Contact welding creates smoother contact normals - but it costs a bit of performance. meshShape.EnableContactWelding = true; AddBody(simulation, "Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, MotionType.Static); // ----- Create a seesaw. var seesawBase = AddBody(simulation, "SeesawBase", new Pose(new Vector3F(5, 0.5f, 0)), new BoxShape(0.2f, 1, 1), MotionType.Static); var seesaw = AddBody(simulation, "Seesaw", new Pose(new Vector3F(5, 1.05f, 0)), new BoxShape(5, 0.1f, 1), MotionType.Dynamic); // Attach the seesaw to the base using a hinge joint. simulation.Constraints.Add(new HingeJoint { BodyA = seesaw, BodyB = seesawBase, AnchorPoseALocal = new Pose(new Vector3F(0, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), AnchorPoseBLocal = new Pose(new Vector3F(0, 0.5f, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), CollisionEnabled = false, }); // ----- A platform that is moving up/down. _elevator = AddBody(simulation, "Elevator", new Pose(new Vector3F(5, -1f, 5)), new BoxShape(3, 1f, 3), MotionType.Kinematic); _elevator.LinearVelocity = new Vector3F(2, 2, 0); // ----- A platform that is moving sideways. _pusher = AddBody(simulation, "Pusher", new Pose(new Vector3F(15, 0.5f, 0)), new BoxShape(3, 1f, 3), MotionType.Kinematic); _pusher.LinearVelocity = new Vector3F(0, 0, 2); // ----- Create conveyor belt with two static boxes on the sides. AddBody(simulation, "ConveyorSide0", new Pose(new Vector3F(19, 0.25f, 0)), new BoxShape(0.8f, 0.5f, 8f), MotionType.Static); AddBody(simulation, "ConveyorSide1", new Pose(new Vector3F(21, 0.25f, 0)), new BoxShape(0.8f, 0.5f, 8f), MotionType.Static); // The conveyor belt is a simple box with a special material. var conveyorBelt = AddBody(simulation, "ConveyorBelt", new Pose(new Vector3F(20, 0.25f, 0)), new BoxShape(1f, 0.51f, 8f), MotionType.Static); UniformMaterial materialWithSurfaceMotion = new UniformMaterial("ConveyorBelt", true) // Important: The second parameter enables the surface { // motion. It has to be set to true in the constructor! SurfaceMotion = new Vector3F(0, 0, 1), // The surface motion relative to the object. }; conveyorBelt.Material = materialWithSurfaceMotion; // ----- Distribute a few dynamic spheres and boxes across the landscape. SphereShape sphereShape = new SphereShape(0.5f); for (int i = 0; i < 10; i++) { Vector3F position = RandomHelper.Random.NextVector3F(-15, 15); position.Y = 20; AddBody(simulation, "Sphere" + i, new Pose(position), sphereShape, MotionType.Dynamic); } BoxShape boxShape = new BoxShape(1, 1, 1); for (int i = 0; i < 10; i++) { Vector3F position = RandomHelper.Random.NextVector3F(-15, 15); position.Y = 20; AddBody(simulation, "Box" + i, new Pose(position), boxShape, MotionType.Dynamic); } }
/// <summary> /// Creates a <see cref="Ragdoll"/> for an Xbox LIVE Avatar. (Only available on Xbox 360.) /// </summary> /// <param name="skeleton">The skeleton of the Xbox LIVE Avatar.</param> /// <param name="simulation">The simulation.</param> /// <returns>The avatar ragdoll.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="skeleton"/> or <paramref name="simulation"/> is /// <see langword="null"/>. /// </exception> /// <remarks> /// This method is available only in the Xbox 360 build of the /// DigitalRune.Physics.Specialized.dll. /// </remarks> public static Ragdoll CreateAvatarRagdoll(Skeleton skeleton, Simulation simulation) { if (skeleton == null) { throw new ArgumentNullException("skeleton"); } if (simulation == null) { throw new ArgumentNullException("simulation"); } var ragdoll = new Ragdoll(); // The lists ragdoll.Bodies, ragdoll.BodyOffsets and _motors contain one entry per bone - even if there // is no RigidBody for this bone. - This wastes memory but simplifies the code. for (int i = 0; i < AvatarRenderer.BoneCount; i++) { ragdoll.Bodies.Add(null); ragdoll.BodyOffsets.Add(Pose.Identity); ragdoll.Joints.Add(null); ragdoll.Limits.Add(null); ragdoll.Motors.Add(null); } // ----- Create bodies. // We use the same mass for all bodies. This is not physically correct but it makes the // simulation more stable, for several reasons: // - It is better to avoid large mass differences. Therefore, all limbs have the same mass. // - Capsule shapes have a low inertia value about their height axis. This causes instability // and it is better to use larger inertia values. var massFrame = MassFrame.FromShapeAndMass(new SphereShape(0.2f), Vector3F.One, 4, 0.1f, 1); // Use standard material. var material = new UniformMaterial(); // Create rigid bodies for the important bones. The shapes have been manually adapted to // produce useful results for thin and overweight avatars. // Without offset, the bodies are centered at the joint. ragdoll.BodyOffsets stores an offset pose // for each body. Instead, we could use TransformedShape but we can easily handle that // ourselves. // The collar bones are special, they use dummy shapes and are only used to connect the // shoulder bones. ragdoll.Bodies[(int)AvatarBone.Root] = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.Root] = new Pose(new Vector3F(0, -0.08f, -0.01f), QuaternionF.CreateRotationX(-0.0f)); ragdoll.Bodies[(int)AvatarBone.BackLower] = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.BackLower] = new Pose(new Vector3F(0, 0.08f, -0.01f), QuaternionF.CreateRotationX(-0.0f)); ragdoll.Bodies[(int)AvatarBone.BackUpper] = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.BackUpper] = new Pose(new Vector3F(0, 0.08f, -0.01f), QuaternionF.CreateRotationX(-0.1f)); ragdoll.Bodies[(int)AvatarBone.Neck] = new RigidBody(new CapsuleShape(0.04f, 0.09f), massFrame, material); ragdoll.Bodies[(int)AvatarBone.Head] = new RigidBody(new SphereShape(0.15f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.Head] = new Pose(new Vector3F(0, 0.1f, 0)); ragdoll.Bodies[(int)AvatarBone.CollarLeft] = new RigidBody(Shape.Empty, massFrame, material); ragdoll.Bodies[(int)AvatarBone.CollarRight] = new RigidBody(Shape.Empty, massFrame, material); ragdoll.Bodies[(int)AvatarBone.ShoulderLeft] = new RigidBody(new CapsuleShape(0.04f, 0.25f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ShoulderLeft] = new Pose(new Vector3F(0.08f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.ShoulderRight] = new RigidBody(new CapsuleShape(0.04f, 0.25f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ShoulderRight] = new Pose(new Vector3F(-0.08f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.ElbowLeft] = new RigidBody(new CapsuleShape(0.04f, 0.21f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ElbowLeft] = new Pose(new Vector3F(0.06f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.ElbowRight] = new RigidBody(new CapsuleShape(0.04f, 0.21f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ElbowRight] = new Pose(new Vector3F(-0.06f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.WristLeft] = new RigidBody(new BoxShape(0.1f, 0.04f, 0.1f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.WristLeft] = new Pose(new Vector3F(0.06f, -0.02f, -0.01f), QuaternionF.CreateRotationZ(0.0f)); ragdoll.Bodies[(int)AvatarBone.WristRight] = new RigidBody(new BoxShape(0.1f, 0.04f, 0.1f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.WristRight] = new Pose(new Vector3F(-0.06f, -0.02f, -0.01f), QuaternionF.CreateRotationZ(0.0f)); ragdoll.Bodies[(int)AvatarBone.HipLeft] = new RigidBody(new CapsuleShape(0.06f, 0.34f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.HipLeft] = new Pose(new Vector3F(0, -0.14f, -0.02f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.HipRight] = new RigidBody(new CapsuleShape(0.06f, 0.34f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.HipRight] = new Pose(new Vector3F(0, -0.14f, -0.02f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.KneeLeft] = new RigidBody(new CapsuleShape(0.06f, 0.36f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.KneeLeft] = new Pose(new Vector3F(0, -0.18f, -0.04f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.KneeRight] = new RigidBody(new CapsuleShape(0.06f, 0.36f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.KneeRight] = new Pose(new Vector3F(0, -0.18f, -0.04f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.AnkleLeft] = new RigidBody(new BoxShape(0.1f, 0.06f, 0.22f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.AnkleLeft] = new Pose(new Vector3F(0, -0.07f, 0.05f), QuaternionF.CreateRotationZ(0)); ragdoll.Bodies[(int)AvatarBone.AnkleRight] = new RigidBody(new BoxShape(0.1f, 0.06f, 0.22f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.AnkleRight] = new Pose(new Vector3F(0, -0.07f, 0.05f), QuaternionF.CreateRotationZ(0)); // ----- Add joint constraints. const float jointErrorReduction = 0.2f; const float jointSoftness = 0.0001f; AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.BackLower, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.BackLower, AvatarBone.BackUpper, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.Neck, 0.6f, 0.000001f); AddJoint(ragdoll, skeleton, AvatarBone.Neck, AvatarBone.Head, 0.6f, 0.000001f); AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.CollarRight, AvatarBone.ShoulderRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ShoulderRight, AvatarBone.ElbowRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ElbowLeft, AvatarBone.WristLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ElbowRight, AvatarBone.WristRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.HipLeft, AvatarBone.KneeLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.HipRight, AvatarBone.KneeRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.KneeLeft, AvatarBone.AnkleLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.KneeRight, AvatarBone.AnkleRight, jointErrorReduction, jointSoftness); // ----- Add constraint limits. // We use TwistSwingLimits to define an allowed twist and swing cone for the joints. // Exceptions are the back and knees, where we use AngularLimits to create hinges. // (We could also create a hinge with a TwistSwingLimit where the twist axis is the hinge // axis and no swing is allowed - but AngularLimits create more stable hinges.) // Another exception are the collar bones joint. We use AngularLimits to disallow any // rotations. AddAngularLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.BackLower, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackLower).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackLower).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(-0.3f, 0, 0), new Vector3F(0.3f, 0, 0)); AddAngularLimit(ragdoll, skeleton, AvatarBone.BackLower, AvatarBone.BackUpper, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackUpper).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackUpper).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(-0.3f, 0, 0), new Vector3F(0.4f, 0, 0)); var rotationZ90Degrees = Matrix33F.CreateRotationZ(ConstantsF.PiOver2); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.Neck, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.3f, -0.3f), new Vector3F(+0.1f, +0.3f, +0.3f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Neck, AvatarBone.Head, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.6f, -0.6f), new Vector3F(+0.1f, +0.6f, +0.6f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarLeft, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarLeft).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarLeft).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0), new Vector3F(0)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarRight, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarRight).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarRight).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0), new Vector3F(0)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft, Matrix33F.Identity, Matrix33F.CreateRotationY(0.7f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.CollarRight, AvatarBone.ShoulderRight, Matrix33F.Identity, Matrix33F.CreateRotationY(-0.7f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft, Matrix33F.Identity, Matrix33F.CreateRotationY(1.2f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ShoulderRight, AvatarBone.ElbowRight, Matrix33F.Identity, Matrix33F.CreateRotationY(-1.2f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ElbowLeft, AvatarBone.WristLeft, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.7f, -0.7f, -0.7f), new Vector3F(+0.7f, +0.7f, +0.7f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ElbowRight, AvatarBone.WristRight, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.7f, -0.7f, -0.7f), new Vector3F(+0.7f, +0.7f, +0.7f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipLeft, rotationZ90Degrees, Matrix33F.CreateRotationX(-1.2f) * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 + 0.2f), new Vector3F(-0.1f, -1.5f, -0.7f), new Vector3F(+0.1f, +1.5f, +0.7f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipRight, rotationZ90Degrees, Matrix33F.CreateRotationX(-1.2f) * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 - 0.2f), new Vector3F(-0.1f, -1.5f, -0.7f), new Vector3F(+0.1f, +1.5f, +0.7f)); AddAngularLimit(ragdoll, skeleton, AvatarBone.HipLeft, AvatarBone.KneeLeft, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeLeft).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeLeft).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0, 0, 0), new Vector3F(2.2f, 0, 0)); AddAngularLimit(ragdoll, skeleton, AvatarBone.HipRight, AvatarBone.KneeRight, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeRight).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeRight).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0, 0, 0), new Vector3F(2.2f, 0, 0)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.KneeLeft, AvatarBone.AnkleLeft, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.7f, -0.3f), new Vector3F(+0.1f, +0.7f, +0.3f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.KneeRight, AvatarBone.AnkleRight, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.7f, -0.3f), new Vector3F(+0.1f, +0.7f, +0.3f)); // ----- Add motors // We use QuaternionMotors to create forces that rotate the bones into desired poses. // This can be used for damping, spring or animating the ragdoll. AddMotor(ragdoll, (AvatarBone)(-1), AvatarBone.Root); AddMotor(ragdoll, AvatarBone.Root, AvatarBone.BackLower); AddMotor(ragdoll, AvatarBone.BackLower, AvatarBone.BackUpper); AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.Neck); AddMotor(ragdoll, AvatarBone.Neck, AvatarBone.Head); AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.CollarLeft); AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.CollarRight); AddMotor(ragdoll, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft); AddMotor(ragdoll, AvatarBone.CollarRight, AvatarBone.ShoulderRight); AddMotor(ragdoll, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft); AddMotor(ragdoll, AvatarBone.ShoulderRight, AvatarBone.ElbowRight); AddMotor(ragdoll, AvatarBone.ElbowLeft, AvatarBone.WristLeft); AddMotor(ragdoll, AvatarBone.ElbowRight, AvatarBone.WristRight); AddMotor(ragdoll, AvatarBone.Root, AvatarBone.HipLeft); AddMotor(ragdoll, AvatarBone.Root, AvatarBone.HipRight); AddMotor(ragdoll, AvatarBone.HipLeft, AvatarBone.KneeLeft); AddMotor(ragdoll, AvatarBone.HipRight, AvatarBone.KneeRight); AddMotor(ragdoll, AvatarBone.KneeLeft, AvatarBone.AnkleLeft); AddMotor(ragdoll, AvatarBone.KneeRight, AvatarBone.AnkleRight); // ----- Set collision filters. // Collisions between connected bones have been disabled with Constraint.CollisionEnabled // = false in the joints. We need to disable a few other collisions. // Following bodies do not collide with anything. They are only used to connect other // bones. ragdoll.Bodies[(int)AvatarBone.Neck].CollisionObject.Enabled = false; ragdoll.Bodies[(int)AvatarBone.CollarLeft].CollisionObject.Enabled = false; ragdoll.Bodies[(int)AvatarBone.CollarRight].CollisionObject.Enabled = false; // We disable filters for following body pairs because they are usually penetrating each // other, which needs to be ignored. var filter = simulation.CollisionDomain.CollisionDetection.CollisionFilter as CollisionFilter; if (filter != null) { filter.Set(ragdoll.Bodies[(int)AvatarBone.BackUpper].CollisionObject, ragdoll.Bodies[(int)AvatarBone.ShoulderLeft].CollisionObject, false); filter.Set(ragdoll.Bodies[(int)AvatarBone.BackUpper].CollisionObject, ragdoll.Bodies[(int)AvatarBone.ShoulderRight].CollisionObject, false); } return(ragdoll); }
public void AddRagdoll(float scale, Vector3F ragdollPosition) { // Ragdolls are usually used in games to create realistic death animations of // characters. The character is usually rendered using a skinned triangle mesh. // But in the physics simulation the body parts of the character are represented // using simple shapes, such as spheres, capsules, boxes, or convex polyhedra, // which are connected with joints. // The physics simulations computes how these parts collide and fall. The positions // and orientations are then read back each frame to update the animation of the // triangle mesh. // In this example the ragdoll is built from spheres, capsules and boxes. The // rigid bodies are created in code. In practice, ragdolls should be built using // external tools, such as a 3D modeller or a game editor. #region ----- Create rigid bodies for the most relevant body parts ----- BoxShape pelvisShape = new BoxShape(0.3f * scale, 0.22f * scale, 0.20f * scale); MassFrame pelvisMass = MassFrame.FromShapeAndDensity(pelvisShape, Vector3F.One, Density, 0.01f, 3); RigidBody pelvis = new RigidBody(pelvisShape, pelvisMass, null) { Pose = new Pose(new Vector3F(0f, 0.01f * scale, -0.03f * scale) + ragdollPosition), }; Simulation.RigidBodies.Add(pelvis); BoxShape torsoShape = new BoxShape(0.35f * scale, 0.22f * scale, 0.44f * scale); MassFrame torsoMass = MassFrame.FromShapeAndDensity(torsoShape, Vector3F.One, Density, 0.01f, 3); RigidBody torso = new RigidBody(torsoShape, torsoMass, null) { Pose = new Pose(new Vector3F(0f, 0.01f * scale, -0.4f * scale) + ragdollPosition), }; Simulation.RigidBodies.Add(torso); SphereShape headShape = new SphereShape(0.13f * scale); MassFrame headMass = MassFrame.FromShapeAndDensity(headShape, Vector3F.One, Density, 0.01f, 3); RigidBody head = new RigidBody(headShape, headMass, null) { Pose = new Pose(new Vector3F(0f * scale, 0f, -0.776f * scale) + ragdollPosition), }; Simulation.RigidBodies.Add(head); CapsuleShape upperArmShape = new CapsuleShape(0.08f * scale, 0.3f * scale); MassFrame upperArmMass = MassFrame.FromShapeAndDensity(upperArmShape, Vector3F.One, Density, 0.01f, 3); RigidBody leftUpperArm = new RigidBody(upperArmShape, upperArmMass, null) { Pose = new Pose(new Vector3F(-0.32f * scale, 0.06f * scale, -0.53f * scale) + ragdollPosition, Matrix33F.CreateRotationZ(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(leftUpperArm); RigidBody rightUpperArm = new RigidBody(upperArmShape, upperArmMass, null) { Pose = new Pose(new Vector3F(0.32f * scale, 0.06f * scale, -0.53f * scale) + ragdollPosition, Matrix33F.CreateRotationZ(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(rightUpperArm); CapsuleShape lowerArmShape = new CapsuleShape(0.08f * scale, 0.4f * scale); MassFrame lowerArmMass = MassFrame.FromShapeAndDensity(lowerArmShape, Vector3F.One, Density, 0.01f, 3); RigidBody leftLowerArm = new RigidBody(lowerArmShape, lowerArmMass, null) { Pose = new Pose(new Vector3F(-0.62f * scale, 0.06f * scale, -0.53f * scale) + ragdollPosition, Matrix33F.CreateRotationZ(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(leftLowerArm); RigidBody rightLowerArm = new RigidBody(lowerArmShape, lowerArmMass, null) { Pose = new Pose(new Vector3F(0.62f * scale, 0.06f * scale, -0.53f * scale) + ragdollPosition, Matrix33F.CreateRotationZ(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(rightLowerArm); CapsuleShape upperLegShape = new CapsuleShape(0.09f * scale, 0.5f * scale); MassFrame upperLegMass = MassFrame.FromShapeAndDensity(upperLegShape, Vector3F.One, Density, 0.01f, 3); RigidBody leftUpperLeg = new RigidBody(upperLegShape, upperLegMass, null) { Pose = new Pose(new Vector3F(-0.10f * scale, 0.01f * scale, 0.233f * scale) + ragdollPosition, Matrix33F.CreateRotationX(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(leftUpperLeg); RigidBody rightUpperLeg = new RigidBody(upperLegShape, upperLegMass, null) { Pose = new Pose(new Vector3F(0.10f * scale, 0.01f * scale, 0.233f * scale) + ragdollPosition, Matrix33F.CreateRotationX(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(rightUpperLeg); CapsuleShape lowerLegShape = new CapsuleShape(0.08f * scale, 0.4f * scale); MassFrame lowerLegMass = MassFrame.FromShapeAndDensity(pelvisShape, Vector3F.One, Density, 0.01f, 3); RigidBody leftLowerLeg = new RigidBody(lowerLegShape, lowerLegMass, null) { Pose = new Pose(new Vector3F(-0.11f * scale, 0.01f * scale, 0.7f * scale) + ragdollPosition, Matrix33F.CreateRotationX(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(leftLowerLeg); RigidBody rightLowerLeg = new RigidBody(lowerLegShape, lowerLegMass, null) { Pose = new Pose(new Vector3F(0.11f * scale, 0.01f * scale, 0.7f * scale) + ragdollPosition, Matrix33F.CreateRotationX(ConstantsF.PiOver2)), }; Simulation.RigidBodies.Add(rightLowerLeg); BoxShape footShape = new BoxShape(0.12f * scale, 0.28f * scale, 0.07f * scale); MassFrame footMass = MassFrame.FromShapeAndDensity(footShape, Vector3F.One, Density, 0.01f, 3); RigidBody leftFoot = new RigidBody(footShape, footMass, null) { Pose = new Pose(new Vector3F(-0.11f * scale, -0.06f * scale, 0.94f * scale) + ragdollPosition), }; Simulation.RigidBodies.Add(leftFoot); RigidBody rightFoot = new RigidBody(footShape, footMass, null) { Pose = new Pose(new Vector3F(0.11f * scale, -0.06f * scale, 0.94f * scale) + ragdollPosition), }; Simulation.RigidBodies.Add(rightFoot); #endregion #region ----- Add joints between body parts ----- Vector3F pelvisJointPosition = new Vector3F(0f, 0.026f * scale, -0.115f * scale) + ragdollPosition; HingeJoint pelvisJoint = new HingeJoint { BodyA = torso, BodyB = pelvis, AnchorPoseALocal = new Pose(torso.Pose.ToLocalPosition(pelvisJointPosition)), AnchorPoseBLocal = new Pose(pelvis.Pose.ToLocalPosition(pelvisJointPosition)), Minimum = -0.5f, Maximum = 1.1f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(pelvisJoint); Vector3F neckJointPosition = new Vector3F(0f, 0.026f * scale, -0.690f * scale) + ragdollPosition; HingeJoint neckJoint = new HingeJoint { BodyA = head, BodyB = torso, AnchorPoseALocal = new Pose(head.Pose.ToLocalPosition(neckJointPosition)), AnchorPoseBLocal = new Pose(torso.Pose.ToLocalPosition(neckJointPosition)), Minimum = -1f, Maximum = 1f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(neckJoint); Vector3F leftShoulderJointPosition = new Vector3F(-0.193f * scale, 0.056f * scale, -0.528f * scale) + ragdollPosition; Vector3F leftShoulderJointAxis = new Vector3F(0, -1, -1).Normalized; Matrix33F leftShoulderJointOrientation = new Matrix33F(); leftShoulderJointOrientation.SetColumn(0, leftShoulderJointAxis); leftShoulderJointOrientation.SetColumn(1, leftShoulderJointAxis.Orthonormal1); leftShoulderJointOrientation.SetColumn(2, leftShoulderJointAxis.Orthonormal2); BallJoint leftShoulderJoint = new BallJoint { BodyA = leftUpperArm, BodyB = torso, AnchorPositionALocal = leftUpperArm.Pose.ToLocalPosition(leftShoulderJointPosition), AnchorPositionBLocal = torso.Pose.ToLocalPosition(leftShoulderJointPosition), CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(leftShoulderJoint); Vector3F rightShoulderJointPosition = new Vector3F(0.193f * scale, 0.056f * scale, -0.528f * scale) + ragdollPosition; Vector3F rightShoulderJointAxis = new Vector3F(0, 1, 1).Normalized; Matrix33F rightShoulderJointOrientation = new Matrix33F(); rightShoulderJointOrientation.SetColumn(0, rightShoulderJointAxis); rightShoulderJointOrientation.SetColumn(1, rightShoulderJointAxis.Orthonormal1); rightShoulderJointOrientation.SetColumn(2, rightShoulderJointAxis.Orthonormal2); BallJoint rightShoulderJoint = new BallJoint { BodyA = rightUpperArm, BodyB = torso, AnchorPositionALocal = rightUpperArm.Pose.ToLocalPosition(rightShoulderJointPosition), AnchorPositionBLocal = torso.Pose.ToLocalPosition(rightShoulderJointPosition), CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(rightShoulderJoint); Vector3F leftElbowJointPosition = new Vector3F(-0.451f * scale, 0.071f * scale, -0.538f * scale) + ragdollPosition; Matrix33F elbowAxisOrientation = new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0); HingeJoint leftElbowJoint = new HingeJoint { BodyA = leftLowerArm, BodyB = leftUpperArm, AnchorPoseALocal = new Pose(leftLowerArm.Pose.ToLocalPosition(leftElbowJointPosition), leftLowerArm.Pose.Orientation.Inverse * elbowAxisOrientation), AnchorPoseBLocal = new Pose(leftUpperArm.Pose.ToLocalPosition(leftElbowJointPosition), leftUpperArm.Pose.Orientation.Inverse * elbowAxisOrientation), Minimum = -2, Maximum = 0, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(leftElbowJoint); Vector3F rightElbowJointPosition = new Vector3F(0.451f * scale, 0.071f * scale, -0.538f * scale) + ragdollPosition; HingeJoint rightElbowJoint = new HingeJoint { BodyA = rightLowerArm, BodyB = rightUpperArm, AnchorPoseALocal = new Pose(rightLowerArm.Pose.ToLocalPosition(rightElbowJointPosition), rightLowerArm.Pose.Orientation.Inverse * elbowAxisOrientation), AnchorPoseBLocal = new Pose(rightUpperArm.Pose.ToLocalPosition(rightElbowJointPosition), rightUpperArm.Pose.Orientation.Inverse * elbowAxisOrientation), Minimum = 0, Maximum = 2, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(rightElbowJoint); Vector3F leftHipJointPosition = new Vector3F(-0.107f * scale, 0.049f * scale, 0.026f * scale) + ragdollPosition; HingeJoint leftHipJoint = new HingeJoint { BodyA = pelvis, BodyB = leftUpperLeg, AnchorPoseALocal = new Pose(pelvis.Pose.ToLocalPosition(leftHipJointPosition)), AnchorPoseBLocal = new Pose(leftUpperLeg.Pose.ToLocalPosition(leftHipJointPosition), leftUpperLeg.Pose.Orientation.Inverse), Minimum = -0.1f, Maximum = 1.2f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(leftHipJoint); Vector3F rightHipJointPosition = new Vector3F(0.107f * scale, 0.049f * scale, 0.026f * scale) + ragdollPosition; HingeJoint rightHipJoint = new HingeJoint { BodyA = pelvis, BodyB = rightUpperLeg, AnchorPoseALocal = new Pose(pelvis.Pose.ToLocalPosition(rightHipJointPosition)), AnchorPoseBLocal = new Pose(rightUpperLeg.Pose.ToLocalPosition(rightHipJointPosition), rightUpperLeg.Pose.Orientation.Inverse), Minimum = -0.1f, Maximum = 1.2f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(rightHipJoint); Vector3F leftKneeJointPosition = new Vector3F(-0.118f * scale, -0.012f * scale, 0.439f * scale) + ragdollPosition; HingeJoint leftKneeJoint = new HingeJoint { BodyA = leftLowerLeg, BodyB = leftUpperLeg, AnchorPoseALocal = new Pose(leftLowerLeg.Pose.ToLocalPosition(leftKneeJointPosition)), AnchorPoseBLocal = new Pose(leftUpperLeg.Pose.ToLocalPosition(leftKneeJointPosition)), Minimum = 0, Maximum = 1.7f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(leftKneeJoint); Vector3F rightKneeJointPosition = new Vector3F(0.118f * scale, -0.012f * scale, 0.439f * scale) + ragdollPosition; HingeJoint rightKneeJoint = new HingeJoint { BodyA = rightLowerLeg, BodyB = rightUpperLeg, AnchorPoseALocal = new Pose(rightLowerLeg.Pose.ToLocalPosition(rightKneeJointPosition)), AnchorPoseBLocal = new Pose(rightUpperLeg.Pose.ToLocalPosition(rightKneeJointPosition)), Minimum = 0, Maximum = 1.7f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(rightKneeJoint); Vector3F leftAnkleJointPosition = new Vector3F(-0.118f * scale, -0.016f * scale, 0.861f * scale) + ragdollPosition; HingeJoint leftAnkleJoint = new HingeJoint { BodyA = leftFoot, BodyB = leftLowerLeg, AnchorPoseALocal = new Pose(leftFoot.Pose.ToLocalPosition(leftAnkleJointPosition)), AnchorPoseBLocal = new Pose(leftLowerLeg.Pose.ToLocalPosition(leftAnkleJointPosition), leftLowerLeg.Pose.Orientation.Inverse), Minimum = -0.4f, Maximum = 0.9f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(leftAnkleJoint); Vector3F rightAnkleJointPosition = new Vector3F(0.118f * scale, -0.016f * scale, 0.861f * scale) + ragdollPosition; HingeJoint rightAnkleJoint = new HingeJoint { BodyA = rightFoot, BodyB = rightLowerLeg, AnchorPoseALocal = new Pose(rightFoot.Pose.ToLocalPosition(rightAnkleJointPosition)), AnchorPoseBLocal = new Pose(rightLowerLeg.Pose.ToLocalPosition(rightAnkleJointPosition), rightLowerLeg.Pose.Orientation.Inverse), Minimum = -0.4f, Maximum = 0.9f, CollisionEnabled = false, ErrorReduction = JointErrorReduction, Softness = JointSoftness, MaxForce = JointMaxForce, }; Simulation.Constraints.Add(rightAnkleJoint); #endregion #region ----- Add damping to improve stability ----- if (DampingEnabled) { // Damping removes jiggling and improves stability. AddDamping(pelvis, torso); AddDamping(torso, head); AddDamping(torso, leftUpperArm); AddDamping(leftUpperArm, leftLowerArm); AddDamping(torso, rightUpperArm); AddDamping(rightUpperArm, rightLowerArm); AddDamping(pelvis, leftUpperLeg); AddDamping(pelvis, rightUpperLeg); AddDamping(leftUpperLeg, leftLowerLeg); AddDamping(rightUpperLeg, rightLowerLeg); AddDamping(leftLowerLeg, leftFoot); AddDamping(rightLowerLeg, rightFoot); } #endregion }
/// <summary> /// Initializes the ragdoll for the given skeleton pose. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <param name="ragdoll">The ragdoll.</param> /// <param name="simulation">The simulation in which the ragdoll will be used.</param> /// <param name="scale">A scaling factor to scale the size of the ragdoll.</param> public static void Create(SkeletonPose skeletonPose, Ragdoll ragdoll, Simulation simulation, float scale) { var skeleton = skeletonPose.Skeleton; const float totalMass = 80; // The total mass of the ragdoll. const int numberOfBodies = 17; // Get distance from foot to head as a measure for the size of the ragdoll. int head = skeleton.GetIndex("Head"); int footLeft = skeleton.GetIndex("L_Ankle1"); var headPosition = skeletonPose.GetBonePoseAbsolute(head).Translation; var footPosition = skeletonPose.GetBonePoseAbsolute(footLeft).Translation; var headToFootDistance = (headPosition - footPosition).Length; // We use the same mass properties for all bodies. This is not realistic but more stable // because large mass differences or thin bodies (arms!) are less stable. // We use the mass properties of sphere proportional to the size of the model. var massFrame = MassFrame.FromShapeAndMass(new SphereShape(headToFootDistance / 8), Vector3F.One, totalMass / numberOfBodies, 0.1f, 1); var material = new UniformMaterial(); #region ----- Add Bodies and Body Offsets ----- var numberOfBones = skeleton.NumberOfBones; ragdoll.Bodies.AddRange(Enumerable.Repeat <RigidBody>(null, numberOfBones)); ragdoll.BodyOffsets.AddRange(Enumerable.Repeat(Pose.Identity, numberOfBones)); var pelvis = skeleton.GetIndex("Pelvis"); ragdoll.Bodies[pelvis] = new RigidBody(new BoxShape(0.3f * scale, 0.4f * scale, 0.55f * scale), massFrame, material); ragdoll.BodyOffsets[pelvis] = new Pose(new Vector3F(0, 0, 0)); var backLower = skeleton.GetIndex("Spine"); ragdoll.Bodies[backLower] = new RigidBody(new BoxShape(0.36f * scale, 0.4f * scale, 0.55f * scale), massFrame, material); ragdoll.BodyOffsets[backLower] = new Pose(new Vector3F(0.18f * scale, 0, 0)); var backUpper = skeleton.GetIndex("Spine2"); ragdoll.Bodies[backUpper] = new RigidBody(new BoxShape(0.5f * scale, 0.4f * scale, 0.65f * scale), massFrame, material); ragdoll.BodyOffsets[backUpper] = new Pose(new Vector3F(0.25f * scale, 0, 0)); var neck = skeleton.GetIndex("Neck"); ragdoll.Bodies[neck] = new RigidBody(new CapsuleShape(0.12f * scale, 0.3f * scale), massFrame, material); ragdoll.BodyOffsets[neck] = new Pose(new Vector3F(0.15f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[neck].CollisionObject.Enabled = false; ragdoll.Bodies[head] = new RigidBody(new SphereShape(0.2f * scale), massFrame, material); ragdoll.BodyOffsets[head] = new Pose(new Vector3F(0.15f * scale, 0.02f * scale, 0)); var armUpperLeft = skeleton.GetIndex("L_UpperArm"); ragdoll.Bodies[armUpperLeft] = new RigidBody(new CapsuleShape(0.12f * scale, 0.6f * scale), massFrame, material); ragdoll.BodyOffsets[armUpperLeft] = new Pose(new Vector3F(0.2f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var armLowerLeft = skeleton.GetIndex("L_Forearm"); ragdoll.Bodies[armLowerLeft] = new RigidBody(new CapsuleShape(0.08f * scale, 0.5f * scale), massFrame, material); ragdoll.BodyOffsets[armLowerLeft] = new Pose(new Vector3F(0.2f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var handLeft = skeleton.GetIndex("L_Hand"); ragdoll.Bodies[handLeft] = new RigidBody(new BoxShape(0.2f * scale, 0.06f * scale, 0.15f * scale), massFrame, material); ragdoll.BodyOffsets[handLeft] = new Pose(new Vector3F(0.1f * scale, 0, 0)); var armUpperRight = skeleton.GetIndex("R_UpperArm"); ragdoll.Bodies[armUpperRight] = new RigidBody(new CapsuleShape(0.12f * scale, 0.6f * scale), massFrame, material); ragdoll.BodyOffsets[armUpperRight] = new Pose(new Vector3F(0.2f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var armLowerRight = skeleton.GetIndex("R_Forearm"); ragdoll.Bodies[armLowerRight] = new RigidBody(new CapsuleShape(0.08f * scale, 0.5f * scale), massFrame, material); ragdoll.BodyOffsets[armLowerRight] = new Pose(new Vector3F(0.2f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var handRight = skeleton.GetIndex("R_Hand"); ragdoll.Bodies[handRight] = new RigidBody(new BoxShape(0.2f * scale, 0.06f * scale, 0.15f * scale), massFrame, material); ragdoll.BodyOffsets[handRight] = new Pose(new Vector3F(0.1f * scale, 0, 0)); var legUpperLeft = skeleton.GetIndex("L_Thigh1"); ragdoll.Bodies[legUpperLeft] = new RigidBody(new CapsuleShape(0.16f * scale, 0.8f * scale), massFrame, material); ragdoll.BodyOffsets[legUpperLeft] = new Pose(new Vector3F(0.4f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var legLowerLeft = skeleton.GetIndex("L_Knee2"); ragdoll.Bodies[legLowerLeft] = new RigidBody(new CapsuleShape(0.12f * scale, 0.65f * scale), massFrame, material); ragdoll.BodyOffsets[legLowerLeft] = new Pose(new Vector3F(0.32f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); //var footLeft = skeleton.GetIndex("L_Ankle1"); ragdoll.Bodies[footLeft] = new RigidBody(new BoxShape(0.20f * scale, 0.5f * scale, 0.3f * scale), massFrame, material); ragdoll.BodyOffsets[footLeft] = new Pose(new Vector3F(0.16f * scale, 0.15f * scale, 0)); var legUpperRight = skeleton.GetIndex("R_Thigh"); ragdoll.Bodies[legUpperRight] = new RigidBody(new CapsuleShape(0.16f * scale, 0.8f * scale), massFrame, material); ragdoll.BodyOffsets[legUpperRight] = new Pose(new Vector3F(0.4f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var legLowerRight = skeleton.GetIndex("R_Knee"); ragdoll.Bodies[legLowerRight] = new RigidBody(new CapsuleShape(0.12f * scale, 0.65f * scale), massFrame, material); ragdoll.BodyOffsets[legLowerRight] = new Pose(new Vector3F(0.32f * scale, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var footRight = skeleton.GetIndex("R_Ankle"); ragdoll.Bodies[footRight] = new RigidBody(new BoxShape(0.20f * scale, 0.5f * scale, 0.3f * scale), massFrame, material); ragdoll.BodyOffsets[footRight] = new Pose(new Vector3F(0.16f * scale, 0.15f * scale, 0)); #endregion #region ----- Set Collision Filters ----- // Collisions between connected bodies will be disabled in AddJoint(). (A BallJoint // has a property CollisionEnabled which decides whether connected bodies can // collide.) // But we need to disable some more collision between bodies that are not directly // connected but still too close to each other. var filter = (ICollisionFilter)simulation.CollisionDomain.CollisionDetection.CollisionFilter; filter.Set(ragdoll.Bodies[backUpper].CollisionObject, ragdoll.Bodies[head].CollisionObject, false); filter.Set(ragdoll.Bodies[armUpperRight].CollisionObject, ragdoll.Bodies[backLower].CollisionObject, false); filter.Set(ragdoll.Bodies[armUpperLeft].CollisionObject, ragdoll.Bodies[backLower].CollisionObject, false); filter.Set(ragdoll.Bodies[legUpperLeft].CollisionObject, ragdoll.Bodies[legUpperRight].CollisionObject, false); #endregion #region ----- Add Joints ----- AddJoint(skeletonPose, ragdoll, pelvis, backLower); AddJoint(skeletonPose, ragdoll, backLower, backUpper); AddJoint(skeletonPose, ragdoll, backUpper, neck); AddJoint(skeletonPose, ragdoll, neck, head); AddJoint(skeletonPose, ragdoll, backUpper, armUpperLeft); AddJoint(skeletonPose, ragdoll, armUpperLeft, armLowerLeft); AddJoint(skeletonPose, ragdoll, armLowerLeft, handLeft); AddJoint(skeletonPose, ragdoll, backUpper, armUpperRight); AddJoint(skeletonPose, ragdoll, armUpperRight, armLowerRight); AddJoint(skeletonPose, ragdoll, armLowerRight, handRight); AddJoint(skeletonPose, ragdoll, pelvis, legUpperLeft); AddJoint(skeletonPose, ragdoll, legUpperLeft, legLowerLeft); AddJoint(skeletonPose, ragdoll, legLowerLeft, footLeft); AddJoint(skeletonPose, ragdoll, pelvis, legUpperRight); AddJoint(skeletonPose, ragdoll, legUpperRight, legLowerRight); AddJoint(skeletonPose, ragdoll, legLowerRight, footRight); #endregion #region ----- Add Limits ----- // Choosing limits is difficult. // We create hinge limits with AngularLimits in the back and in the knee. // For all other joints we use TwistSwingLimits with symmetric cones. AddAngularLimit(skeletonPose, ragdoll, pelvis, backLower, new Vector3F(0, 0, -0.3f), new Vector3F(0, 0, 0.3f)); AddAngularLimit(skeletonPose, ragdoll, backLower, backUpper, new Vector3F(0, 0, -0.3f), new Vector3F(0, 0, 0.4f)); AddAngularLimit(skeletonPose, ragdoll, backUpper, neck, new Vector3F(0, 0, -0.3f), new Vector3F(0, 0, 0.3f)); AddTwistSwingLimit(ragdoll, neck, head, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.1f, -0.5f, -0.7f), new Vector3F(0.1f, 0.5f, 0.7f)); var parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(backUpper).Inverse; var childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(armUpperLeft).Inverse; var bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, backUpper, armUpperLeft, bindPoseRelative.Orientation * Matrix33F.CreateRotationY(-0.5f) * Matrix33F.CreateRotationZ(-0.5f), Matrix33F.Identity, new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(0.7f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armUpperLeft, armLowerLeft, Matrix33F.CreateRotationZ(-1.2f), Matrix33F.Identity, new Vector3F(-0.3f, -1.2f, -1.2f), new Vector3F(0.3f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armLowerLeft, handLeft, Matrix33F.Identity, Matrix33F.CreateRotationX(+ConstantsF.PiOver2), new Vector3F(-0.3f, -0.7f, -0.7f), new Vector3F(0.3f, 0.7f, 0.7f)); parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(backUpper).Inverse; childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(armUpperRight).Inverse; bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, backUpper, armUpperRight, bindPoseRelative.Orientation * Matrix33F.CreateRotationY(0.5f) * Matrix33F.CreateRotationZ(-0.5f), Matrix33F.Identity, new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(0.7f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armUpperRight, armLowerRight, Matrix33F.CreateRotationZ(-1.2f), Matrix33F.Identity, new Vector3F(-0.3f, -1.2f, -1.2f), new Vector3F(0.3f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armLowerRight, handRight, Matrix33F.Identity, Matrix33F.CreateRotationX(-ConstantsF.PiOver2), new Vector3F(-0.3f, -0.7f, -0.7f), new Vector3F(0.3f, 0.7f, 0.7f)); parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(pelvis).Inverse; childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(legUpperLeft).Inverse; bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, pelvis, legUpperLeft, bindPoseRelative.Orientation * Matrix33F.CreateRotationZ(1.2f), Matrix33F.Identity, new Vector3F(-0.1f, -0.7f, -1.5f), new Vector3F(+0.1f, +0.7f, +1.5f)); AddAngularLimit(skeletonPose, ragdoll, legUpperLeft, legLowerLeft, new Vector3F(0, 0, -2.2f), new Vector3F(0, 0, 0.0f)); AddTwistSwingLimit(ragdoll, legLowerLeft, footLeft, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.1f, -0.3f, -0.7f), new Vector3F(0.1f, 0.3f, 0.7f)); parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(pelvis).Inverse; childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(legUpperRight).Inverse; bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, pelvis, legUpperRight, bindPoseRelative.Orientation * Matrix33F.CreateRotationZ(1.2f), Matrix33F.Identity, new Vector3F(-0.1f, -0.7f, -1.5f), new Vector3F(+0.1f, +0.7f, +1.5f)); AddAngularLimit(skeletonPose, ragdoll, legUpperRight, legLowerRight, new Vector3F(0, 0, -2.2f), new Vector3F(0, 0, 0.0f)); AddTwistSwingLimit(ragdoll, legLowerRight, footRight, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.1f, -0.3f, -0.7f), new Vector3F(0.1f, 0.3f, 0.7f)); #endregion #region ----- Add Motors ----- ragdoll.Motors.AddRange(Enumerable.Repeat <RagdollMotor>(null, numberOfBones)); ragdoll.Motors[pelvis] = new RagdollMotor(pelvis, -1); ragdoll.Motors[backLower] = new RagdollMotor(backLower, pelvis); ragdoll.Motors[backUpper] = new RagdollMotor(backUpper, backLower); ragdoll.Motors[neck] = new RagdollMotor(neck, backUpper); ragdoll.Motors[head] = new RagdollMotor(head, neck); ragdoll.Motors[armUpperLeft] = new RagdollMotor(armUpperLeft, backUpper); ragdoll.Motors[armLowerLeft] = new RagdollMotor(armLowerLeft, armUpperLeft); ragdoll.Motors[handLeft] = new RagdollMotor(handLeft, armLowerLeft); ragdoll.Motors[armUpperRight] = new RagdollMotor(armUpperRight, backUpper); ragdoll.Motors[armLowerRight] = new RagdollMotor(armLowerRight, armUpperRight); ragdoll.Motors[handRight] = new RagdollMotor(handRight, armLowerRight); ragdoll.Motors[legUpperLeft] = new RagdollMotor(legUpperLeft, pelvis); ragdoll.Motors[legLowerLeft] = new RagdollMotor(legLowerLeft, legUpperLeft); ragdoll.Motors[footLeft] = new RagdollMotor(footLeft, legLowerLeft); ragdoll.Motors[legUpperRight] = new RagdollMotor(legUpperRight, pelvis); ragdoll.Motors[legLowerRight] = new RagdollMotor(legLowerRight, legUpperRight); ragdoll.Motors[footRight] = new RagdollMotor(footRight, legLowerRight); #endregion }
// Add a 3D coordinate cross. private void CreateGizmo(SpriteFont spriteFont) { var gizmoNode = new SceneNode { Name = "Gizmo", Children = new SceneNodeCollection(), PoseLocal = new Pose(new Vector3F(3, 2, 0)), ScaleLocal = new Vector3F(0.5f) }; // Red arrow var arrow = new PathFigure2F(); arrow.Segments.Add(new LineSegment2F { Point1 = new Vector2F(0, 0), Point2 = new Vector2F(1, 0) }); arrow.Segments.Add(new LineSegment2F { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(0.9f, 0.02f) }); arrow.Segments.Add(new LineSegment2F { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(0.9f, -0.02f) }); var figureNode = new FigureNode(arrow) { Name = "Gizmo X", StrokeThickness = 2, StrokeColor = new Vector3F(1, 0, 0), PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Green arrow var transformedArrow = new TransformedFigure(arrow) { Pose = new Pose(Matrix33F.CreateRotationZ(MathHelper.ToRadians(90))) }; figureNode = new FigureNode(transformedArrow) { Name = "Gizmo Y", StrokeThickness = 2, StrokeColor = new Vector3F(0, 1, 0), PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Blue arrow transformedArrow = new TransformedFigure(arrow) { Pose = new Pose(Matrix33F.CreateRotationY(MathHelper.ToRadians(-90))) }; figureNode = new FigureNode(transformedArrow) { Name = "Gizmo Z", StrokeThickness = 2, StrokeColor = new Vector3F(0, 0, 1), PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Red arc var arc = new PathFigure2F(); arc.Segments.Add( new StrokedSegment2F( new LineSegment2F { Point1 = new Vector2F(0, 0), Point2 = new Vector2F(1, 0), }, false)); arc.Segments.Add( new ArcSegment2F { Point1 = new Vector2F(1, 0), Point2 = new Vector2F(0, 1), Radius = new Vector2F(1, 1) }); arc.Segments.Add( new StrokedSegment2F( new LineSegment2F { Point1 = new Vector2F(0, 1), Point2 = new Vector2F(0, 0), }, false)); var transformedArc = new TransformedFigure(arc) { Scale = new Vector3F(0.333f), Pose = new Pose(Matrix33F.CreateRotationY(MathHelper.ToRadians(-90))) }; figureNode = new FigureNode(transformedArc) { Name = "Gizmo YZ", StrokeThickness = 2, StrokeColor = new Vector3F(1, 0, 0), FillColor = new Vector3F(1, 0, 0), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Green arc transformedArc = new TransformedFigure(arc) { Scale = new Vector3F(0.333f), Pose = new Pose(Matrix33F.CreateRotationX(MathHelper.ToRadians(90))) }; figureNode = new FigureNode(transformedArc) { Name = "Gizmo XZ", StrokeThickness = 2, StrokeColor = new Vector3F(0, 1, 0), FillColor = new Vector3F(0, 1, 0), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Blue arc transformedArc = new TransformedFigure(arc) { Scale = new Vector3F(0.333f), }; figureNode = new FigureNode(transformedArc) { Name = "Gizmo XY", StrokeThickness = 2, StrokeColor = new Vector3F(0, 0, 1), FillColor = new Vector3F(0, 0, 1), FillAlpha = 0.5f, PoseLocal = new Pose(new Vector3F(0, 0, 0)) }; gizmoNode.Children.Add(figureNode); // Labels "X", "Y", "Z" var spriteNode = new SpriteNode(new TextSprite("X", spriteFont)) { Color = new Vector3F(1, 0, 0), Origin = new Vector2F(0, 1), PoseLocal = new Pose(new Vector3F(1, 0, 0)) }; gizmoNode.Children.Add(spriteNode); spriteNode = new SpriteNode(new TextSprite("Y", spriteFont)) { Color = new Vector3F(0, 1, 0), Origin = new Vector2F(0, 1), PoseLocal = new Pose(new Vector3F(0, 1, 0)) }; gizmoNode.Children.Add(spriteNode); spriteNode = new SpriteNode(new TextSprite("Z", spriteFont)) { Color = new Vector3F(0, 0, 1), Origin = new Vector2F(0, 1), PoseLocal = new Pose(new Vector3F(0, 0, 1)) }; gizmoNode.Children.Add(spriteNode); _scene.Children.Add(gizmoNode); }
/// <summary> /// Initializes the physics simulation. /// </summary> private void InitializePhysics() { // Add a gravity force. _gravity = new Gravity { Acceleration = new Vector3F(0, -GravityAcceleration, 0) }; Simulation.ForceEffects.Add(_gravity); // Add a damping force. Simulation.ForceEffects.Add(new Damping()); // Add a few spheres. Simulation.RigidBodies.Add(new RigidBody(new SphereShape(0.3f)) { Pose = new Pose(new Vector3F(0, 1, 0)), }); Simulation.RigidBodies.Add(new RigidBody(new SphereShape(0.2f)) { Pose = new Pose(new Vector3F(1, 1, 0)), }); Simulation.RigidBodies.Add(new RigidBody(new SphereShape(0.4f)) { Pose = new Pose(new Vector3F(0, 1, 2)), }); // Add ragdoll. AddRagdoll(1, new Vector3F(0, 2, 0)); // The Simulation performs 2 sub-time-steps per frame because we have set // the FixedTimeStep of the simulation to 1/60 s and the TargetElapsedTime of the game // is 1/30 s (30 Hz). In the event SubTimeStepFinished, we call our method // HandleBreakableJoints() to check the forces in the joints and disable constraints where // the force is too large. // Instead, we could also call HandleBreakableJoints() in the Update() method of the game // but then it is only called with the 30 Hz of the game. It is more accurate to call the // method at the end of each simulation sub-time-step (60 Hz). Simulation.SubTimeStepFinished += (s, e) => HandleBreakableJoints(); // Add 6 planes that keep the bodies inside the visible area. The exact positions and angles // have been determined by experimentation. var groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0)) { Name = "GroundPlane", MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(groundPlane); var nearPlane = new RigidBody(new PlaneShape(-Vector3F.UnitY, -8)) { Name = "NearPlane", MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(nearPlane); var leftPlane = new RigidBody(new PlaneShape(Matrix33F.CreateRotationZ(MathHelper.ToRadians(-22f)) * Vector3F.UnitX, -4.8f)) { Name = "LeftPlane", MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(leftPlane); var rightPlane = new RigidBody(new PlaneShape(Matrix33F.CreateRotationZ(MathHelper.ToRadians(22f)) * -Vector3F.UnitX, -4.8f)) { Name = "RightPlane", MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(rightPlane); var topPlane = new RigidBody(new PlaneShape(Matrix33F.CreateRotationX(MathHelper.ToRadians(14f)) * Vector3F.UnitZ, -3f)) { Name = "TopPlane", MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(topPlane); var bottomPlane = new RigidBody(new PlaneShape(Matrix33F.CreateRotationX(MathHelper.ToRadians(-14f)) * -Vector3F.UnitZ, -3f)) { Name = "BottomPlane", MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(bottomPlane); }
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(); }