public void ReadSphere(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Vector3 scaleDelta = transform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) { log.Error("Scale is not currently supported for sphere shapes"); } float radius = 0; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "radius": radius = float.Parse(childNode.InnerText); break; default: DebugMessage(childNode); break; } } Vector3 center = unitConversion * transform.Translation; radius *= unitConversion; CollisionShape collisionShape = new CollisionSphere(center, radius); physicsData.AddCollisionShape(objectId, collisionShape); }
public void ExportPhysics(PhysicsData physicsData, Stream stream) { XmlDocument document = new XmlDocument(); XmlNode node = Write(document, physicsData); document.AppendChild(node); document.Save(stream); }
public void ExportPhysics(PhysicsData physicsData, string filename) { Stream outStream = new FileStream(filename, FileMode.Create); try { ExportPhysics(physicsData, outStream); } finally { outStream.Close(); } }
public void ImportPhysics(PhysicsData physicsData, string filename) { Stream inStream = new FileStream(filename, FileMode.Open); try { ImportPhysics(physicsData, inStream); } finally { inStream.Close(); } }
public void ReadCapsule(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Quaternion rot = MathHelpers.GetRotation(transform); Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform; Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) { log.Error("Scale is not currently supported for capsule shapes"); } float height = 0; float[] radius = new float[2]; Vector3 halfExtents = Vector3.Zero; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "height": height = float.Parse(childNode.InnerText); break; case "radius": { string[] values = childNode.InnerText.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); Debug.Assert(values.Length == 2); for (int i = 0; i < 2; ++i) { radius[i] = float.Parse(values[i]); } } break; default: DebugMessage(childNode); break; } } // We only support capsules where the two radii match if (radius[0] != radius[1]) { log.Error("Different radii for capsules are not currently supported"); } Vector3 center = unitConversion * transform.Translation; Vector3 halfExtent = unitConversion * (.5f * height * (rot * Vector3.UnitY)); radius[0] *= unitConversion; radius[1] *= unitConversion; CollisionShape collisionShape; collisionShape = new CollisionCapsule(center - halfExtent, center + halfExtent, radius[0]); physicsData.AddCollisionShape(objectId, collisionShape); }
public XmlNode Write(XmlDocument document, PhysicsData physicsData) { XmlNode node = document.CreateElement("physics_model"); foreach (string objectId in physicsData.GetCollisionObjects()) { XmlNode childNode = WriteRigidBody(objectId, document, physicsData); node.AppendChild(childNode); } return(node); }
public XmlNode WriteRigidBody(string objectId, XmlDocument document, PhysicsData physicsData) { XmlNode node = document.CreateElement("rigid_body"); XmlAttribute attr = document.CreateAttribute("sid"); attr.Value = objectId; node.Attributes.Append(attr); XmlNode childNode = WriteRigidBody_TechniqueCommon(objectId, document, physicsData); node.AppendChild(childNode); return(node); }
public void ReadBox(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Quaternion rot = MathHelpers.GetRotation(transform); Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform; Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) { log.Error("Scale is not currently supported for box shapes"); } Vector3 halfExtents = Vector3.Zero; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "half_extents": ReadVector(ref halfExtents, childNode); break; default: DebugMessage(childNode); break; } } Vector3 center = unitConversion * transform.Translation; halfExtents *= unitConversion; CollisionShape collisionShape; float angle = 0; Vector3 axis = Vector3.Zero; rot.ToAngleAxis(ref angle, ref axis); // I could build AABB shapes for boxes that are aligned, but then // I can't drop instances in the world with arbitrary rotations. // Instead, just always use an OBB. //if (angle < PhysicsSerializer.RotateEpsilon) { // collisionShape = new CollisionAABB(center - halfExtents, center + halfExtents); //} else { // TODO: I'm not sure I understand the OBB constructor Vector3[] axes = new Vector3[3]; axes[0] = rot.XAxis; axes[1] = rot.YAxis; axes[2] = rot.ZAxis; collisionShape = new CollisionOBB(center, axes, halfExtents); physicsData.AddCollisionShape(objectId, collisionShape); }
public void ReadRigidBody_TechniqueCommon(string objectId, XmlNode node, PhysicsData physicsData) { foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "shape": ReadShape(objectId, childNode, physicsData); break; default: DebugMessage(childNode); break; } } }
public void ReadPhysicsModel(XmlNode node, PhysicsData physicsData) { foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "rigid_body": ReadRigidBody(childNode, physicsData); break; default: DebugMessage(childNode); break; } } }
public void ReadRigidBody(XmlNode node, PhysicsData physicsData) { string objectId = node.Attributes["sid"].Value; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "technique_common": ReadRigidBody_TechniqueCommon(objectId, childNode, physicsData); break; default: DebugMessage(childNode); break; } } }
public void ImportPhysics(PhysicsData physicsData, Stream stream) { XmlDocument document = new XmlDocument(); document.Load(stream); foreach (XmlNode childNode in document.ChildNodes) { switch (childNode.Name) { case "physics_model": ReadPhysicsModel(childNode, physicsData); break; default: DebugMessage(childNode); break; } } }
public void ReadShape(string objectId, XmlNode node, PhysicsData physicsData) { List <NamedTransform> transformChain = new List <NamedTransform>(); foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "rotate": { float angle = 0; Vector3 axis = Vector3.UnitY; ReadRotate(ref angle, ref axis, childNode); transformChain.Add(new NamedRotateTransform(null, angle, axis)); } break; case "scale": { Vector3 scale = Vector3.UnitScale; ReadVector(ref scale, childNode); transformChain.Add(new NamedScaleTransform(null, scale)); } break; case "translate": { Vector3 translation = Vector3.Zero; ReadVector(ref translation, childNode); transformChain.Add(new NamedTranslateTransform(null, translation)); } break; case "box": { Matrix4 transform = Matrix4.Identity; foreach (NamedTransform t in transformChain) { transform = t.Transform * transform; Debug.Assert(transform != Matrix4.Zero); } ReadBox(objectId, transform, childNode, physicsData); } break; case "sphere": { Matrix4 transform = Matrix4.Identity; foreach (NamedTransform t in transformChain) { transform = t.Transform * transform; Debug.Assert(transform != Matrix4.Zero); } ReadSphere(objectId, transform, childNode, physicsData); } break; case "capsule": { Matrix4 transform = Matrix4.Identity; foreach (NamedTransform t in transformChain) { transform = t.Transform * transform; Debug.Assert(transform != Matrix4.Zero); } ReadCapsule(objectId, transform, childNode, physicsData); } break; default: DebugMessage(childNode); break; } } }
private static void TestPhysics( string srcDir, string dstDir, string name ) { float OneMeter = 1000; PhysicsData pd = new PhysicsData(); Vector3 center = new Vector3( 10 * OneMeter, 1 * OneMeter, 1 * OneMeter ); Vector3[] obbAxes = new Vector3[ 3 ]; obbAxes[ 0 ] = new Vector3( 1, 0, -1 ); obbAxes[ 0 ].Normalize(); obbAxes[ 1 ] = Vector3.UnitY; obbAxes[ 2 ] = new Vector3( 1, 0, 1 ); obbAxes[ 2 ].Normalize(); Vector3 obbExtents = new Vector3( 2.5f * OneMeter, 1 * OneMeter, 1 * OneMeter ); CollisionOBB obb = new CollisionOBB( center, obbAxes, obbExtents ); pd.AddCollisionShape( "submesh01", obb ); CollisionAABB aabb = new CollisionAABB( center - obbExtents, center + obbExtents ); pd.AddCollisionShape( "submesh01", aabb ); CollisionSphere sphere = new CollisionSphere( center, 2 * OneMeter ); pd.AddCollisionShape( "submesh01", sphere ); Vector3 capExtents = new Vector3( -1 * OneMeter, 0, 0 ); CollisionCapsule capsule = new CollisionCapsule( center + capExtents, center - capExtents, .5f * OneMeter ); pd.AddCollisionShape( "submesh01", capsule ); PhysicsSerializer ps = new PhysicsSerializer(); ps.ExportPhysics( pd, name ); pd = new PhysicsData(); ps.ImportPhysics( pd, name ); foreach( string objectId in pd.GetCollisionObjects() ) { log.InfoFormat( "Collision shapes for: {0}", objectId ); List<CollisionShape> collisionShapes = pd.GetCollisionShapes( objectId ); foreach( CollisionShape shape in collisionShapes ) log.InfoFormat( "Shape: {0}", shape ); } }
public void ReadShape(string objectId, XmlNode node, PhysicsData physicsData) { List<NamedTransform> transformChain = new List<NamedTransform>(); foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "rotate": { float angle = 0; Vector3 axis = Vector3.UnitY; ReadRotate(ref angle, ref axis, childNode); transformChain.Add(new NamedRotateTransform(null, angle, axis)); } break; case "scale": { Vector3 scale = Vector3.UnitScale; ReadVector(ref scale, childNode); transformChain.Add(new NamedScaleTransform(null, scale)); } break; case "translate": { Vector3 translation = Vector3.Zero; ReadVector(ref translation, childNode); transformChain.Add(new NamedTranslateTransform(null, translation)); } break; case "box": { Matrix4 transform = Matrix4.Identity; foreach (NamedTransform t in transformChain) { transform = t.Transform * transform; Debug.Assert(transform != Matrix4.Zero); } ReadBox(objectId, transform, childNode, physicsData); } break; case "sphere": { Matrix4 transform = Matrix4.Identity; foreach (NamedTransform t in transformChain) { transform = t.Transform * transform; Debug.Assert(transform != Matrix4.Zero); } ReadSphere(objectId, transform, childNode, physicsData); } break; case "capsule": { Matrix4 transform = Matrix4.Identity; foreach (NamedTransform t in transformChain) { transform = t.Transform * transform; Debug.Assert(transform != Matrix4.Zero); } ReadCapsule(objectId, transform, childNode, physicsData); } break; default: DebugMessage(childNode); break; } } }
public void ReadBox(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Quaternion rot = MathHelpers.GetRotation(transform); Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform; Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) log.Error("Scale is not currently supported for box shapes"); Vector3 halfExtents = Vector3.Zero; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "half_extents": ReadVector(ref halfExtents, childNode); break; default: DebugMessage(childNode); break; } } Vector3 center = unitConversion * transform.Translation; halfExtents *= unitConversion; CollisionShape collisionShape; float angle = 0; Vector3 axis = Vector3.Zero; rot.ToAngleAxis(ref angle, ref axis); // I could build AABB shapes for boxes that are aligned, but then // I can't drop instances in the world with arbitrary rotations. // Instead, just always use an OBB. //if (angle < PhysicsSerializer.RotateEpsilon) { // collisionShape = new CollisionAABB(center - halfExtents, center + halfExtents); //} else { // TODO: I'm not sure I understand the OBB constructor Vector3[] axes = new Vector3[3]; axes[0] = rot.XAxis; axes[1] = rot.YAxis; axes[2] = rot.ZAxis; collisionShape = new CollisionOBB(center, axes, halfExtents); physicsData.AddCollisionShape(objectId, collisionShape); }
public void ReadSphere(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Vector3 scaleDelta = transform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) log.Error("Scale is not currently supported for sphere shapes"); float radius = 0; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "radius": radius = float.Parse(childNode.InnerText); break; default: DebugMessage(childNode); break; } } Vector3 center = unitConversion * transform.Translation; radius *= unitConversion; CollisionShape collisionShape = new CollisionSphere(center, radius); physicsData.AddCollisionShape(objectId, collisionShape); }
public void ReadCapsule(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Quaternion rot = MathHelpers.GetRotation(transform); Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform; Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) log.Error("Scale is not currently supported for capsule shapes"); float height = 0; float[] radius = new float[2]; Vector3 halfExtents = Vector3.Zero; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "height": height = float.Parse(childNode.InnerText); break; case "radius": { string[] values = childNode.InnerText.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); Debug.Assert(values.Length == 2); for (int i = 0; i < 2; ++i) radius[i] = float.Parse(values[i]); } break; default: DebugMessage(childNode); break; } } // We only support capsules where the two radii match if (radius[0] != radius[1]) log.Error("Different radii for capsules are not currently supported"); Vector3 center = unitConversion * transform.Translation; Vector3 halfExtent = unitConversion * (.5f * height * (rot * Vector3.UnitY)); radius[0] *= unitConversion; radius[1] *= unitConversion; CollisionShape collisionShape; collisionShape = new CollisionCapsule(center - halfExtent, center + halfExtent, radius[0]); physicsData.AddCollisionShape(objectId, collisionShape); }
public XmlNode WriteRigidBody_TechniqueCommon(string objectId, XmlDocument document, PhysicsData physicsData) { XmlNode node = document.CreateElement("technique_common"); List <CollisionShape> collisionShapes = physicsData.GetCollisionShapes(objectId); foreach (CollisionShape shape in collisionShapes) { XmlNode childNode = WriteShape(shape, document); node.AppendChild(childNode); } return(node); }
public XmlNode WriteRigidBody_TechniqueCommon(string objectId, XmlDocument document, PhysicsData physicsData) { XmlNode node = document.CreateElement("technique_common"); List<CollisionShape> collisionShapes = physicsData.GetCollisionShapes(objectId); foreach (CollisionShape shape in collisionShapes) { XmlNode childNode = WriteShape(shape, document); node.AppendChild(childNode); } return node; }
public XmlNode WriteRigidBody(string objectId, XmlDocument document, PhysicsData physicsData) { XmlNode node = document.CreateElement("rigid_body"); XmlAttribute attr = document.CreateAttribute("sid"); attr.Value = objectId; node.Attributes.Append(attr); XmlNode childNode = WriteRigidBody_TechniqueCommon(objectId, document, physicsData); node.AppendChild(childNode); return node; }
public XmlNode Write(XmlDocument document, PhysicsData physicsData) { XmlNode node = document.CreateElement("physics_model"); foreach (string objectId in physicsData.GetCollisionObjects()) { XmlNode childNode = WriteRigidBody(objectId, document, physicsData); node.AppendChild(childNode); } return node; }
/// <summary> /// Add the collision data for an object. This involves looking /// for a physics file that matches the mesh file's name, and /// loading the information from that file to build collision /// volumes. /// </summary> /// <param name="objNode">the object for which we are adding the collision data</param> private void AddCollisionObject(Entity modelEntity, SceneNode modelSceneNode, long oid, string physicsName) { // Create a set of collision shapes for the object List<CollisionShape> shapes = new List<CollisionShape>(); PhysicsData pd = new PhysicsData(); PhysicsSerializer ps = new PhysicsSerializer(); try { Stream stream = ResourceManager.FindCommonResourceData(physicsName); ps.ImportPhysics(pd, stream); for (int i=0; i<modelEntity.SubEntityCount; i++) { SubEntity subEntity = modelEntity.GetSubEntity(i); if (subEntity.IsVisible) { string submeshName = subEntity.SubMesh.Name; List<CollisionShape> subEntityShapes = pd.GetCollisionShapes(submeshName); foreach (CollisionShape subShape in subEntityShapes) { // static objects will be transformed here, but movable objects // are transformed on the fly subShape.Transform(modelSceneNode.DerivedScale, modelSceneNode.DerivedOrientation, modelSceneNode.DerivedPosition); shapes.Add(subShape); log.InfoFormat("Added collision shape: {0} for {1}", subShape, submeshName); } } } } catch (Exception e) { // Unable to load physics data -- use a sphere or no collision data? log.WarnFormat("Unable to load physics data: {0}", e); } foreach (CollisionShape shape in shapes) collisionManager.AddCollisionShape(shape, oid); }
/// <summary> /// Add the collision data for an object. This involves looking /// for a physics file that matches the mesh file's name, and /// loading the information from that file to build collision /// volumes. /// </summary> /// <param name="objNode">the object for which we are adding the collision data</param> public void AddCollisionObject(ObjectNode objNode) { if (worldManager.CollisionHelper == null) return; if (!objNode.UseCollisionObject) return; // Create a set of collision shapes for the object List<CollisionShape> shapes = new List<CollisionShape>(); string meshName = objNode.Entity.Mesh.Name; PhysicsData pd = new PhysicsData(); PhysicsSerializer ps = new PhysicsSerializer(); bool static_object = true; if ((objNode.ObjectType == ObjectNodeType.Npc) || (objNode.ObjectType == ObjectNodeType.User)) { static_object = false; } if (meshName.EndsWith(".mesh")) { string physicsName = meshName.Substring(0, meshName.Length - 5) + ".physics"; try { Stream stream = ResourceManager.FindCommonResourceData(physicsName); ps.ImportPhysics(pd, stream); foreach (SubEntity subEntity in objNode.Entity.SubEntities) { if (subEntity.IsVisible) { string submeshName = subEntity.SubMesh.Name; List<CollisionShape> subEntityShapes = pd.GetCollisionShapes(submeshName); foreach (CollisionShape subShape in subEntityShapes) { // static objects will be transformed here, but movable objects // are transformed on the fly if (static_object) subShape.Transform(objNode.SceneNode.DerivedScale, objNode.SceneNode.DerivedOrientation, objNode.SceneNode.DerivedPosition); shapes.Add(subShape); log.DebugFormat("Added collision shape for oid {0}, subShape {1}, subMesh {2}", objNode.Oid, subShape, submeshName); } } } // Now populate the region volumes foreach (KeyValuePair<string, List<CollisionShape>> entry in pd.CollisionShapes) { string regionName = RegionVolumes.ExtractRegionName(entry.Key); if (regionName != "") { // We must record this region - - must be // a static object Debug.Assert(static_object); List<CollisionShape> subShapes = new List<CollisionShape>(); foreach (CollisionShape subShape in entry.Value) { subShape.Transform(objNode.SceneNode.DerivedScale, objNode.SceneNode.DerivedOrientation, objNode.SceneNode.DerivedPosition); subShapes.Add(subShape); } RegionVolumes.Instance.AddRegionShapes(objNode.Oid, regionName, subShapes); } } } catch (Exception) { // Unable to load physics data -- use a sphere or no collision data? log.InfoFormat("Unable to load physics data: {0}", physicsName); //// For now, I'm going to put in spheres. Later I should do something real. //CollisionShape shape = new CollisionSphere(Vector3.Zero, Client.OneMeter); //if (static_object) // // static objects will be transformed here, but movable objects // // are transformed on the fly // shape.Transform(objNode.SceneNode.DerivedScale, // objNode.SceneNode.DerivedOrientation, // objNode.SceneNode.DerivedPosition); //shapes.Add(shape); } } if (static_object) { foreach (CollisionShape shape in shapes) worldManager.CollisionHelper.AddCollisionShape(shape, objNode.Oid); objNode.CollisionShapes = shapes; } else { MovingObject mo = new MovingObject(worldManager.CollisionHelper); foreach (CollisionShape shape in shapes) worldManager.CollisionHelper.AddPartToMovingObject(mo, shape); objNode.Collider = mo; objNode.Collider.Transform(objNode.SceneNode.DerivedScale, objNode.SceneNode.DerivedOrientation, objNode.SceneNode.DerivedPosition); } }
/// <summary> /// Return the untransformed collision shapes associated /// with a mesh. If they are already encached, return them, /// else look for a physics file that matches the mesh /// file's name, and load the information from that file to /// build the collision shapes. /// </summary> public List<CollisionShape> FindMeshCollisionShapes(string meshName, Entity entity) { if (collisionManager == null) { Axiom.Core.LogManager.Instance.Write("DisplayObject.collisionManager is null!"); return null; } List<CollisionShape> shapes; if (!WorldEditor.Instance.MeshCollisionShapes.TryGetValue(meshName, out shapes)) { string physicsName = Path.GetFileNameWithoutExtension(meshName) + ".physics"; // Create a set of collision shapes for the object shapes = new List<CollisionShape>(); PhysicsData pd = new PhysicsData(); PhysicsSerializer ps = new PhysicsSerializer(); try { Stream stream = ResourceManager.FindCommonResourceData(physicsName); ps.ImportPhysics(pd, stream); for (int i = 0; i < entity.SubEntityCount; i++) { SubEntity subEntity = entity.GetSubEntity(i); if (subEntity.IsVisible) { string submeshName = subEntity.SubMesh.Name; List<CollisionShape> subEntityShapes = pd.GetCollisionShapes(submeshName); foreach (CollisionShape subShape in subEntityShapes) { // Clone the shape, and add to the list of // untransformed shapes shapes.Add(subShape); } } } } catch (Exception e) { // Unable to load physics data -- use a sphere or no collision data? Axiom.Core.LogManager.Instance.Write("Unable to load physics data: " + e); shapes = new List<CollisionShape>(); } WorldEditor.Instance.MeshCollisionShapes[meshName] = shapes; } List<CollisionShape> newShapes = new List<CollisionShape>(); foreach (CollisionShape shape in shapes) newShapes.Add(shape.Clone()); return newShapes; }
public static void ExtractCollisionShapes( Mesh mesh, string path ) { PhysicsData physicsData = null; List<string> deleteEm = new List<string>(); int count = mesh.SubMeshCount; for( int i = 0; i < count; i++ ) { SubMesh subMesh = mesh.GetSubMesh( i ); CollisionShape shape = null; string targetName = null; bool cv = String.Compare( subMesh.Name.Substring( 0, 5 ), "mvcv_", false ) == 0; bool rg = String.Compare( subMesh.Name.Substring( 0, 5 ), "mvrg_", false ) == 0; int firstIndex = 0; if( cv ) firstIndex = 5; else if( rg ) { string rest = subMesh.Name.Substring( 5 ); firstIndex = rest.IndexOf( "_" ) + 1 + 5; } if( cv || rg ) { // It's probably a collision volume - - check the // shape type to make sure if( String.Compare( subMesh.Name.Substring( firstIndex, 4 ), "obb_", false ) == 0 ) { shape = ExtractBox( subMesh ); } else if( String.Compare( subMesh.Name.Substring( firstIndex, 5 ), "aabb_", false ) == 0 ) { shape = ExtractBox( subMesh ); } else if( String.Compare( subMesh.Name.Substring( firstIndex, 7 ), "sphere_", false ) == 0 ) { shape = ExtractSphere( subMesh ); } else if( String.Compare( subMesh.Name.Substring( firstIndex, 8 ), "capsule_", false ) == 0 ) { shape = ExtractCapsule( subMesh ); } if( shape != null ) targetName = GetTargetSubmesh( mesh, subMesh.Name ); } if( shape != null ) { deleteEm.Add( subMesh.Name ); if( physicsData == null ) physicsData = new PhysicsData(); physicsData.AddCollisionShape( targetName, shape ); } } for( int i = 0; i < deleteEm.Count; i++ ) { mesh.RemoveSubMesh( deleteEm[ i ] ); } if( physicsData != null ) { PhysicsSerializer serializer = new PhysicsSerializer(); serializer.ExportPhysics( physicsData, path + ".physics" ); } if( DoLog ) CloseLog(); }