private void SynchronizeShape() { Debug.Assert(ParticleSystem != null); // Note: Scene does not allow TransformedShapes with infinite shapes. // --> Handle infinite shapes explicitly. (The code below only checks for InfiniteShape. // LineShape or PlaneShape will raise an exception in Scene!) if (ParticleSystem.ReferenceFrame == ParticleReferenceFrame.Local || ParticleSystem.Shape is InfiniteShape) { Shape = ParticleSystem.Shape; } else { // Particles are simulated in world space. ParticleSystem.Shape must not be scale by // SceneNode.ScaleWorld. --> Add a TransformedShape that negates the scale. var transformedShape = Shape as TransformedShape; if (transformedShape == null) { transformedShape = new TransformedShape(new GeometricObject()); Shape = transformedShape; } var geometricObject = transformedShape.Child as GeometricObject; if (geometricObject == null) { geometricObject = new GeometricObject(); transformedShape.Child = geometricObject; } geometricObject.Shape = ParticleSystem.Shape; geometricObject.Scale = Vector3F.One / ScaleWorld; } }
public void GetAxisAlignedBoundingBox() { Assert.AreEqual(new Aabb(new Vector3(0, -100, 0), new Vector3(1000, 0, 1000)), new HeightField().GetAabb(Pose.Identity)); Assert.AreEqual(new Aabb(new Vector3(1000, -101, 2000), new Vector3(1100, 5, 2200)), _field.GetAabb(Pose.Identity)); Assert.AreEqual(new Aabb(new Vector3(0, -1, 0), new Vector3(10, 5, 20)), new HeightField(0, 0, 10, 20, _samples, 3, 8) { Depth = 0 }.GetAabb(Pose.Identity)); // Now with pose. Quaternion rotation = Quaternion.CreateRotationX(0.2f); Pose pose = new Pose(new Vector3(1, 1, 1), rotation); _field.Depth = 0; var box = new TransformedShape( new GeometricObject(new BoxShape(100, 6, 200), new Pose(new Vector3(1050, 2, 2100)))); Assert.IsTrue(Vector3.AreNumericallyEqual(box.GetAabb(pose).Minimum, _field.GetAabb(pose).Minimum)); _field.Depth = 4; box = new TransformedShape( new GeometricObject(new BoxShape(100, 10, 200), new Pose(new Vector3(1000, 0, 2000)))); Assert.IsTrue(Vector3.AreNumericallyEqual(box.GetAabb(pose).Minimum + rotation.Rotate(new Vector3(50, 0, 100)), _field.GetAabb(pose).Minimum)); }
private static CompoundShape create_shapes(RepeatedField <Collider> colliders) { if (colliders == null || colliders.Count == 0) { throw new Exception("Colliders is null or count is zero"); } var shape_buffer = new List <TransformedShape>(); foreach (var collider in colliders) { Shape shape = null; Vector3 center; Quaternion rotation; switch (collider.ShapeCase) { case Collider.ShapeOneofCase.None: throw new Exception("Collider without any shape"); case Collider.ShapeOneofCase.Box: var box = collider.Box; shape = new Jitter.Collision.Shapes.BoxShape(box.Length, box.Height, box.Width); center = box.Center; rotation = box.Rotation; break; case Collider.ShapeOneofCase.Sphere: var sphere = collider.Sphere; shape = new Jitter.Collision.Shapes.SphereShape(sphere.Radius); center = sphere.Center; rotation = sphere.Rotation; break; case Collider.ShapeOneofCase.Capsule: var capsule = collider.Capsule; shape = new Jitter.Collision.Shapes.CapsuleShape(capsule.Height, capsule.Radius); center = capsule.Center; rotation = capsule.Rotation; break; default: Debug.Assert(false, "Unhandled enum value " + collider.ShapeCase); throw new Exception(); } var center_j = to_j(center); var rotation_j = to_j(rotation); var transformed_shape = new TransformedShape(shape, JMatrix.Identity, center_j); shape_buffer.Add(transformed_shape); if (collider.Children != null && collider.Children.Count > 0) { create_shapes(collider.Children); } } return(new CompoundShape(shape_buffer)); }
public void TransformedShapeNonuniformScaleWithRotationNotSupported() { var s = new TransformedShape(new GeometricObject(new BoxShape(3, 2, 1), new Vector3F(0.7f, 0.8f, 0.9f), new Pose(new Vector3F(-1, 7, 4), QuaternionF.CreateRotationX(1)))); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 1, true, 0.001f, 10, out m0, out com0, out i0); }
public void TransformedShapeNegativeScalingNotSupported() { var s = new TransformedShape(new GeometricObject(new BoxShape(3, 2, 1), new Vector3F(0.7f, 0.8f, 0.9f), new Pose(new Vector3F(-1, 7, 4)))); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(2, 2.1f, -2.8f), 1, true, 0.001f, 10, out m0, out com0, out i0); }
/// <summary> /// Initializes a new instance of the <see cref="FigureRenderData"/> class. /// </summary> public FigureRenderData() { BoundingShape = new TransformedShape { Child = new GeometricObject(new BoxShape(new Vector3(Single.MaxValue))) }; // The HitShape is created on demand. }
//-------------------------------------------------------------- #region Creation & Cleanup //-------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="Spotlight"/> class. /// </summary> public Spotlight() { Color = Vector3F.One; DiffuseIntensity = 1; SpecularIntensity = 1; HdrScale = 1; _falloffAngle = 20.0f * ConstantsF.Pi / 180; Shape = new TransformedShape(new GeometricObject(new ConeShape((float)Math.Tan(MathHelper.ToRadians(30)) * 5, 5), new Pose(new Vector3F(0, 0, -5), QuaternionF.CreateRotationX(ConstantsF.PiOver2)))); Attenuation = 2; }
public CompoundShape(TransformedShape[] shapes) { this.shapes = new TransformedShape[shapes.Length]; Array.Copy(shapes, this.shapes, shapes.Length); if (!TestValidity()) throw new ArgumentException("Multishapes are not supported!"); this.UpdateShape(); }
private static Shape ComputeAxisAlignedBoundingShape(MeshContent mesh) { Debug.Assert(mesh.Positions.Count > 0); List <Vector3> points = mesh.Positions.Select(position => (Vector3)position).ToList(); var boundingShape = GeometryHelper.CreateBoundingShape(points); // Compute minimal sphere. Vector3 center; float radius; GeometryHelper.ComputeBoundingSphere(points, out radius, out center); SphereShape sphere = new SphereShape(radius); float sphereVolume = sphere.GetVolume(); // Compute minimal AABB. Aabb aabb = new Aabb(points[0], points[0]); for (int i = 1; i < points.Count; i++) { aabb.Grow(points[i]); } var boxPose = new Pose(aabb.Center); var box = new BoxShape(aabb.Extent); float boxVolume = box.GetVolume(); // Return the object with the smallest volume. // A TransformedShape is used if the shape needs to be translated. if (sphereVolume < boxVolume) { if (center.IsNumericallyZero) { boundingShape = sphere; } else { boundingShape = new TransformedShape(new GeometricObject(sphere, new Pose(center))); } } else { if (!boxPose.HasTranslation) { boundingShape = box; } else { boundingShape = new TransformedShape(new GeometricObject(box, boxPose)); } } return(boundingShape); }
public void InnerPoint2() { TransformedShape t = new TransformedShape { Child = new GeometricObject { Pose = new Pose(new Vector3(0, 1, 0)), Shape = new PointShape(1, 0, 0), }, }; Assert.AreEqual(new Vector3(1, 1, 0), t.InnerPoint); }
/// <summary> /// Gets a bounding shape that matches the specified AABB. /// </summary> /// <param name="aabb">The AABB.</param> /// <returns>A box or transformed box that matches the specified AABB.</returns> private Shape GetBoundingShape(Aabb aabb) { // The AABB of the LOD is real world size including scaling. We have to undo // the scale because this LodGroupNode also applies the same scale. var unscaledCenter = aabb.Center / ScaleWorld; var unscaledExtent = aabb.Extent / ScaleWorld; // Get existing shape objects to avoid unnecessary memory allocation. BoxShape boxShape; GeometricObject geometricObject = null; TransformedShape transformedShape = null; if (Shape is BoxShape) { boxShape = (BoxShape)Shape; } else if (Shape is TransformedShape) { transformedShape = (TransformedShape)Shape; geometricObject = (GeometricObject)transformedShape.Child; boxShape = (BoxShape)geometricObject.Shape; } else { boxShape = new BoxShape(); } // Make bounding box the size of the unscaled AABB. boxShape.Extent = unscaledExtent; if (unscaledCenter.IsNumericallyZero) { // Bounding box is centered at origin. return(boxShape); } // Apply offset to bounding box. if (transformedShape == null) { geometricObject = new GeometricObject(boxShape, new Pose(unscaledCenter)); transformedShape = new TransformedShape(geometricObject); } else { geometricObject.Shape = boxShape; geometricObject.Pose = new Pose(unscaledCenter); } return(transformedShape); }
public void TransformedShapeTest() { var c = new TransformedShape(); Assert.AreEqual(0, c.GetVolume(0.1f, 10)); c.Child = new GeometricObject( new BoxShape(1, 2, 3), new Vector3(10, 10, 10), new Pose(new Vector3(1, 2, 3), RandomHelper.Random.NextQuaternion())); var v0 = c.GetVolume(0.001f, 10); Assert.AreEqual(10 * 20 * 30, v0); }
/// <summary> /// Gets a bounding shape that matches the specified AABB. /// </summary> /// <param name="aabb">The AABB.</param> /// <returns>A box or transformed box that matches the specified AABB.</returns> private Shape GetBoundingShape(Aabb aabb) { // Get existing shape objects to avoid unnecessary memory allocation. BoxShape boxShape; GeometricObject geometricObject = null; TransformedShape transformedShape = null; if (Shape is BoxShape) { boxShape = (BoxShape)Shape; } else if (Shape is TransformedShape) { transformedShape = (TransformedShape)Shape; geometricObject = (GeometricObject)transformedShape.Child; boxShape = (BoxShape)geometricObject.Shape; } else { boxShape = new BoxShape(); } // Make box the size of the AABB. boxShape.Extent = aabb.Extent; if (aabb.Center.IsNumericallyZero) { // Bounding box is centered at origin. return(boxShape); } // Apply offset to bounding box. if (transformedShape == null) { geometricObject = new GeometricObject(boxShape, new Pose(aabb.Center)); transformedShape = new TransformedShape(geometricObject); } else { geometricObject.Shape = boxShape; geometricObject.Pose = new Pose(aabb.Center); } return(transformedShape); }
public void SerializationBinary() { Pose pose = new Pose(new Vector3(1, 2, 3)); PointShape pointShape = new PointShape(3, 4, 5); var a = new TransformedShape(new GeometricObject(pointShape, pose)); // Serialize object. var stream = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize(stream, a); // Deserialize object. stream.Position = 0; var deserializer = new BinaryFormatter(); var b = (TransformedShape)deserializer.Deserialize(stream); Assert.AreEqual(a.Child.Pose, b.Child.Pose); Assert.AreEqual(((PointShape)a.Child.Shape).Position, ((PointShape)b.Child.Shape).Position); }
public void Clone() { Pose pose = new Pose(new Vector3F(1, 2, 3)); PointShape pointShape = new PointShape(3, 4, 5); GeometricObject geometry = new GeometricObject(pointShape, pose); TransformedShape transformedShape = new TransformedShape(geometry); TransformedShape clone = transformedShape.Clone() as TransformedShape; Assert.IsNotNull(clone); Assert.IsNotNull(clone.Child); Assert.AreNotSame(geometry, clone.Child); Assert.IsTrue(clone.Child is GeometricObject); Assert.AreEqual(pose, clone.Child.Pose); Assert.IsNotNull(clone.Child.Shape); Assert.AreNotSame(pointShape, clone.Child.Shape); Assert.IsTrue(clone.Child.Shape is PointShape); Assert.AreEqual(pointShape.Position, ((PointShape)clone.Child.Shape).Position); Assert.AreEqual(transformedShape.GetAabb(Pose.Identity).Minimum, clone.GetAabb(Pose.Identity).Minimum); Assert.AreEqual(transformedShape.GetAabb(Pose.Identity).Maximum, clone.GetAabb(Pose.Identity).Maximum); }
public void GetAabb() { Assert.AreEqual(new Vector3(0, 0, 0), new TransformedShape().GetAabb(Pose.Identity).Minimum); Assert.AreEqual(new Vector3(0, 0, 0), new TransformedShape().GetAabb(Pose.Identity).Maximum); TransformedShape t = new TransformedShape { Child = new GeometricObject { Pose = new Pose(new Vector3(0, 1, 0)), Shape = new SphereShape(10), }, }; Assert.AreEqual(new Vector3(-10, -9, -10), t.GetAabb(Pose.Identity).Minimum); Assert.AreEqual(new Vector3(10, 11, 10), t.GetAabb(Pose.Identity).Maximum); Assert.AreEqual(new Vector3(-8, -9, -10), t.GetAabb(new Pose(new Vector3(2, 0, 0))).Minimum); Assert.AreEqual(new Vector3(12, 11, 10), t.GetAabb(new Pose(new Vector3(2, 0, 0))).Maximum); }
public void GetAabb() { Assert.AreEqual(new Vector3F(0, 0, 0), new TransformedShape().GetAabb(Pose.Identity).Minimum); Assert.AreEqual(new Vector3F(0, 0, 0), new TransformedShape().GetAabb(Pose.Identity).Maximum); TransformedShape t = new TransformedShape { Child = new GeometricObject { Pose = new Pose(new Vector3F(0, 1, 0)), Shape = new SphereShape(10), }, }; Assert.AreEqual(new Vector3F(-10, -9, -10), t.GetAabb(Pose.Identity).Minimum); Assert.AreEqual(new Vector3F(10, 11, 10), t.GetAabb(Pose.Identity).Maximum); Assert.AreEqual(new Vector3F(-8, -9, -10), t.GetAabb(new Pose(new Vector3F(2, 0, 0))).Minimum); Assert.AreEqual(new Vector3F(12, 11, 10), t.GetAabb(new Pose(new Vector3F(2, 0, 0))).Maximum); }
public void Clone() { Pose pose = new Pose(new Vector3(1, 2, 3)); PointShape pointShape = new PointShape(3, 4, 5); GeometricObject geometry = new GeometricObject(pointShape, pose); TransformedShape transformedShape = new TransformedShape(geometry); TransformedShape clone = transformedShape.Clone() as TransformedShape; Assert.IsNotNull(clone); Assert.IsNotNull(clone.Child); Assert.AreNotSame(geometry, clone.Child); Assert.IsTrue(clone.Child is GeometricObject); Assert.AreEqual(pose, clone.Child.Pose); Assert.IsNotNull(clone.Child.Shape); Assert.AreNotSame(pointShape, clone.Child.Shape); Assert.IsTrue(clone.Child.Shape is PointShape); Assert.AreEqual(pointShape.Position, ((PointShape)clone.Child.Shape).Position); Assert.AreEqual(transformedShape.GetAabb(Pose.Identity).Minimum, clone.GetAabb(Pose.Identity).Minimum); Assert.AreEqual(transformedShape.GetAabb(Pose.Identity).Maximum, clone.GetAabb(Pose.Identity).Maximum); }
public void GetAxisAlignedBoundingBox() { Assert.AreEqual(new Aabb(new Vector3F(0, -100, 0), new Vector3F(1000, 0, 1000)), new HeightField().GetAabb(Pose.Identity)); Assert.AreEqual(new Aabb(new Vector3F(1000, -101, 2000), new Vector3F(1100, 5, 2200)), _field.GetAabb(Pose.Identity)); Assert.AreEqual(new Aabb(new Vector3F(0, -1, 0), new Vector3F(10, 5, 20)), new HeightField(0, 0, 10, 20, _samples, 3, 8) { Depth = 0 }.GetAabb(Pose.Identity)); // Now with pose. QuaternionF rotation = QuaternionF.CreateRotationX(0.2f); Pose pose = new Pose(new Vector3F(1, 1, 1), rotation); _field.Depth = 0; var box = new TransformedShape( new GeometricObject(new BoxShape(100, 6, 200), new Pose(new Vector3F(1050, 2, 2100)))); Assert.IsTrue(Vector3F.AreNumericallyEqual(box.GetAabb(pose).Minimum, _field.GetAabb(pose).Minimum)); _field.Depth = 4; box = new TransformedShape( new GeometricObject(new BoxShape(100, 10, 200), new Pose(new Vector3F(1000, 0, 2000)))); Assert.IsTrue(Vector3F.AreNumericallyEqual(box.GetAabb(pose).Minimum + rotation.Rotate(new Vector3F(50, 0, 100)), _field.GetAabb(pose).Minimum)); }
public void ApproximateAabbMass() { var s = new ConvexHullOfPoints(new[] { new Vector3F(1, 1, 1), new Vector3F(2, 4, 6) }); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(1.2f, 2.1f, 0.6f), 0.7f, true, 0.001f, 0, out m0, out com0, out i0); var s2 = new TransformedShape(new GeometricObject(new BoxShape(1, 3, 5), new Pose(new Vector3F(1.5f, 2.5f, 3.5f)))); float m1; Vector3F com1; Matrix33F i1; MassHelper.GetMass(s2, new Vector3F(1.2f, 2.1f, 0.6f), 0.7f, true, 0.001f, 0, out m1, out com1, out i1); const float e = 0.0001f; Assert.IsTrue(Numeric.AreEqual(m0, m1, e * (1 + m0))); Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com1, e * (1 + com0.Length))); Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0, i1, e * (1 + i0.Trace))); }
public void PropertyChangedTest() { TransformedShape t = new TransformedShape(); t.Changed += delegate { _propertyChanged = true; }; Assert.IsFalse(_propertyChanged); ((GeometricObject)t.Child).Shape = new SphereShape(1); Assert.IsTrue(_propertyChanged); _propertyChanged = false; ((SphereShape)t.Child.Shape).Radius = 3; Assert.IsTrue(_propertyChanged); _propertyChanged = false; ((GeometricObject)t.Child).Pose = new Pose(new Vector3(1, 2, 3)); Assert.IsTrue(_propertyChanged); _propertyChanged = false; // Setting Pose to the same value does not create a changed event. ((GeometricObject)t.Child).Pose = new Pose(new Vector3(1, 2, 3)); Assert.IsFalse(_propertyChanged); _propertyChanged = false; ((GeometricObject)t.Child).Pose = Pose.Identity; Assert.IsTrue(_propertyChanged); _propertyChanged = false; t.Child = new GeometricObject(); Assert.IsTrue(_propertyChanged); _propertyChanged = false; // Setting Pose to the same value does not create a changed event. ((GeometricObject)t.Child).Pose = Pose.Identity; Assert.IsFalse(_propertyChanged); _propertyChanged = false; }
private Shape BuildBoundingShape(DRMeshNodeContent meshNode) { Shape boundingShape = Shape.Empty; var mesh = meshNode.InputMesh; if (mesh.Positions.Count > 0) { if (_modelDescription != null && _modelDescription.AabbEnabled) { // We assume that the AABB is given in the local space. Vector3 aabbMinimum = (Vector3)_modelDescription.AabbMinimum; Vector3 aabbMaximum = (Vector3)_modelDescription.AabbMaximum; Vector3 center = (aabbMaximum + aabbMinimum) / 2; Vector3 extent = aabbMaximum - aabbMinimum; if (center.IsNumericallyZero) { boundingShape = new BoxShape(extent); } else { boundingShape = new TransformedShape(new GeometricObject(new BoxShape(extent), new Pose(center))); } } else { // Best fit bounding shape. //boundingShape = ComputeBestFitBoundingShape(mesh); // Non-rotated bounding shape. This is usually larger but contains no rotations. // (TransformedShapes with rotated children cannot be used with non-uniform scaling.) boundingShape = ComputeAxisAlignedBoundingShape(mesh); } } return(boundingShape); }
public void TransformedShapeMassWithScaling() { var s = new TransformedShape(new GeometricObject(new BoxShape(3, 2, 1), new Vector3(0.7f), new Pose(new Vector3(-1, 7, 4), RandomHelper.Random.NextQuaternion()))); float m0; Vector3 com0; Matrix i0; MassHelper.GetMass(s, new Vector3(2), 1, true, 0.001f, 10, out m0, out com0, out i0); var m = s.GetMesh(0.001f, 6); m.Transform(Matrix.CreateScale(2)); float m1; Vector3 com1; Matrix i1; MassHelper.GetMass(m, out m1, out com1, out i1); const float e = 0.01f; Assert.IsTrue(Numeric.AreEqual(m0, m1, e * (1 + m0))); Assert.IsTrue(Vector3.AreNumericallyEqual(com0, com1, e * (1 + com0.Length))); Assert.IsTrue(Matrix.AreNumericallyEqual(i0, i1, e * (1 + i0.Trace))); }
public void TransformedShapeMassWithNonuniformScaling() { var s = new TransformedShape(new GeometricObject(new BoxShape(3, 2, 1), new Vector3F(0.7f, 0.8f, 0.9f), new Pose(new Vector3F(-1, 7, 4)))); float m0; Vector3F com0; Matrix33F i0; MassHelper.GetMass(s, new Vector3F(2, 2.1f, 2.8f), 1, true, 0.001f, 10, out m0, out com0, out i0); var m = s.GetMesh(0.001f, 6); m.Transform(Matrix44F.CreateScale(2, 2.1f, 2.8f)); float m1; Vector3F com1; Matrix33F i1; MassHelper.GetMass(m, out m1, out com1, out i1); const float e = 0.01f; Assert.IsTrue(Numeric.AreEqual(m0, m1, e * (1 + m0))); Assert.IsTrue(Vector3F.AreNumericallyEqual(com0, com1, e * (1 + com0.Length))); Assert.IsTrue(Matrix33F.AreNumericallyEqual(i0, i1, e * (1 + i0.Trace))); }
public IntersectionSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; var delegateGraphicsScreen = new DelegateGraphicsScreen(GraphicsService) { RenderCallback = Render, }; GraphicsService.Screens.Insert(0, delegateGraphicsScreen); // Add a custom game object which controls the camera. _cameraObject = new CameraObject(Services, 10); _cameraObject.ResetPose(new Vector3(0, 0, -4), ConstantsF.Pi, 0); GameObjectService.Objects.Add(_cameraObject); // Create a new scene with some lights. _scene = new Scene(); SceneSample.InitializeDefaultXnaLights(_scene); _meshRenderer = new MeshRenderer(); _debugRenderer = new DebugRenderer(GraphicsService, null); _intersectionRenderer = new IntersectionRenderer(GraphicsService, ContentManager) { DownsampleFactor = 1, }; //_submeshA = MeshHelper.CreateSubmesh(GraphicsService.GraphicsDevice, new SphereShape(0.5f).GetMesh(0.001f, 5), MathHelper.ToRadians(70)); //_submeshB = MeshHelper.CreateSubmesh(GraphicsService.GraphicsDevice, new BoxShape(1, 1, 2).GetMesh(0.001f, 5), MathHelper.ToRadians(70)); var meshNodeA = CreateMeshNode(new[] { MeshHelper.CreateTorus(GraphicsService.GraphicsDevice, 1, 0.3f, 30), MeshHelper.CreateSubmesh(GraphicsService.GraphicsDevice, new BoxShape(1, 1, 2).GetMesh(0.001f, 5), MathHelper.ToRadians(70)), }, Color.DarkBlue); meshNodeA.PoseWorld = new Pose(RandomHelper.Random.NextVector3(-0.5f, 0.5f), RandomHelper.Random.NextQuaternion()); _scene.Children.Add(meshNodeA); _debugRenderer.DrawObject(meshNodeA, Color.Green, true, false); var shape = new TransformedShape( new GeometricObject(new SphereShape(0.5f), new Pose(new Vector3(1, 0, 0)))); var meshNodeB = CreateMeshNode(new[] { MeshHelper.CreateTorus(GraphicsService.GraphicsDevice, 1, 0.3f, 30), MeshHelper.CreateSubmesh(GraphicsService.GraphicsDevice, shape.GetMesh(0.001f, 4), MathHelper.ToRadians(90)), }, Color.Gray); meshNodeB.PoseWorld = new Pose(RandomHelper.Random.NextVector3(-1f, 1f), RandomHelper.Random.NextQuaternion()); _scene.Children.Add(meshNodeB); _debugRenderer.DrawObject(meshNodeB, Color.Green, true, false); var meshNodeC = CreateMeshNode(new[] { MeshHelper.CreateBox(GraphicsService.GraphicsDevice), MeshHelper.CreateSubmesh(GraphicsService.GraphicsDevice, new BoxShape(1, 1, 2).GetMesh(0.001f, 5), MathHelper.ToRadians(70)) }, Color.DarkGreen); meshNodeC.PoseWorld = new Pose(RandomHelper.Random.NextVector3(-1f, 1f), RandomHelper.Random.NextQuaternion()); meshNodeC.ScaleLocal = new Vector3(0.1f, 1f, 0.5f); _scene.Children.Add(meshNodeC); _debugRenderer.DrawObject(meshNodeC, Color.Green, true, false); _meshNodePairs.Add(new Pair <MeshNode>(meshNodeA, meshNodeB)); _meshNodePairs.Add(new Pair <MeshNode>(meshNodeA, meshNodeC)); _meshNodePairs.Add(new Pair <MeshNode>(meshNodeB, meshNodeC)); CreateGuiControls(); }
// Creates a lot of random objects. private void CreateRandomObjects() { var random = new Random(); var isFirstHeightField = true; int currentShape = 0; int numberOfObjects = 0; while (true) { numberOfObjects++; if (numberOfObjects > ObjectsPerType) { currentShape++; numberOfObjects = 0; } Shape shape; switch (currentShape) { case 0: // Box shape = new BoxShape(ObjectSize, ObjectSize * 2, ObjectSize * 3); break; case 1: // Capsule shape = new CapsuleShape(0.3f * ObjectSize, 2 * ObjectSize); break; case 2: // Cone shape = new ConeShape(1 * ObjectSize, 2 * ObjectSize); break; case 3: // Cylinder shape = new CylinderShape(0.4f * ObjectSize, 2 * ObjectSize); break; case 4: // Sphere shape = new SphereShape(ObjectSize); break; case 5: // Convex hull of several points. ConvexHullOfPoints hull = new ConvexHullOfPoints(); hull.Points.Add(new Vector3(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize)); hull.Points.Add(new Vector3(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize)); hull.Points.Add(new Vector3(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize)); hull.Points.Add(new Vector3(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize)); hull.Points.Add(new Vector3(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize)); shape = hull; break; case 6: // A composite shape: two boxes that form a "T" shape. var composite = new CompositeShape(); composite.Children.Add( new GeometricObject( new BoxShape(ObjectSize, 3 * ObjectSize, ObjectSize), new Pose(new Vector3(0, 0, 0)))); composite.Children.Add( new GeometricObject( new BoxShape(2 * ObjectSize, ObjectSize, ObjectSize), new Pose(new Vector3(0, 2 * ObjectSize, 0)))); shape = composite; break; case 7: shape = new CircleShape(ObjectSize); break; case 8: { var compBvh = new CompositeShape(); compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3(0, 0.5f, 0), Matrix.Identity))); compBvh.Children.Add(new GeometricObject(new BoxShape(0.8f, 0.5f, 0.5f), new Pose(new Vector3(0.5f, 0.7f, 0), Matrix.CreateRotationZ(-MathHelper.ToRadians(15))))); compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3(0, 1.15f, 0), Matrix.Identity))); compBvh.Children.Add(new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3(0.6f, 1.15f, 0), Matrix.CreateRotationX(0.3f)))); compBvh.Partition = new AabbTree<int>(); shape = compBvh; break; } case 9: CompositeShape comp = new CompositeShape(); comp.Children.Add(new GeometricObject(new BoxShape(0.5f * ObjectSize, 1 * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3(0, 0.5f * ObjectSize, 0), Quaternion.Identity))); comp.Children.Add(new GeometricObject(new BoxShape(0.8f * ObjectSize, 0.5f * ObjectSize, 0.5f * ObjectSize), new Pose(new Vector3(0.3f * ObjectSize, 0.7f * ObjectSize, 0), Quaternion.CreateRotationZ(-MathHelper.ToRadians(45))))); comp.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3(0, 1.15f * ObjectSize, 0), Quaternion.Identity))); shape = comp; break; case 10: shape = new ConvexHullOfPoints(new[] { new Vector3(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize), new Vector3(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize), new Vector3(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize), new Vector3(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize), new Vector3(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize) }); break; case 11: ConvexHullOfShapes shapeHull = new ConvexHullOfShapes(); shapeHull.Children.Add(new GeometricObject(new SphereShape(0.3f * ObjectSize), new Pose(new Vector3(0, 2 * ObjectSize, 0), Matrix.Identity))); shapeHull.Children.Add(new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize), Pose.Identity)); shape = shapeHull; break; case 12: shape = Shape.Empty; break; case 13: var numberOfSamplesX = 10; var numberOfSamplesZ = 10; var samples = new float[numberOfSamplesX * numberOfSamplesZ]; for (int z = 0; z < numberOfSamplesZ; z++) for (int x = 0; x < numberOfSamplesX; x++) samples[z * numberOfSamplesX + x] = (float)(Math.Cos(z / 3f) * Math.Sin(x / 2f) * BoxSize / 6); HeightField heightField = new HeightField(0, 0, 2 * BoxSize, 2 * BoxSize, samples, numberOfSamplesX, numberOfSamplesZ); shape = heightField; break; //case 14: //shape = new LineShape(new Vector3(0.1f, 0.2f, 0.3f), new Vector3(0.1f, 0.2f, -0.3f).Normalized); //break; case 15: shape = new LineSegmentShape( new Vector3(0.1f, 0.2f, 0.3f), new Vector3(0.1f, 0.2f, 0.3f) + 3 * ObjectSize * new Vector3(0.1f, 0.2f, -0.3f)); break; case 16: shape = new MinkowskiDifferenceShape { ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)), ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize)) }; break; case 17: shape = new MinkowskiSumShape { ObjectA = new GeometricObject(new SphereShape(0.1f * ObjectSize)), ObjectB = new GeometricObject(new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize)), }; break; case 18: shape = new OrthographicViewVolume(0, ObjectSize, 0, ObjectSize, ObjectSize / 2, ObjectSize * 2); break; case 19: shape = new PerspectiveViewVolume(MathHelper.ToRadians(60f), 16f / 10, ObjectSize / 2, ObjectSize * 3); break; case 20: shape = new PointShape(0.1f, 0.3f, 0.2f); break; case 21: shape = new RayShape(new Vector3(0.2f, 0, -0.12f), new Vector3(1, 2, 3).Normalized, ObjectSize * 2); break; case 22: shape = new RayShape(new Vector3(0.2f, 0, -0.12f), new Vector3(1, 2, 3).Normalized, ObjectSize * 2) { StopsAtFirstHit = true }; break; case 23: shape = new RectangleShape(ObjectSize, ObjectSize * 2); break; case 24: shape = new TransformedShape( new GeometricObject( new BoxShape(1 * ObjectSize, 2 * ObjectSize, 3 * ObjectSize), new Pose(new Vector3(0.1f, 1, -0.2f)))); break; case 25: shape = new TriangleShape( new Vector3(ObjectSize, 0, 0), new Vector3(0, ObjectSize, 0), new Vector3(ObjectSize, ObjectSize, ObjectSize)); break; //case 26: // { // // Create a composite object from which we get the mesh. // CompositeShape compBvh = new CompositeShape(); // compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3(0, 0.5f, 0), Matrix.Identity))); // compBvh.Children.Add( // new GeometricObject( // new BoxShape(0.8f, 0.5f, 0.5f), // new Pose(new Vector3(0.5f, 0.7f, 0), Matrix.CreateRotationZ(-(float)MathHelper.ToRadians(15))))); // compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3(0, 1.15f, 0), Matrix.Identity))); // compBvh.Children.Add( // new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3(0.6f, 1.15f, 0), Matrix.CreateRotationX(0.3f)))); // TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) }; // meshBvhShape.Partition = new AabbTree<int>(); // shape = meshBvhShape; // break; // } //case 27: // { // // Create a composite object from which we get the mesh. // CompositeShape compBvh = new CompositeShape(); // compBvh.Children.Add(new GeometricObject(new BoxShape(0.5f, 1, 0.5f), new Pose(new Vector3(0, 0.5f, 0), Quaternion.Identity))); // compBvh.Children.Add( // new GeometricObject( // new BoxShape(0.8f, 0.5f, 0.5f), // new Pose(new Vector3(0.5f, 0.7f, 0), Quaternion.CreateRotationZ(-(float)MathHelper.ToRadians(15))))); // compBvh.Children.Add(new GeometricObject(new SphereShape(0.3f), new Pose(new Vector3(0, 1.15f, 0), Quaternion.Identity))); // compBvh.Children.Add( // new GeometricObject(new CapsuleShape(0.2f, 1), new Pose(new Vector3(0.6f, 1.15f, 0), Quaternion.CreateRotationX(0.3f)))); // TriangleMeshShape meshBvhShape = new TriangleMeshShape { Mesh = compBvh.GetMesh(0.01f, 3) }; // meshBvhShape.Partition = new AabbTree<int>(); // shape = meshBvhShape; // break; // } case 28: shape = new ConvexPolyhedron(new[] { new Vector3(-1 * ObjectSize, -2 * ObjectSize, -1 * ObjectSize), new Vector3(2 * ObjectSize, -1 * ObjectSize, -0.5f * ObjectSize), new Vector3(1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize), new Vector3(-1 * ObjectSize, 2 * ObjectSize, 1 * ObjectSize), new Vector3(-1 * ObjectSize, 0.7f * ObjectSize, -0.6f * ObjectSize) }); break; case 29: return; default: currentShape++; continue; } // Create an object with the random shape, pose, color and velocity. Pose randomPose = new Pose( random.NextVector3(-BoxSize + ObjectSize * 2, BoxSize - ObjectSize * 2), random.NextQuaternion()); var newObject = new MovingGeometricObject { Pose = randomPose, Shape = shape, LinearVelocity = random.NextQuaternion().Rotate(new Vector3(MaxLinearVelocity, 0, 0)), AngularVelocity = random.NextQuaternion().Rotate(Vector3.Forward) * RandomHelper.Random.NextFloat(0, MaxAngularVelocity), }; if (RandomHelper.Random.NextBool()) newObject.LinearVelocity = Vector3.Zero; if (RandomHelper.Random.NextBool()) newObject.AngularVelocity = Vector3.Zero; if (shape is LineShape || shape is HeightField) { // Do not move lines or the height field. newObject.LinearVelocity = Vector3.Zero; newObject.AngularVelocity = Vector3.Zero; } // Create only 1 heightField! if (shape is HeightField) { if (isFirstHeightField) { isFirstHeightField = true; newObject.Pose = new Pose(new Vector3(-BoxSize, -BoxSize, -BoxSize)); } else { currentShape++; numberOfObjects = 0; continue; } } // Add collision object to collision domain. _domain.CollisionObjects.Add(new CollisionObject(newObject)); //co.Type = CollisionObjectType.Trigger; //co.Name = "Object" + shape.GetType().Name + "_" + i; } }
public override void ComputeCollision(ContactSet contactSet, CollisionQueryType type) { // Object B should be the transformed shape. CollisionObject objectA = contactSet.ObjectA; CollisionObject objectB = contactSet.ObjectB; // Swap objects if necessary. bool swapped = !(objectB.GeometricObject.Shape is TransformedShape); if (swapped) { MathHelper.Swap(ref objectA, ref objectB); } IGeometricObject geometricObjectB = objectB.GeometricObject; TransformedShape transformedShape = geometricObjectB.Shape as TransformedShape; // Check if collision objects shapes are correct. if (transformedShape == null) { throw new ArgumentException("The contact set must contain a transformed shape.", "contactSet"); } // Assume no contact. contactSet.HaveContact = false; // Currently object B has the following structure: // // CollisionObject objectB // GeometricObject geometricObjectB // Pose poseB // Scale scaleB // TransformedShape transformedShape // GeometricObject childGeometricObject // Pose childPose // Scale childScale // Shape childShape // // To compute the collisions we temporarily remove the TransformedShape: // We replace the original geometric object with a test geometric object and combine the // transformations: // // CollisionObject testObjectB // GeometricObject testGeometricObjectB // Pose poseB * childPose // Shape childShape // Scale scaleB * childScale Pose poseB = geometricObjectB.Pose; Vector3F scaleB = geometricObjectB.Scale; // Apply scale to pose and test geometric object. // (Note: The scaling is either uniform or the transformed object has no local rotation. // Therefore, we only need to apply the scale of the parent to the scale and translation of // the child. We can ignore the rotation.) IGeometricObject childGeometricObject = transformedShape.Child; Pose childPose = childGeometricObject.Pose; // Non-uniform scaling is not supported for rotated child objects. if ((scaleB.X != scaleB.Y || scaleB.Y != scaleB.Z) && childPose.HasRotation) { throw new NotSupportedException("Computing collisions for transformed shapes with local rotations and non-uniform scaling is not supported."); } childPose.Position *= scaleB; // Apply scaling to local translation. var testGeometricObjectB = TestGeometricObject.Create(); testGeometricObjectB.Shape = childGeometricObject.Shape; testGeometricObjectB.Scale = scaleB * childGeometricObject.Scale; // Apply scaling to local scale. testGeometricObjectB.Pose = poseB * childPose; var testCollisionObjectB = ResourcePools.TestCollisionObjects.Obtain(); testCollisionObjectB.SetInternal(objectB, testGeometricObjectB); var testContactSet = swapped ? ContactSet.Create(testCollisionObjectB, objectA) : ContactSet.Create(objectA, testCollisionObjectB); testContactSet.IsPerturbationTestAllowed = contactSet.IsPerturbationTestAllowed; // Transform contacts into space of child and copy them into the testContactSet. //int numberOfOldContacts = contactSet.Count; //for (int i = 0; i < numberOfOldContacts; i++) //{ // Contact contact = contactSet[i]; // if (swapped) // contact.PositionALocal = childPose.ToLocalPosition(contact.PositionALocal); // else // contact.PositionBLocal = childPose.ToLocalPosition(contact.PositionBLocal); // // testContactSet.Add(contact); //} // Compute collision. var collisionAlgorithm = CollisionDetection.AlgorithmMatrix[objectA, testCollisionObjectB]; collisionAlgorithm.ComputeCollision(testContactSet, type); if (testContactSet.HaveContact) { contactSet.HaveContact = true; } // Transform contacts into space of parent TransformShape. int numberOfNewContacts = testContactSet.Count; for (int i = 0; i < numberOfNewContacts; i++) { Contact contact = testContactSet[i]; if (swapped) { contact.PositionALocal = childPose.ToWorldPosition(contact.PositionALocal); } else { contact.PositionBLocal = childPose.ToWorldPosition(contact.PositionBLocal); } } // Merge new contacts to contactSet. // (If testContactSet contains all original contacts (see commented out part above), we can // simply clear contactSet and copy all contacts of testContactSet.) //contactSet.Clear(); //foreach (Contact contact in testContactSet) // contactSet.Add(contact); ContactHelper.Merge(contactSet, testContactSet, type, CollisionDetection.ContactPositionTolerance); // Recycle temporary objects. testContactSet.Recycle(); ResourcePools.TestCollisionObjects.Recycle(testCollisionObjectB); testGeometricObjectB.Recycle(); }
public void GeometryException() { TransformedShape t = new TransformedShape(); t.Child = null; }
public void SerializationBinary() { Pose pose = new Pose(new Vector3F(1, 2, 3)); PointShape pointShape = new PointShape(3, 4, 5); var a = new TransformedShape(new GeometricObject(pointShape, pose)); // Serialize object. var stream = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize(stream, a); // Deserialize object. stream.Position = 0; var deserializer = new BinaryFormatter(); var b = (TransformedShape)deserializer.Deserialize(stream); Assert.AreEqual(a.Child.Pose, b.Child.Pose); Assert.AreEqual(((PointShape)a.Child.Shape).Position, ((PointShape)b.Child.Shape).Position); }
public void PropertyChangedTest() { TransformedShape t = new TransformedShape(); t.Changed += delegate { _propertyChanged = true; }; Assert.IsFalse(_propertyChanged); ((GeometricObject)t.Child).Shape = new SphereShape(1); Assert.IsTrue(_propertyChanged); _propertyChanged = false; ((SphereShape) t.Child.Shape).Radius = 3; Assert.IsTrue(_propertyChanged); _propertyChanged = false; ((GeometricObject)t.Child).Pose = new Pose(new Vector3F(1, 2, 3)); Assert.IsTrue(_propertyChanged); _propertyChanged = false; // Setting Pose to the same value does not create a changed event. ((GeometricObject)t.Child).Pose = new Pose(new Vector3F(1, 2, 3)); Assert.IsFalse(_propertyChanged); _propertyChanged = false; ((GeometricObject)t.Child).Pose = Pose.Identity; Assert.IsTrue(_propertyChanged); _propertyChanged = false; t.Child = new GeometricObject(); Assert.IsTrue(_propertyChanged); _propertyChanged = false; // Setting Pose to the same value does not create a changed event. ((GeometricObject)t.Child).Pose = Pose.Identity; Assert.IsFalse(_propertyChanged); _propertyChanged = false; }
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)); }
public WaterSample(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; // More standard objects. GameObjectService.Objects.Add(new GrabObject(Services)); GameObjectService.Objects.Add(new ObjectCreatorObject(Services)); //GameObjectService.Objects.Add(new StaticSkyObject(Services)); var dynamicSkyObject = new DynamicSkyObject(Services, true, false, true); GameObjectService.Objects.Add(dynamicSkyObject); // Add a ground plane with some detail to see the water refractions. Simulation.RigidBodies.Add(new RigidBody(new PlaneShape(new Vector3(0, 1, 0), 0))); GameObjectService.Objects.Add(new StaticObject(Services, "Gravel/Gravel", 1, new Pose(new Vector3(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, 5)); GameObjectService.Objects.Add(new DynamicObject(Services, 6)); GameObjectService.Objects.Add(new DynamicObject(Services, 7)); GameObjectService.Objects.Add(new FogObject(Services) { AttachToCamera = true }); // The LavaBalls class controls all lava ball instances. var lavaBalls = new LavaBallsObject(Services); GameObjectService.Objects.Add(lavaBalls); // Add a few palm trees. var random = new Random(12345); for (int i = 0; i < 10; i++) { Vector3 position = new Vector3(random.NextFloat(-3, -8), 0, random.NextFloat(0, -5)); Matrix orientation = Matrix.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))); } // Define the appearance of the water. var water = new Water { SpecularColor = new Vector3(10f), // Small water ripples/waves are created using scrolling normal maps. NormalMap0 = ContentManager.Load <Texture2D>("Water/Wave0"), NormalMap1 = ContentManager.Load <Texture2D>("Water/Wave1"), NormalMap0Scale = 1.8f, NormalMap1Scale = 2.2f, NormalMap0Velocity = new Vector3(-0.02f, 0, 0.03f), NormalMap1Velocity = new Vector3(0.02f, 0, -0.03f), NormalMap0Strength = 0.5f, NormalMap1Strength = 0.5f, ReflectionDistortion = 0.2f, ReflectionColor = new Vector3(0.7f), RefractionDistortion = 0.05f, }; // Create a box-shaped body of water. // We use a TransformedShape containing a BoxShape because the top of the // water body must be at height 0. var shape = new TransformedShape(new GeometricObject( new BoxShape(10, 1, 20), new Pose(new Vector3(0, -0.5f, 0)))); _waterNode0 = new WaterNode(water, shape) { PoseWorld = new Pose(new Vector3(-1, 0.5f, 0), Matrix.CreateRotationY(0.1f)), SkyboxReflection = _graphicsScreen.Scene.GetDescendants().OfType <SkyboxNode>().First(), DepthBufferWriteEnable = true, }; _graphicsScreen.Scene.Children.Add(_waterNode0); // Optional: Create a WaterFlow to move the water using a flow texture. _waterFlow0 = new WaterFlow { FlowMapSpeed = 0.5f, FlowMap = GenerateFlowMap(), CycleDuration = 3f, NoiseMapStrength = 0.1f, NoiseMapScale = 0.5f, }; _waterNode0.Flow = _waterFlow0; // Optional: Use a planar reflection instead of the skybox reflection. // We add a PlanarReflectionNode as a child of the WaterNode. var renderToTexture = new RenderToTexture { Texture = new RenderTarget2D(GraphicsService.GraphicsDevice, 512, 512, false, SurfaceFormat.HdrBlendable, DepthFormat.None), }; var planarReflectionNode = new PlanarReflectionNode(renderToTexture) { // Same shape as WaterNode. Shape = _waterNode0.Shape, // Reflection plane is horizontal. NormalLocal = new Vector3(0, 1, 0), }; _waterNode0.PlanarReflection = planarReflectionNode; _waterNode0.Children = new SceneNodeCollection(1) { planarReflectionNode }; // Create a short river with an inclined water surface. // Using a WaterFlow with a SurfaceSlopeSpeed, the water automatically flows // down the inclined surface. _waterNode1 = new WaterNode(water, GetSpiralShape()) { PoseWorld = new Pose(new Vector3(10, 1.5f, 0), Matrix.CreateRotationY(0.1f)), EnableUnderwaterEffect = false, SkyboxReflection = _graphicsScreen.Scene.GetDescendants().OfType <SkyboxNode>().First(), Flow = new WaterFlow { SurfaceSlopeSpeed = 0.5f, CycleDuration = 2f, NoiseMapStrength = 0.1f, NoiseMapScale = 1, } }; _graphicsScreen.Scene.Children.Add(_waterNode1); }
private void Update(bool invalidateRenderData) { if (invalidateRenderData) { RenderData.SafeDispose(); } // Update shape. if (Volume == null) { // Use a PlaneShape for an infinite ocean. var planeShape = Shape as PlaneShape; if (planeShape != null) { planeShape.Normal = new Vector3F(0, 1, 0); planeShape.DistanceFromOrigin = ExtraHeight; } else { Shape = new PlaneShape(new Vector3F(0, 1, 0), ExtraHeight); } return; } // Check if we have a valid AABB. var aabb = Volume.GetAabb(); if (!Numeric.IsZeroOrPositiveFinite(aabb.Extent.LengthSquared)) { throw new GraphicsException("Invalid water volume. The water volume must be a finite shape or null."); } // Apply ExtraHeight. We also apply it horizontally because choppy waves // move vertices horizontally too. aabb.Minimum.X -= ExtraHeight; // Minimum y should be at least max y - ExtraHeight. aabb.Minimum.Y = Math.Min(aabb.Minimum.Y, aabb.Maximum.Y - ExtraHeight); aabb.Minimum.Z -= ExtraHeight; aabb.Maximum.X += ExtraHeight; aabb.Maximum.Y += ExtraHeight; aabb.Maximum.Z += ExtraHeight; // Create shape from volume AABB. if (aabb.Center.IsNumericallyZero) { // Use BoxShape. var boxShape = Shape as BoxShape; if (boxShape != null) { boxShape.Extent = aabb.Extent; } else { Shape = new BoxShape(aabb.Extent); } } else { BoxShape boxShape = null; var transformedShape = Shape as TransformedShape; if (transformedShape != null) { boxShape = transformedShape.Child.Shape as BoxShape; } if (boxShape != null) { boxShape.Extent = aabb.Extent; ((GeometricObject)transformedShape.Child).Pose = new Pose(aabb.Center); } else { Shape = new TransformedShape( new GeometricObject(new BoxShape(aabb.Extent), new Pose(aabb.Center))); } } }
public void InnerPoint2() { TransformedShape t = new TransformedShape { Child = new GeometricObject { Pose = new Pose(new Vector3F(0, 1, 0)), Shape = new PointShape(1, 0, 0), }, }; Assert.AreEqual(new Vector3F(1, 1, 0), t.InnerPoint); }
/// <summary> /// Converts mesh content to a <see cref="Shape"/>. /// </summary> /// <param name="input">The root node content.</param> /// <param name="context">Context for the specified processor.</param> /// <returns>The <see cref="Shape"/>.</returns> public override Shape Process(NodeContent input, ContentProcessorContext context) { // ----- Apply Scale factor. if (Scale != 1f) { // The user has set a scale. Use MeshHelper to apply the scale to the whole model. Matrix transform = Matrix.CreateScale(Scale); MeshHelper.TransformScene(input, transform); } // ----- Convert Mesh to Shapes // The input node is usually a tree of nodes. We need to collect all MeshContent nodes // in the tree. The DigitalRune Helper library provides a TreeHelper that can be used // to traverse trees using LINQ. // The following returns an IEnumerable that contains all nodes of the tree. IEnumerable <NodeContent> nodes = TreeHelper.GetSubtree(input, n => n.Children); // We only need nodes of type MeshContent. IEnumerable <MeshContent> meshes = nodes.OfType <MeshContent>(); // For each MeshContent we extract one shape and its pose (position and orientation). List <Pose> poses = new List <Pose>(); List <Shape> shapes = new List <Shape>(); foreach (var mesh in meshes) { if (mesh.Positions.Count == 0) { continue; } Pose pose = Pose.Identity; Shape shape = null; // The meshes in the imported file must follow a naming convention. The end of the name // of each mesh must be "Box", "Sphere" or "Convex" to tell us which kind of collision // shape we must create. if (mesh.Name.EndsWith("Box")) { LoadBox(mesh, out pose, out shape); } else if (mesh.Name.EndsWith("Sphere")) { LoadSphere(mesh, out pose, out shape); } else if (mesh.Name.EndsWith("Convex")) { LoadConvex(mesh, out pose, out shape); } if (shape != null) { poses.Add(pose); shapes.Add(shape); } } // The CollisionShapeProcessor exports a single shape. Shape collisionShape; if (shapes.Count == 0) { // We did not find any collision shapes. --> Return a dummy shape. collisionShape = Shape.Empty; } else if (shapes.Count == 1) { // We have found 1 shape. if (poses[0].HasRotation || poses[0].HasTranslation) { // The shape is not centered in origin of the model space or it is rotated, // therefore we create a TransformedShape that applies the transformation. collisionShape = new TransformedShape(new GeometricObject(shapes[0], poses[0])); } else { // Use the shape directly, there is no translation or rotation we have to apply. collisionShape = shapes[0]; } } else { // We have found several collision shapes. --> Combine all shapes into one CompositeShape. CompositeShape compositeShape = new CompositeShape(); for (int i = 0; i < shapes.Count; i++) { compositeShape.Children.Add(new GeometricObject(shapes[i], poses[i])); } // If the composite shape has many children, the performance is improved if the composite // shape uses a spatial partition. //compositeShape.Partition = new CompressedAabbTree(); collisionShape = compositeShape; } return(collisionShape); }
/// <inheritdoc/> /// <exception cref="ArgumentException"> /// Neither <paramref name="objectA"/> nor <paramref name="objectB"/> is a /// <see cref="TransformedShape"/>. /// <exception cref="ArgumentNullException"> /// <paramref name="objectA"/> or <paramref name="objectB"/> is <see langword="null"/>. /// </exception> /// </exception> public override float GetTimeOfImpact(CollisionObject objectA, Pose targetPoseA, CollisionObject objectB, Pose targetPoseB, float allowedPenetration) { // Most of this code is copied from ComputeCollision() above. // We get the child and compute the TOI for the child movement. The child movement is // linearly interpolated from start to end pose. - This is not correct if the real center // of rotation and the center of the child shape are not equal! But for small rotational // movement and small offsets this is acceptable. if (objectA == null) { throw new ArgumentNullException("objectA"); } if (objectB == null) { throw new ArgumentNullException("objectB"); } // B should be the transformed shape, swap objects if necessary. bool swapped = !(objectB.GeometricObject.Shape is TransformedShape); if (swapped) { MathHelper.Swap(ref objectA, ref objectB); MathHelper.Swap(ref targetPoseA, ref targetPoseB); } IGeometricObject geometricObjectB = objectB.GeometricObject; TransformedShape transformedShape = geometricObjectB.Shape as TransformedShape; // Check if collision objects shapes are correct. if (transformedShape == null) { throw new ArgumentException("objectA or objectB must be a TransformedShape."); } Pose poseB = geometricObjectB.Pose; Vector3F scaleB = geometricObjectB.Scale; // Note: Non-uniform scaling for rotated child objects is not supported // but we might still get a usable TOI query result. // Apply scale to pose and test geometric object. // (Note: The scaling is either uniform or the transformed object has no local rotation. // Therefore, we only need to apply the scale of the parent to the scale and translation of // the child. We can ignore the rotation.) IGeometricObject childGeometricObject = transformedShape.Child; Pose childPose = childGeometricObject.Pose; childPose.Position *= scaleB; // Apply scaling to local translation. var testGeometricObjectB = TestGeometricObject.Create(); testGeometricObjectB.Shape = childGeometricObject.Shape; testGeometricObjectB.Scale = scaleB * childGeometricObject.Scale; // Apply scaling to local scale. testGeometricObjectB.Pose = poseB * childPose; var testCollisionObjectB = ResourcePools.TestCollisionObjects.Obtain(); testCollisionObjectB.SetInternal(objectB, testGeometricObjectB); // Compute TOI. var collisionAlgorithm = CollisionDetection.AlgorithmMatrix[objectA, testCollisionObjectB]; float timeOfImpact = collisionAlgorithm.GetTimeOfImpact( objectA, targetPoseA, testCollisionObjectB, targetPoseB * childPose, allowedPenetration); // Recycle temporary objects. ResourcePools.TestCollisionObjects.Recycle(testCollisionObjectB); testGeometricObjectB.Recycle(); return(timeOfImpact); }