/// <summary> /// Add vertex and index sets of a mesh to the builder. /// </summary> /// <param name="mesh">The mesh object.</param> /// <param name="lodIndex">The LOD level to be processed.</param> public void AddObject( Mesh mesh, int lodIndex ) { if ( mesh == null ) throw new ArgumentNullException(); //mesh.AddVertexAndIndexSets(this, lodIndex); //NOTE: The Mesh.AddVertexAndIndexSets() assumes there weren't any vertex data added to the builder yet. //For this class I decided to break that assumption, thus using following replacement for the commented call. //I guess rarely, but still you might want to add vertex/index sets of several objects to one builder. //Maybe AddVertexAndIndexSets could be removed and this method utilized back in Mesh. //TODO: find out whether custom index buffer needs to be created in cases (like in the AddObject(IRenderable)). //Borrilis, do you know? int vertexSetCount = vertexDataList.Count; int indexOfSharedVertexSet = vertexSetCount; if ( mesh.SharedVertexData != null ) { AddVertexData( mesh.SharedVertexData ); vertexSetCount++; } // Prepare the builder using the submesh information for ( int i = 0; i < mesh.SubMeshCount; i++ ) { SubMesh sm = mesh.GetSubMesh( i ); if ( sm.useSharedVertices ) { // Use shared vertex data if ( lodIndex == 0 ) { AddIndexData( sm.IndexData, indexOfSharedVertexSet, sm.OperationType ); } else { AddIndexData( sm.LodFaceList[ lodIndex - 1 ], indexOfSharedVertexSet, sm.OperationType ); } } else { // own vertex data, add it and reference it directly AddVertexData( sm.VertexData ); if ( lodIndex == 0 ) { // base index data AddIndexData( sm.IndexData, vertexSetCount++, sm.OperationType ); } else { // LOD index data AddIndexData( sm.LodFaceList[ lodIndex - 1 ], vertexSetCount++, sm.OperationType ); } } } }
public static Mesh CopyMesh(Mesh mesh) { Mesh newMesh = new Mesh(mesh.Name); if (mesh.Skeleton != null) newMesh.NotifySkeleton(mesh.Skeleton); newMesh.SetVertexBufferPolicy(mesh.VertexBufferUsage, mesh.UseVertexShadowBuffer); newMesh.SetIndexBufferPolicy(mesh.IndexBufferUsage, mesh.UseIndexShadowBuffer); // this sets bounding radius as well newMesh.BoundingBox = mesh.BoundingBox; MeshUtility meshUtility = new MeshUtility(); for (int i = 0; i < mesh.SubMeshCount; ++i) meshUtility.AddSubmeshData(mesh.GetSubMesh(i)); // This should be done after we finish with the lod stuff newMesh.AutoBuildEdgeLists = true; newMesh.BuildEdgeList(); foreach (AttachmentPoint ap in mesh.AttachmentPoints) newMesh.AttachmentPoints.Add(new AttachmentPoint(ap)); for (int i = 0; i < mesh.SubMeshCount; ++i) { SubMesh srcSubMesh = mesh.GetSubMesh(i); SubMesh dstSubMesh = newMesh.CreateSubMesh(srcSubMesh.Name); CopySubMesh(dstSubMesh, srcSubMesh, meshUtility.subMeshDataMap[srcSubMesh.Name]); } if (mesh.SharedVertexData != null) { newMesh.SharedVertexData = new VertexData(); CopyVertexData(newMesh.SharedVertexData, mesh.SharedVertexData, meshUtility.sharedSubMeshData.VertexIdMap); CopyBoneAssignments(newMesh, mesh, meshUtility.sharedSubMeshData.VertexIdMap); } // newMesh.CompileBoneAssignments(); return newMesh; }
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(); }
// This attempts to parse a CV name and get the name of a matching submesh // defined in the Axiom mesh. This is tailored to ideosyncrasities in how // the 3dsMax COLLADA exporter mangles names. I'm not sure exactly what it // does, but it has something to do with inserting a suffix like '-lib' at // or near the end of the CV mesh name. // // Return a target submesh name, or String.Empty if either we cannot parse // the name satisfactorily, or the target is not found. private static string GetTargetSubmeshMaxStyle( Mesh mesh, string collisionSubmesh ) { const string mesh_pattern = "(.*)-(lib|obj|mesh)\\.([0-9]+)"; const string cv_prefix = "mvcv_(obb|aabb|sphere|capsule)_"; Regex mvcv_regex = new Regex( cv_prefix + mesh_pattern ); Match mvcvMatch = mvcv_regex.Match( collisionSubmesh ); if( !mvcvMatch.Success || mvcvMatch.Groups.Count < 3 ) { if( DoLog ) { Log( string.Format( "Unexpected collision volume name: {0}", collisionSubmesh ) ); } return String.Empty; } string mvcv_target = mvcvMatch.Groups[ 2 ].Value; for( int i = 0; i < mesh.SubMeshCount; ++i ) { string submeshName = mesh.GetSubMesh( i ).Name; // strip off the -obj.0 part Regex submesh_regex = new Regex( mesh_pattern ); Match submeshMatch = submesh_regex.Match( submeshName ); if( !submeshMatch.Success || submeshMatch.Groups.Count < 2 ) { continue; } string shortName = submeshMatch.Groups[ 1 ].Value; if( mvcv_target.StartsWith( shortName, StringComparison.CurrentCultureIgnoreCase ) ) { return submeshName; } } if( DoLog ) { Log( string.Format( "Failed to find target submesh for {0}", collisionSubmesh ) ); } return String.Empty; }
// Look for a target submesh assuming that the COLLADA exporter did not // do any special name mangling. I've tested this against files emitted // from Maya; I expect it will work for DAE files from other sources, too, // such as Blender or XSI. Time will tell... private static string GetTargetSubmeshGeneralStyle( Mesh mesh, string collisionSubmesh ) { string targetName = String.Empty; CvNameParser parser = new CvNameParser(); parser.AnalyzeName( collisionSubmesh ); if( parser.IsValid ) { // Form the target name as the first submesh name and see if // there is actually matching submesh. string candidate = parser.Target + ".0"; for( int i = 0; i < mesh.SubMeshCount; i++ ) { if( mesh.GetSubMesh( i ).Name.Equals( candidate ) ) { targetName = candidate; break; } } } return targetName; }