public static void CreateShapes(Demo demo, PhysicsScene scene) { TriangleMesh triangleMesh = null; ShapePrimitive shapePrimitive = null; Shape shape = null; shapePrimitive = scene.Factory.ShapePrimitiveManager.Create("CapsuleY1"); shapePrimitive.CreateCapsuleY(1.5f, 1.0f); shape = scene.Factory.ShapeManager.Create("CapsuleY1"); shape.Set(shapePrimitive, Matrix4.Identity, 0.0f); shapePrimitive = scene.Factory.ShapePrimitiveManager.Create("CapsuleY2"); shapePrimitive.CreateCapsuleY(2.0f, 0.5f); shape = scene.Factory.ShapeManager.Create("CapsuleY2"); shape.Set(shapePrimitive, Matrix4.Identity, 0.0f); shapePrimitive = scene.Factory.ShapePrimitiveManager.Create("CapsuleY3"); shapePrimitive.CreateCapsuleY(2.5f, 0.5f); shape = scene.Factory.ShapeManager.Create("CapsuleY3"); shape.Set(shapePrimitive, Matrix4.Identity, 0.0f); triangleMesh = scene.Factory.TriangleMeshManager.Create("CapsuleY1"); triangleMesh.CreateCapsuleY(10, 15, 1.5f, 1.0f); if (!demo.Meshes.ContainsKey("CapsuleY1")) { demo.Meshes.Add("CapsuleY1", new DemoMesh(demo, triangleMesh, demo.Textures["Default"], Vector2.One, true, true, true, false, true, CullFaceMode.Back, false, false)); } triangleMesh = scene.Factory.TriangleMeshManager.Create("CapsuleY2"); triangleMesh.CreateCapsuleY(10, 15, 2.0f, 0.5f); if (!demo.Meshes.ContainsKey("CapsuleY2")) { demo.Meshes.Add("CapsuleY2", new DemoMesh(demo, triangleMesh, demo.Textures["Default"], Vector2.One, true, true, true, false, true, CullFaceMode.Back, false, false)); } triangleMesh = scene.Factory.TriangleMeshManager.Create("CapsuleY3"); triangleMesh.CreateCapsuleY(10, 15, 2.5f, 0.5f); if (!demo.Meshes.ContainsKey("CapsuleY3")) { demo.Meshes.Add("CapsuleY3", new DemoMesh(demo, triangleMesh, demo.Textures["Default"], Vector2.One, true, true, true, false, true, CullFaceMode.Back, false, false)); } }
/// <summary> /// /// </summary> /// <remarks> /// For all of the shapes that has directions (e.g., Cylinder, Hemisphere), Y direction is /// used, so if you would like it to face other directions, use MataliObject.ShapeOriginalMatrix /// to orient them. /// /// For a cylinder with different bottom and top radius, IPhysicsObject.ShapeData are used. /// ShapeData[0] - bottom radius, ShapeData[1] - height, ShapeData[2] = top radius /// /// For Compound shape, an additional information can be set by using /// MataliObject.CompoundShape. /// /// For additional shape types such as Heightmap, Point, and so on, set Shape to ShapeType.Extra /// and define MataliObject.ExtraShape. /// </remarks> /// <param name="mataliPhysicsObj"></param> /// <param name="physObj"></param> private void SetShape(MataliPhysicsObject mataliPhysicsObj, IPhysicsObject physObj) { Vector3 boundingBox = Vector3.Zero; if (physObj.Model != null) { boundingBox = Vector3Helper.GetDimensions(physObj.Model.MinimumBoundingBox); } Vector3 size = Vector3.Zero; MataliObject mataliObj = null; if (physObj is MataliObject) { mataliObj = (MataliObject)physObj; } switch (physObj.Shape) { case ShapeType.Box: if (physObj.ShapeData.Count == 3) { size = new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]); } else { size = boundingBox; } size /= 2; break; case ShapeType.Sphere: if (physObj.ShapeData.Count == 1) { size = new Vector3(physObj.ShapeData[0], 0, 0); } else { size = boundingBox / 2; } break; case ShapeType.Cone: case ShapeType.Cylinder: case ShapeType.Capsule: if (physObj.ShapeData.Count == 2) { size = new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[0]); } else if (physObj.ShapeData.Count == 3) { size = new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]); } else { size = new Vector3(boundingBox.X / 2, boundingBox.Y, boundingBox.X / 2); } break; case ShapeType.Compound: // size is used solely for naming, not used for the collision shape size = new Vector3(physObj.ShapeData.Count, physObj.ShapeData[0], physObj.ShapeData[physObj.ShapeData.Count - 1]); break; case ShapeType.ConvexHull: // size is used solely for naming, not used for the collision shape size = new Vector3(physObj.MeshProvider.Vertices.Count, physObj.MeshProvider.Indices.Count, physObj.MeshProvider.Vertices[0].X); break; case ShapeType.Extra: if (mataliObj == null) { throw new GoblinException("For extra shape type, you need to define the 'physObj' " + "as MataliObject instance"); } if (mataliObj.ExtraShape == ExtraShapeType.Undefined) { throw new GoblinException("Undefined type is not allowed if Extra shape type is specified"); } // size is used solely for naming, not used for the collision shape switch (mataliObj.ExtraShape) { case ExtraShapeType.Point: if (physObj.ShapeData.Count != 3) { throw new GoblinException("For Point shape type, you need to specify the position (x,y,z) in ShapeData"); } size = new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]); break; case ExtraShapeType.Heightmap: if (physObj.ShapeData.Count < 2) { throw new GoblinException("There needs to be at least two floats specifying the " + "width and height"); } size = new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData.Count); break; case ExtraShapeType.Edge: if (physObj.ShapeData.Count != 6) { throw new GoblinException("For Edge shape type, you need to specify the start and " + "end positions (x,y,z) in ShapeData"); } size = new Vector3(physObj.ShapeData[0] + physObj.ShapeData[3], physObj.ShapeData[1] + physObj.ShapeData[4], physObj.ShapeData[2] + physObj.ShapeData[5]); break; default: throw new GoblinException(mataliObj.ExtraShape.ToString() + " not implemented yet"); } break; } String shapeName = physObj.Shape.ToString() + size.ToString(); String primitiveName = physObj.Shape.ToString() + size.ToString(); if (mataliObj != null) { String suffix = ""; if (physObj.Shape == ShapeType.Extra) { suffix += mataliObj.ExtraShape.ToString(); } else if (physObj.Shape == ShapeType.Compound) { suffix += mataliObj.CompoundShape.ToString(); } suffix += mataliObj.ShapeOriginalMatrix.ToString(); suffix += mataliObj.ShapeCollisionMargin; shapeName += suffix; primitiveName += suffix; } Shape shape = null; ShapePrimitive primitive = null; if (scene.Factory.ShapeManager.Contains(shapeName)) { shape = scene.Factory.ShapeManager.Find(shapeName); } else { if (physObj.Shape != ShapeType.Compound) { primitive = scene.Factory.ShapePrimitiveManager.Create(primitiveName); } shape = scene.Factory.ShapeManager.Create(shapeName); bool shapeSet = false; switch (physObj.Shape) { case ShapeType.Box: primitive.CreateBox(size.X, size.Y, size.Z); break; case ShapeType.Sphere: primitive.CreateSphere(size.X); break; case ShapeType.Cone: primitive.CreateConeY(size.Y, size.X); break; case ShapeType.Cylinder: if (size.X != size.Z) { primitive.CreateCylinder2RY(size.Y, size.X, size.Z); } else { primitive.CreateCylinderY(size.Y, size.X); } break; case ShapeType.Capsule: primitive.CreateCapsuleY(size.Y - size.X * 2, size.X); break; case ShapeType.Compound: ShapeCompoundType type = ShapeCompoundType.ConvexHull; if (mataliObj != null) { if (mataliObj.CompoundShape == CompoundShapeType.MinkowskiSum) { type = ShapeCompoundType.MinkowskiSum; } } int dataIndex = 0; Shape compoundShapePart = null; ShapePrimitive compoundPrimitive = null; float[] matrixVals = new float[16]; while (dataIndex < physObj.ShapeData.Count) { ShapeType shapeType = (ShapeType)Enum.ToObject(typeof(ShapeType), (int)physObj.ShapeData[dataIndex++]); switch (shapeType) { case ShapeType.Cylinder: size = new Vector3(physObj.ShapeData[dataIndex], physObj.ShapeData[dataIndex + 1], physObj.ShapeData[dataIndex]); dataIndex += 2; break; case ShapeType.Sphere: size = new Vector3(physObj.ShapeData[dataIndex], 0, 0); dataIndex++; break; } shapeName = shapeType.ToString() + size.ToString(); primitiveName = shapeType.ToString() + size.ToString(); if (scene.Factory.ShapeManager.Contains(shapeName)) { compoundShapePart = scene.Factory.ShapeManager.Find(shapeName); } else { compoundPrimitive = scene.Factory.ShapePrimitiveManager.Create(primitiveName); compoundShapePart = scene.Factory.ShapeManager.Create(shapeName); switch (shapeType) { case ShapeType.Cylinder: compoundPrimitive.CreateCylinderY(size.Y, size.X); break; case ShapeType.Sphere: compoundPrimitive.CreateSphere(size.X); break; default: throw new GoblinException(shape.ToString() + " is not supported yet as a compound part"); } compoundShapePart.Set(compoundPrimitive, Matrix.Identity, 0.0f); } for (int i = 0; i < 16; ++i) { matrixVals[i] = physObj.ShapeData[dataIndex + i]; } dataIndex += 16; shape.Add(compoundShapePart, MatrixHelper.FloatsToMatrix(matrixVals), 0.0f, type); } float margin = 0.0f; if (mataliObj != null) { margin = mataliObj.ShapeCollisionMargin; } shape.CreateMesh(margin); shapeSet = true; break; case ShapeType.ConvexHull: case ShapeType.TriangleMesh: float[] frictions = null; float[] restitutions = null; if (physObj.Shape == ShapeType.ConvexHull) { primitive.CreateConvex(physObj.MeshProvider.Vertices); } else { int triangleCount = physObj.MeshProvider.Indices.Count / 3; frictions = new float[triangleCount]; restitutions = new float[triangleCount]; for (int i = 0; i < frictions.Length; i++) { frictions[i] = 1.0f; restitutions[i] = 0.0f; } Vector3[] triVerts = new Vector3[physObj.MeshProvider.Indices.Count]; for (int i = 0; i < triVerts.Length; ++i) { triVerts[i] = physObj.MeshProvider.Vertices[physObj.MeshProvider.Indices[i]]; } bool flipTriangle = (physObj is MataliObject) ? ((MataliObject)physObj).FlipTriangleOrder : true; primitive.CreateTriangleMesh(triVerts, flipTriangle, 2, frictions, restitutions, 1.0f, 0.0f); } break; case ShapeType.Extra: switch (mataliObj.ExtraShape) { case ExtraShapeType.Heightmap: int width = (int)physObj.ShapeData[0]; int height = (int)physObj.ShapeData[1]; float[] heightData = new float[height * width]; float[] heightFrictions = new float[height * width]; float[] heightRestituions = new float[height * width]; if (physObj.ShapeData.Count < (2 + heightData.Length)) { throw new GoblinException("You also need to specify the hegith map data"); } Buffer.BlockCopy(physObj.ShapeData.ToArray(), 2 * sizeof(float), heightData, 0, heightData.Length * sizeof(float)); if (physObj.ShapeData.Count > (2 + heightData.Length * 2)) { Buffer.BlockCopy(physObj.ShapeData.ToArray(), (2 + heightData.Length) * sizeof(float), heightFrictions, 0, heightFrictions.Length * sizeof(float)); } else { for (int i = 0; i < heightFrictions.Length; ++i) { heightFrictions[i] = mataliObj.TriangleMeshFriction; } } if (physObj.ShapeData.Count > (2 + heightData.Length * 3)) { Buffer.BlockCopy(physObj.ShapeData.ToArray(), (2 + heightData.Length * 2) * sizeof(float), heightRestituions, 0, heightRestituions.Length * sizeof(float)); } else { for (int i = 0; i < heightRestituions.Length; ++i) { heightRestituions[i] = mataliObj.TriangleMeshRestitution; } } primitive.CreateHeightmap(0, 0, width, height, width, height, heightData, heightFrictions, heightRestituions, mataliObj.TriangleMeshFriction, mataliObj.TriangleMeshRestitution, mataliObj.IsDynamic); shape.Set(primitive, mataliObj.ShapeOriginalMatrix, mataliObj.ShapeCollisionMargin); shape.CreateMesh(0.0f); shapeSet = true; mataliPhysicsObj.InternalControllers.CreateHeightmapController(true); break; case ExtraShapeType.Point: primitive.CreatePoint(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]); break; case ExtraShapeType.Edge: primitive.CreateEdge(new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]), new Vector3(physObj.ShapeData[3], physObj.ShapeData[4], physObj.ShapeData[5])); break; case ExtraShapeType.Plane: primitive.CreatePlaneY(physObj.ShapeData[0], (physObj.ShapeData[1] > 0)); break; case ExtraShapeType.Triangle: primitive.CreateTriangle( new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]), new Vector3(physObj.ShapeData[3], physObj.ShapeData[4], physObj.ShapeData[5]), new Vector3(physObj.ShapeData[6], physObj.ShapeData[7], physObj.ShapeData[8])); break; case ExtraShapeType.Tetrahedron: primitive.CreateTetrahedron( new Vector3(physObj.ShapeData[0], physObj.ShapeData[1], physObj.ShapeData[2]), new Vector3(physObj.ShapeData[3], physObj.ShapeData[4], physObj.ShapeData[5]), new Vector3(physObj.ShapeData[6], physObj.ShapeData[7], physObj.ShapeData[8]), new Vector3(physObj.ShapeData[9], physObj.ShapeData[10], physObj.ShapeData[11])); break; case ExtraShapeType.Fluid: break; case ExtraShapeType.Hemisphere: primitive.CreateHemisphereY(physObj.ShapeData[0]); break; } break; } if (!shapeSet) { if (mataliObj != null) { shape.Set(primitive, mataliObj.ShapeOriginalMatrix, mataliObj.ShapeCollisionMargin); } else { shape.Set(primitive, Matrix.Identity, 0.0f); } if (buildCollisionMesh) { float margin = 0.0f; if (mataliObj != null) { margin = mataliObj.ShapeCollisionMargin; } shape.CreateMesh(margin); } } } mataliPhysicsObj.Shape = shape; }