public void Push_Tri(FaceVertex A, FaceVertex B, FaceVertex C, Model_Prefab_Transform[] transforms) { if (transforms != null) { foreach (var trans in transforms) { switch (trans) { case Model_Prefab_Transform.Flip_X: case Model_Prefab_Transform.Flip_Y: case Model_Prefab_Transform.Flip_Z: FaceVertex vA = A, vB = B, vC = C; A = vA; B = vC; C = vB; break; default: throw new NotImplementedException($"Model_Prefab_Transform: {Enum.GetName(typeof(Model_Prefab_Transform), trans)} is not yet implemented!"); break; } } } this.Push(A, transforms); this.Push(B, transforms); this.Push(C, transforms); }
private Vector3 ComputeNormal(FaceVertex v1, FaceVertex v2, FaceVertex v3) { Vector3 pos1 = Positions[v1.PositionIndex - 1]; Vector3 pos2 = Positions[v2.PositionIndex - 1]; Vector3 pos3 = Positions[v3.PositionIndex - 1]; return(Vector3.Normalize(Vector3.Cross(pos1 - pos2, pos1 - pos3))); }
private vec3 ComputeNormal(FaceVertex v1, FaceVertex v2, FaceVertex v3) { vec3 pos1 = Positions[v1.PositionIndex - 1]; vec3 pos2 = Positions[v2.PositionIndex - 1]; vec3 pos3 = Positions[v3.PositionIndex - 1]; return(glm.normalize(vec3.Cross(pos1 - pos2, pos1 - pos3))); }
public Face(FaceVertex v0, FaceVertex v1, FaceVertex v2, int smoothingGroup = -1) { Vertex0 = v0; Vertex1 = v1; Vertex2 = v2; SmoothingGroup = smoothingGroup; }
/// <summary> /// Computes face adjacency for the whole mesh and stores it in the appropriate dictionaries. /// </summary> public void ComputeFaceAdjacency() { foreach (MeshFace face in mesh.Faces) { foreach (MeshVertex adjacent in face.AdjacentVertices()) { if (!FaceVertex.ContainsKey(face.Index)) { FaceVertex.Add(face.Index, new List <int>() { adjacent.Index }); } else { FaceVertex[face.Index].Add(adjacent.Index); } } foreach (MeshFace adjacent in face.AdjacentFaces()) { if (!FaceFace.ContainsKey(face.Index)) { FaceFace.Add(face.Index, new List <int>() { adjacent.Index }); } else { FaceFace[face.Index].Add(adjacent.Index); } } foreach (MeshEdge adjacent in face.AdjacentEdges()) { if (!FaceEdge.ContainsKey(face.Index)) { FaceEdge.Add(face.Index, new List <int>() { adjacent.Index }); } else { FaceEdge[face.Index].Add(adjacent.Index); } } } }
public uint GetOrCreate( Dictionary <FaceVertex, uint> vertexMap, FastList <VertexPosTexNorm> vertices, FaceVertex key, FaceVertex adjacent1, FaceVertex adjacent2) { uint index; if (!vertexMap.TryGetValue(key, out index)) { VertexPosTexNorm vertex = ConstructVertex(key, adjacent1, adjacent2); vertices.Add(vertex); index = checked ((uint)(vertices.Count - 1)); vertexMap.Add(key, index); } return(index); }
private VertexPositionNormalTexture ConstructVertex(FaceVertex key, FaceVertex adjacent1, FaceVertex adjacent2) { Vector3 position = Positions[key.PositionIndex - 1]; Vector3 normal; if (key.NormalIndex == -1) { normal = ComputeNormal(key, adjacent1, adjacent2); } else { normal = Normals[key.NormalIndex - 1]; } Vector2 texCoord = key.TexCoordIndex == -1 ? Vector2.Zero : TexCoords[key.TexCoordIndex - 1]; return(new VertexPositionNormalTexture(position, normal, texCoord)); }
private VertexPosTexNorm ConstructVertex(FaceVertex key, FaceVertex adjacent1, FaceVertex adjacent2) { vec3 position = Positions[key.PositionIndex - 1]; vec3 normal; if (key.NormalIndex == -1) { normal = ComputeNormal(key, adjacent1, adjacent2); } else { normal = Normals[key.NormalIndex - 1]; } vec2 texCoord = key.TexCoordIndex == -1 ? vec2.Zero : TexCoords[key.TexCoordIndex - 1]; return(new VertexPosTexNorm(position, texCoord, normal)); }
private ushort GetOrCreate( Dictionary <FaceVertex, ushort> vertexMap, List <VertexPositionNormalTexture> vertices, FaceVertex key, FaceVertex adjacent1, FaceVertex adjacent2) { ushort index; if (!vertexMap.TryGetValue(key, out index)) { VertexPositionNormalTexture vertex = ConstructVertex(key, adjacent1, adjacent2); vertices.Add(vertex); index = checked ((ushort)(vertices.Count - 1)); vertexMap.Add(key, index); } return(index); }
private FaceVertex ParseFaceVertex(string vertexString) { var fields = vertexString.Split(new[] { '/' }, StringSplitOptions.None); var vertexIndex = fields[0].ParseInvariantInt(); var faceVertex = new FaceVertex(vertexIndex, 0, 0); if (fields.Length > 1) { var textureIndex = fields[1].Length == 0 ? 0 : fields[1].ParseInvariantInt(); faceVertex.TextureIndex = textureIndex; } if (fields.Length > 2) { var normalIndex = fields.Length > 2 && fields[2].Length == 0 ? 0 : fields[2].ParseInvariantInt(); faceVertex.NormalIndex = normalIndex; } return(faceVertex); }
// Returns true on success, false if it was a degenerate triangle public bool AddTriangle(FaceVertex v0, FaceVertex v1, FaceVertex v2) { AddVertexResult vb_id_0 = m_addVertex(v0); AddVertexResult vb_id_1 = m_addVertex(v1); AddVertexResult vb_id_2 = m_addVertex(v2); // Degenerate check if (vb_id_0.CombinedVertexIndex == vb_id_1.CombinedVertexIndex || vb_id_0.CombinedVertexIndex == vb_id_2.CombinedVertexIndex || vb_id_1.CombinedVertexIndex == vb_id_2.CombinedVertexIndex) { return(false); } m_combined_vertlist.Add(vb_id_0.CombinedVertexIndex); m_combined_vertlist.Add(vb_id_1.CombinedVertexIndex); m_combined_vertlist.Add(vb_id_2.CombinedVertexIndex); m_submesh_vertlist.Add(vb_id_0.SubmeshVertexIndex); m_submesh_vertlist.Add(vb_id_1.SubmeshVertexIndex); m_submesh_vertlist.Add(vb_id_2.SubmeshVertexIndex); return(true); }
private void ProcessLine(string line) { var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length <= 0) { return; } switch (parts[0]) { case "v": var vertex = new GeometricVertex(); vertex.ProcessData(parts, _maxValue); GeometricVertices.Add(vertex); break; case "f": var face = new FaceVertex(); face.ProcessData(parts); FaceVertices.Add(face); break; case "vt": var textureVertex = new TextureVertex(); textureVertex.ProcessData(parts); TextureVertices.Add(textureVertex); break; case "vn": var normalVertex = new NormalVertex(); normalVertex.ProcessData(parts); NormalVertices.Add(normalVertex); break; } }
public static void GenerateSegmentedPlane(int axis, Vector2 size, Vector2I segments, Vector2 uvTilesPerUnit, Vector2 uvTilesInTotal, out Vector3[] positions, out Vector3[] normals, out Vector4[] tangents, out Vector2[] texCoords, out int[] indices, out Face[] faces) { int resX = Math.Max(2, segments.X + 1); // 2 minimum int resY = Math.Max(2, segments.Y + 1); positions = new Vector3[resX * resY]; texCoords = new Vector2[positions.Length]; Vector2 vt = uvTilesPerUnit * size; for (int y = 0; y < resY; y++) { // [ -height / 2, height / 2 ] double yPos = ((double)y / (resY - 1) - .5) * size.Y; double ty = yPos + size.Y / 2; // [0, height] ty /= size.Y; // [0, 1] for (int x = 0; x < resX; x++) { // [ -width / 2, width / 2 ] double xPos = ((double)x / (resX - 1) - .5) * size.X; double tx = xPos + size.X / 2; // [0, width] tx /= size.X; // [0, 1] int index = x + y * resX; if (axis == 0) { positions[index] = new Vector3(0, xPos, yPos); } else if (axis == 1) { positions[index] = new Vector3(-xPos, 0, yPos); } else { positions[index] = new Vector3(xPos, yPos, 0); } //texCoords[ index ] = new Vector2( tx, 1.0f - ty ); if (uvTilesInTotal != Vector2.Zero) { texCoords[index] = new Vector2(tx * uvTilesInTotal.X, 1.0f - ty * uvTilesInTotal.Y); } else if (uvTilesPerUnit != Vector2.Zero) { texCoords[index] = new Vector2(tx * vt.X, 1.0f - ty * vt.Y); } else { texCoords[index] = new Vector2(tx, 1.0f - ty); } } } normals = new Vector3[positions.Length]; for (int n = 0; n < normals.Length; n++) { if (axis == 0) { normals[n] = Vector3F.XAxis; } else if (axis == 1) { normals[n] = Vector3F.YAxis; } else { normals[n] = Vector3F.ZAxis; } } tangents = new Vector4[positions.Length]; for (int n = 0; n < tangents.Length; n++) { if (axis == 0) { tangents[n] = new Vector4F(0, 1, 0, -1); } else if (axis == 1) { tangents[n] = new Vector4F(-1, 0, 0, -1); } else { tangents[n] = new Vector4F(1, 0, 0, -1); } } int nbFaces = (resX - 1) * (resY - 1); indices = new int[nbFaces * 6]; int tIdx = 0; for (int fy = 0; fy < (resY - 1); fy++) { for (int fx = 0; fx < (resX - 1); fx++) { indices[tIdx++] = fy * resX + fx; indices[tIdx++] = fy * resX + 1 + fx; indices[tIdx++] = fy * resX + resX + fx; indices[tIdx++] = fy * resX + resX + fx; indices[tIdx++] = fy * resX + 1 + fx; indices[tIdx++] = fy * resX + resX + 1 + fx; } } var faceTriangles = new FaceVertex[indices.Length]; for (int i = 0; i < indices.Length; i++) { faceTriangles[i] = new FaceVertex(indices[i], indices[i]); } faces = new Face[] { new Face(faceTriangles) }; }
public static void GeneratePlane(Vector2 size, Vector2 uvTilesPerUnit, Vector2 uvTilesInTotal, out Vector3[] positions, out Vector3[] normals, out Vector4[] tangents, out Vector2[] texCoords, out int[] indices, out Face[] faces) { var half = size * 0.5; positions = new Vector3[4]; positions[0] = new Vector3(-half.X, -half.Y, 0); positions[1] = new Vector3(half.X, -half.Y, 0); positions[2] = new Vector3(half.X, half.Y, 0); positions[3] = new Vector3(-half.X, half.Y, 0); normals = new Vector3[4]; normals[0] = Vector3.ZAxis; normals[1] = Vector3.ZAxis; normals[2] = Vector3.ZAxis; normals[3] = Vector3.ZAxis; tangents = new Vector4[4]; tangents[0] = new Vector4(1, 0, 0, -1); tangents[1] = new Vector4(1, 0, 0, -1); tangents[2] = new Vector4(1, 0, 0, -1); tangents[3] = new Vector4(1, 0, 0, -1); //tangents[ 0 ] = new Vector4( 1, 0, 0, 1 ); //tangents[ 1 ] = new Vector4( 1, 0, 0, 1 ); //tangents[ 2 ] = new Vector4( 1, 0, 0, 1 ); //tangents[ 3 ] = new Vector4( 1, 0, 0, 1 ); texCoords = new Vector2[4]; if (uvTilesInTotal != Vector2.Zero) { texCoords[0] = new Vector2(0, uvTilesInTotal.Y); texCoords[1] = new Vector2(uvTilesInTotal.X, uvTilesInTotal.Y); texCoords[2] = new Vector2(uvTilesInTotal.X, 0); texCoords[3] = new Vector2(0, 0); //var half = uvTilesInTotal * 0.5; //texCoords[ 0 ] = new Vec2( -half.X, -half.Y ); //texCoords[ 1 ] = new Vec2( half.X, -half.Y ); //texCoords[ 2 ] = new Vec2( half.X, half.Y ); //texCoords[ 3 ] = new Vec2( -half.X, half.Y ); } else if (uvTilesPerUnit != Vector2.Zero) { Vector2 v = uvTilesPerUnit * size; texCoords[0] = new Vector2(0, v.Y); texCoords[1] = new Vector2(v.X, v.Y); texCoords[2] = new Vector2(v.X, 0); texCoords[3] = new Vector2(0, 0); //Vec2 half = uvTilesPerUnit * size * 0.5; //texCoords[ 0 ] = new Vec2( -half.X, -half.Y ); //texCoords[ 1 ] = new Vec2( half.X, -half.Y ); //texCoords[ 2 ] = new Vec2( half.X, half.Y ); //texCoords[ 3 ] = new Vec2( -half.X, half.Y ); } indices = new int[] { 0, 1, 2, 2, 3, 0 }; var faceTriangles = new FaceVertex[indices.Length]; for (int i = 0; i < indices.Length; i++) { faceTriangles[i] = new FaceVertex(indices[i], indices[i]); } faces = new Face[] { new Face(faceTriangles) }; }
//Is used in Sphere, Capsule public static Face[] BuildFacesForGeoSphere(int hSegments, int vSegments, int rawVerticesInFace, int rawVerticesInFaceForMiddle, int[] indices) { Debug.Assert(rawVerticesInFace == 3 && (rawVerticesInFaceForMiddle == 3 || rawVerticesInFaceForMiddle == 6)); int faceCount = hSegments * (vSegments - 2) * 6 / rawVerticesInFace + hSegments * 6 / rawVerticesInFaceForMiddle; var faces = new Face[faceCount]; int middleSegmentStart = (vSegments / 2) * hSegments * 6; int middleSegmentEnd = middleSegmentStart + hSegments * 6; int curTriangle = 0; int curFace = 0; FaceVertex[] faceTriangles = null; for (int i = 0; i < indices.Length; i++) { int index = indices[i]; int vIndex = index / (hSegments + 1); int hIndex = index % (hSegments + 1); hIndex %= hSegments; //Each vSegment has hSegments of vertices, exept the first and last vSegment, they have 1 vertex. //Verext count == hSegments * (vSegments-1) + 2; int vertexIndex; if (vIndex == 0) { vertexIndex = hSegments * (vSegments - 1); } else if (vIndex == vSegments) { vertexIndex = hSegments * (vSegments - 1) + 1; } else { vertexIndex = (vIndex - 1) * hSegments + hIndex; } if (faceTriangles == null) { faceTriangles = new FaceVertex[middleSegmentStart <= i && i < middleSegmentEnd ? rawVerticesInFaceForMiddle : rawVerticesInFace]; curTriangle = 0; } faceTriangles[curTriangle++] = new FaceVertex(vertexIndex, index); if (curTriangle == faceTriangles.Length) { bool isFirstDegenerate = IsDegenerate(faceTriangles[0].Vertex, faceTriangles[1].Vertex, faceTriangles[2].Vertex); Debug.Assert(!(faceTriangles.Length == 6 && ( isFirstDegenerate || IsDegenerate(faceTriangles[3].Vertex, faceTriangles[4].Vertex, faceTriangles[5].Vertex)) )); //??? Сейчас отбрасываются вырожденные. Можно ли сделать чтобы вырожденные не перебирались совсем? if (!isFirstDegenerate) { faces[curFace++] = new Face(faceTriangles); } faceTriangles = null; } } Debug.Assert(faces.Length == curFace); return(faces.ToArray()); bool IsDegenerate(int i0, int i1, int i2) => i0 == i1 || i0 == i2 || i1 == i2; }
public static void ExportXModel(string FilePath, XModelType FileType, bool Siege = false, string Cosmetic = "") { // Configure scene using (var MayaCfg = new MayaSceneConfigure()) { // First, get the current selection var ExportObjectList = new MSelectionList(); MGlobal.getActiveSelectionList(ExportObjectList); // If empty, select all joints and meshes if (ExportObjectList.length == 0) { // Select all joints and meshes MGlobal.executeCommand("string $selected[] = `ls -type joint`; select -r $selected;"); MGlobal.executeCommand("string $transforms[] = `ls -tr`;string $polyMeshes[] = `filterExpand -sm 12 $transforms`;select -add $polyMeshes;"); // Get it again MGlobal.getActiveSelectionList(ExportObjectList); } // If still empty, error blank scene if (ExportObjectList.length == 0) { MGlobal.displayError("[CODTools] The current scene is empty..."); return; } // Progress MayaCfg.StartProgress("Exporting XModel...", (int)ExportObjectList.length); // Create new model var Result = new XModel(System.IO.Path.GetFileNameWithoutExtension(FilePath)); // Assign siege model flag (Default: false) Result.SiegeModel = Siege; // Metadata var SceneName = string.Empty; MGlobal.executeCommand("file -q -sceneName", out SceneName); Result.Comments.Add(string.Format("Export filename: '{0}'", FilePath)); Result.Comments.Add(string.Format("Source filename: '{0}'", SceneName)); Result.Comments.Add(string.Format("Export time: {0}", DateTime.Now.ToString())); // Iterate and add joints var ParentStack = new List <string>(); var UniqueBones = new HashSet <string>(); foreach (var Joint in ExportObjectList.DependNodes(MFn.Type.kJoint)) { // Step MayaCfg.StepProgress(); // Grab the controller var Path = GetObjectDagPath(Joint); var Controller = new MFnIkJoint(Path); // Create a new bone var TagName = CleanNodeName(Controller.name); if (UniqueBones.Contains(TagName)) { continue; } UniqueBones.Add(TagName); var NewBone = new Bone(TagName); // Add parent ParentStack.Add(GetParentName(Controller)); // Fetch the world-space position and rotation var WorldPosition = Controller.getTranslation(MSpace.Space.kWorld); var WorldRotation = new MQuaternion(MQuaternion.identity); Controller.getRotation(WorldRotation, MSpace.Space.kWorld); var WorldScale = new double[3] { 1, 1, 1 }; Controller.getScale(WorldScale); // Create the matrix NewBone.Translation = WorldPosition * (1 / 2.54); NewBone.Scale = new MVector(WorldScale[0], WorldScale[1], WorldScale[2]); NewBone.RotationMatrix = WorldRotation.asMatrix; // Add it Result.Bones.Add(NewBone); } // Sort joints SortJoints(ref Result, ParentStack, Cosmetic); // Pre-fetch skins var SkinClusters = GetSkinClusters(); var BoneMapping = Result.GetBoneMapping(); // A list of used materials int MaterialIndex = 0; var UsedMaterials = new Dictionary <string, int>(); var UsedMeshes = new HashSet <string>(); // Iterate and add meshes foreach (var Mesh in ExportObjectList.DependNodes(MFn.Type.kMesh)) { // Step MayaCfg.StepProgress(); // Grab the controller var Path = GetObjectDagPath(Mesh); Path.extendToShape(); var Controller = new MFnMesh(Path); // Ignore duplicates if (UsedMeshes.Contains(Path.partialPathName)) { continue; } UsedMeshes.Add(Path.partialPathName); // Pre-fetch materials var MeshMaterials = GetMaterialsMesh(ref Controller, ref Path); foreach (var Mat in MeshMaterials) { if (!UsedMaterials.ContainsKey(Mat.Name)) { UsedMaterials.Add(Mat.Name, MaterialIndex++); Result.Materials.Add(Mat); } } // New mesh var NewMesh = new Mesh(); // Grab iterators var VertexIterator = new MItMeshVertex(Path); var FaceIterator = new MItMeshPolygon(Path); // Get the cluster for this var SkinCluster = FindSkinCluster(ref SkinClusters, Controller); var SkinJoints = new MDagPathArray(); if (SkinCluster != null) { SkinCluster.influenceObjects(SkinJoints); } // Build vertex array for (; !VertexIterator.isDone; VertexIterator.next()) { // Prepare var NewVert = new Vertex(); // Grab data NewVert.Position = VertexIterator.position(MSpace.Space.kWorld) * (1 / 2.54); // Weights if valid if (SkinCluster != null) { var WeightValues = new MDoubleArray(); uint Influence = 0; SkinCluster.getWeights(Path, VertexIterator.currentItem(), WeightValues, ref Influence); for (int i = 0; i < (int)WeightValues.length; i++) { if (WeightValues[i] < 0.000001) { continue; } var WeightTagName = CleanNodeName(SkinJoints[i].partialPathName); var WeightID = (BoneMapping.ContainsKey(WeightTagName)) ? BoneMapping[WeightTagName] : 0; NewVert.Weights.Add(new Tuple <int, float>(WeightID, (float)WeightValues[i])); } } if (NewVert.Weights.Count == 0) { NewVert.Weights.Add(new Tuple <int, float>(0, 1.0f)); } // Add it NewMesh.Vertices.Add(NewVert); } // Build face array for (; !FaceIterator.isDone; FaceIterator.next()) { var Indices = new MIntArray(); var Normals = new MVectorArray(); var UVUs = new MFloatArray(); var UVVs = new MFloatArray(); FaceIterator.getVertices(Indices); FaceIterator.getNormals(Normals, MSpace.Space.kWorld); FaceIterator.getUVs(UVUs, UVVs); // Only support TRIS/QUAD if (Indices.Count < 3) { continue; } if (Indices.Count == 3) { // Create new face var NewFace = new FaceVertex(); // Setup NewFace.Indices[0] = Indices[0]; NewFace.Indices[2] = Indices[1]; NewFace.Indices[1] = Indices[2]; // Normals NewFace.Normals[0] = new MVector(Normals[0][0], Normals[0][1], Normals[0][2]); NewFace.Normals[2] = new MVector(Normals[1][0], Normals[1][1], Normals[1][2]); NewFace.Normals[1] = new MVector(Normals[2][0], Normals[2][1], Normals[2][2]); // Colors FaceIterator.getColor(NewFace.Colors[0], 0); FaceIterator.getColor(NewFace.Colors[2], 1); FaceIterator.getColor(NewFace.Colors[1], 2); // Append UV Layers NewFace.UVs[0] = new Tuple <float, float>(UVUs[0], 1 - UVVs[0]); NewFace.UVs[2] = new Tuple <float, float>(UVUs[1], 1 - UVVs[1]); NewFace.UVs[1] = new Tuple <float, float>(UVUs[2], 1 - UVVs[2]); // Set material index if (MeshMaterials.Count > 0) { NewFace.MaterialIndex = UsedMaterials[MeshMaterials[0].Name]; } // Add it NewMesh.Faces.Add(NewFace); } else { // Create new faces FaceVertex NewFace = new FaceVertex(), NewFace2 = new FaceVertex(); // Setup NewFace.Indices[0] = Indices[0]; NewFace.Indices[2] = Indices[1]; NewFace.Indices[1] = Indices[2]; NewFace2.Indices[0] = Indices[0]; NewFace2.Indices[2] = Indices[2]; NewFace2.Indices[1] = Indices[3]; // Normals NewFace.Normals[0] = new MVector(Normals[0][0], Normals[0][1], Normals[0][2]); NewFace.Normals[2] = new MVector(Normals[1][0], Normals[1][1], Normals[1][2]); NewFace.Normals[1] = new MVector(Normals[2][0], Normals[2][1], Normals[2][2]); NewFace2.Normals[0] = new MVector(Normals[0][0], Normals[0][1], Normals[0][2]); NewFace2.Normals[2] = new MVector(Normals[2][0], Normals[2][1], Normals[2][2]); NewFace2.Normals[1] = new MVector(Normals[3][0], Normals[3][1], Normals[3][2]); // Colors FaceIterator.getColor(NewFace.Colors[0], 0); FaceIterator.getColor(NewFace.Colors[2], 1); FaceIterator.getColor(NewFace.Colors[1], 2); FaceIterator.getColor(NewFace2.Colors[0], 0); FaceIterator.getColor(NewFace2.Colors[2], 2); FaceIterator.getColor(NewFace2.Colors[1], 3); // Append UV Layers NewFace.UVs[0] = new Tuple <float, float>(UVUs[0], 1 - UVVs[0]); NewFace.UVs[2] = new Tuple <float, float>(UVUs[1], 1 - UVVs[1]); NewFace.UVs[1] = new Tuple <float, float>(UVUs[2], 1 - UVVs[2]); NewFace2.UVs[0] = new Tuple <float, float>(UVUs[0], 1 - UVVs[0]); NewFace2.UVs[2] = new Tuple <float, float>(UVUs[2], 1 - UVVs[2]); NewFace2.UVs[1] = new Tuple <float, float>(UVUs[3], 1 - UVVs[3]); // Set material index if (MeshMaterials.Count > 0) { NewFace.MaterialIndex = UsedMaterials[MeshMaterials[0].Name]; NewFace2.MaterialIndex = UsedMaterials[MeshMaterials[0].Name]; } // Add it NewMesh.Faces.Add(NewFace); NewMesh.Faces.Add(NewFace2); } } // Add it Result.Meshes.Add(NewMesh); } // Write switch (FileType) { case XModelType.Export: Result.WriteExport(FilePath); break; case XModelType.Bin: Result.WriteBin(FilePath); break; } } // Log complete MGlobal.displayInfo(string.Format("[CODTools] Exported {0}", System.IO.Path.GetFileName(FilePath))); }
public void AddVertex(FaceVertex vertex) { _vertices.Add(vertex); }
public static void GenerateCone(int axis, ConeOrigin origin, double radius, double height, int segments, bool needSide, bool needBottom, out Vector3[] positions, out Vector3[] normals, out Vector4[] tangents, out Vector2[] texCoords, out int[] indices, out Face[] faces) { if (!needSide && !needBottom) { positions = new Vector3[0]; indices = new int[0]; normals = new Vector3[0]; tangents = new Vector4[0]; texCoords = new Vector2[0]; faces = null; return; } if (axis < 0 || axis > 2) { Log.Fatal("SimpleMeshGenerator: GenerateCone: axis < 0 || axis > 2."); } //if( radius < 0 ) // Log.Fatal( "SimpleMeshGenerator: GenerateCone: radius < 0." ); //if( height < 0 ) // Log.Fatal( "SimpleMeshGenerator: GenerateCone: height < 0." ); if (segments < 3) { Log.Fatal("SimpleMeshGenerator: GenerateCone: segments < 3."); } int bottomStartIndex = 0; //positions { int vertexCount = 0; if (needSide) { vertexCount += (segments + 1) * 2; } if (needBottom) { vertexCount += segments + 2; } positions = new Vector3[vertexCount]; normals = new Vector3[vertexCount]; tangents = new Vector4[vertexCount]; texCoords = new Vector2[vertexCount]; double[] cosTable = new double[segments + 1]; double[] sinTable = new double[segments + 1]; { double angleStep = Math.PI * 2 / segments; for (int n = 0; n < segments + 1; n++) { double angle = angleStep * n; cosTable[n] = Math.Cos(angle); sinTable[n] = Math.Sin(angle); } } int currentPosition = 0; if (needSide) { for (int n = 0; n < segments + 1; n++) { var fromVector = new Vector3(0, cosTable[n], sinTable[n]); var from = fromVector * radius; var to = new Vector3(Math.Abs(height), 0, 0); positions[currentPosition] = from; //normals Vector3 normal; if (radius == 0) { normal = fromVector; } else if (height == 0) { normal = Vector3.XAxis; } else { var v = new Vector3(0, from.Y, from.Z).GetNormalize(); normal = new Vector3(radius / height, v.Y * (height / radius), v.Z * (height / radius)).GetNormalize(); } if (radius < 0 || height < 0) { normal = -normal; } normals[currentPosition] = normal; tangents[currentPosition] = new Vector4((to - from).GetNormalize(), -1); texCoords[currentPosition] = new Vector2(0, (double)n / (double)segments * 2); currentPosition++; } for (int n = 0; n < segments + 1; n++) { double angle = ((double)n + 0.5) / (double)segments * Math.PI * 2; var fromVector = new Vector3(0, Math.Cos(angle), Math.Sin(angle)); //var fromVector = new Vec3( 0, cosTable[ n ], sinTable[ n ] ); var from = fromVector * radius; var to = new Vector3(Math.Abs(height), 0, 0); positions[currentPosition] = to; //normals Vector3 normal; if (radius == 0) { normal = fromVector; } else if (height == 0) { normal = Vector3.XAxis; } else { var v = new Vector3(0, from.Y, from.Z).GetNormalize(); normal = new Vector3(radius / height, v.Y * (height / radius), v.Z * (height / radius)).GetNormalize(); } if (radius < 0 || height < 0) { normal = -normal; } normals[currentPosition] = normal; tangents[currentPosition] = new Vector4((to - from).GetNormalize(), -1); texCoords[currentPosition] = new Vector2(1, ((double)n + 0.5) / (double)segments * 2); currentPosition++; } } if (needBottom) { bottomStartIndex = currentPosition; for (int n = 0; n < segments + 1; n++) { positions[currentPosition] = new Vector3(0, cosTable[n] * radius, sinTable[n] * radius); normals[currentPosition] = new Vector3(-1, 0, 0); if (radius < 0 || height < 0) { normals[currentPosition] = -normals[currentPosition]; } tangents[currentPosition] = new Vector4(0, 0, -1, -1); if (radius < 0 || height < 0) { texCoords[currentPosition] = new Vector2(sinTable[n], cosTable[n]) * 0.5 + new Vector2(0.5, 0.5); } else { texCoords[currentPosition] = new Vector2(-sinTable[n], cosTable[n]) * 0.5 + new Vector2(0.5, 0.5); } currentPosition++; } positions[currentPosition] = new Vector3(0, 0, 0); normals[currentPosition] = new Vector3(-1, 0, 0); if (radius < 0 || height < 0) { normals[currentPosition] = -normals[currentPosition]; } tangents[currentPosition] = new Vector4(0, 0, -1, -1); texCoords[currentPosition] = new Vector2(0.5, 0.5); currentPosition++; } if (positions.Length != currentPosition) { Log.Fatal("SimpleMeshGenerator: GenerateCone: positions.Length != currentPosition."); } } //indices and faces { int faceCount = 0; if (needSide) { faceCount += segments; } if (needBottom) { faceCount += 1; } //side faces - faces[0..segments) ; bottom - faces[segments] faces = new Face[faceCount]; //Vertex indices will be: on bottom [0..segments); top[segments] ; bottom center[segments+1] const int bottomVertexStart = 0; int topVertex = segments; int bottomCenterVertex = segments + 1; int indexCount = 0; if (needSide) { indexCount += segments * 3; } if (needBottom) { indexCount += segments * 3; } indices = new int[indexCount]; int currentIndex = 0; if (needSide) { for (int n = 0; n < segments; n++) { //int index = n * 2; indices[currentIndex++] = n; int nextClipped = (n + 1) % segments; if (radius < 0 || height < 0) { indices[currentIndex++] = n + segments + 1; //top indices[currentIndex++] = n + 1; faces[n] = new Face { Triangles = new[] { new FaceVertex(bottomVertexStart + n, n), new FaceVertex(topVertex, n + segments + 1), new FaceVertex(bottomVertexStart + nextClipped, n + 1) } }; } else { indices[currentIndex++] = n + 1; indices[currentIndex++] = n + segments + 1; faces[n] = new Face { Triangles = new[] { new FaceVertex(bottomVertexStart + n, n), new FaceVertex(bottomVertexStart + nextClipped, n + 1), new FaceVertex(topVertex, n + segments + 1) } }; } } } if (needBottom) { var faceTriangles = new FaceVertex[segments * 3]; for (int n = 0; n < segments; n++) { int index = bottomStartIndex + n; int n3 = n * 3; faceTriangles[n3] = new FaceVertex(bottomVertexStart + (n + 1) % segments, index + 1); indices[currentIndex++] = index + 1; if (radius < 0 || height < 0) { faceTriangles[n3 + 1] = new FaceVertex(bottomCenterVertex, bottomStartIndex + segments + 1); indices[currentIndex++] = bottomStartIndex + segments + 1; //center faceTriangles[n3 + 2] = new FaceVertex(bottomVertexStart + n, index); indices[currentIndex++] = index; } else { faceTriangles[n3 + 1] = new FaceVertex(bottomVertexStart + n, index); indices[currentIndex++] = index; faceTriangles[n3 + 2] = new FaceVertex(bottomCenterVertex, bottomStartIndex + segments + 1); indices[currentIndex++] = bottomStartIndex + segments + 1; } } faces[segments] = new Face(faceTriangles); } if (indices.Length != currentIndex) { Log.Fatal("SimpleMeshGenerator: GenerateCone: indices.Length != currentIndex."); } } if (origin == ConeOrigin.Center) { Vector3 offset = new Vector3(-Math.Abs(height) * .5, 0, 0); var newValues = new Vector3[positions.Length]; for (int n = 0; n < positions.Length; n++) { newValues[n] = positions[n] + offset; } positions = newValues; } positions = RotateByAxis(axis, positions); normals = RotateByAxis(axis, normals); tangents = RotateByAxis(axis, tangents); }
public Mesh LoadFromString(string objModel) { // Seperate lines from the file List <string> lines = new List <string>(objModel.Split('\n')); // Lists to hold model data List <Vector3> verts = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Vector2> texs = new List <Vector2>(); List <Vector3> decodedVertices = new List <Vector3>(); List <Vector3> decodedNormals = new List <Vector3>(); List <Vector2> decodedUvCoords = new List <Vector2>(); List <Tuple <TempVertex, TempVertex, TempVertex> > faces = new List <Tuple <TempVertex, TempVertex, TempVertex> >(); // Base values verts.Add(new Vector3()); texs.Add(new Vector2()); normals.Add(new Vector3()); // Read file line by line foreach (String line in lines) { if (line.StartsWith("v ")) // Vertex definition { // Cut off beginning of line String temp = line.Substring(2); Vector3 vec = new Vector3(); if (temp.Trim().Count((char c) => c == ' ') == 2) // Check if there's enough elements for a vertex { String[] vertparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Attempt to parse each part of the vertice bool success = float.TryParse(vertparts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.X); success |= float.TryParse(vertparts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.Y); success |= float.TryParse(vertparts[2], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.Z); // If any of the parses failed, report the error if (!success) { Console.WriteLine("Error parsing vertex: {0}", line); } } else { Console.WriteLine("Error parsing vertex: {0}", line); } verts.Add(vec); } else if (line.StartsWith("vt ")) // Texture coordinate { // Cut off beginning of line String temp = line.Substring(2); Vector2 vec = new Vector2(); if (temp.Trim().Count((char c) => c == ' ') > 0) // Check if there's enough elements for a vertex { String[] texcoordparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Attempt to parse each part of the vertice bool success = float.TryParse(texcoordparts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.X); success |= float.TryParse(texcoordparts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.Y); // If any of the parses failed, report the error if (!success) { Console.WriteLine("Error parsing texture coordinate: {0}", line); } } else { Console.WriteLine("Error parsing texture coordinate: {0}", line); } texs.Add(vec); } else if (line.StartsWith("vn ")) // Normal vector { // Cut off beginning of line String temp = line.Substring(2); Vector3 vec = new Vector3(); if (temp.Trim().Count((char c) => c == ' ') == 2) // Check if there's enough elements for a normal { String[] vertparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Attempt to parse each part of the vertice bool success = float.TryParse(vertparts[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.X); success |= float.TryParse(vertparts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.Y); success |= float.TryParse(vertparts[2], NumberStyles.Any, CultureInfo.InvariantCulture, out vec.Z); // If any of the parses failed, report the error if (!success) { Console.WriteLine("Error parsing normal: {0}", line); } } else { Console.WriteLine("Error parsing normal: {0}", line); } normals.Add(vec); } else if (line.StartsWith("f ")) // Face definition { // Cut off beginning of line String temp = line.Substring(2); Tuple <TempVertex, TempVertex, TempVertex> face = new Tuple <TempVertex, TempVertex, TempVertex>(new TempVertex(), new TempVertex(), new TempVertex()); if (temp.Trim().Count((char c) => c == ' ') == 2) // Check if there's enough elements for a face { String[] faceparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int v1, v2, v3; int t1, t2, t3; int n1, n2, n3; // Attempt to parse each part of the face bool success = int.TryParse(faceparts[0].Split('/')[0], out v1); success |= int.TryParse(faceparts[1].Split('/')[0], out v2); success |= int.TryParse(faceparts[2].Split('/')[0], out v3); if (faceparts[0].Count((char c) => c == '/') >= 2) { success |= int.TryParse(faceparts[0].Split('/')[1], out t1); success |= int.TryParse(faceparts[1].Split('/')[1], out t2); success |= int.TryParse(faceparts[2].Split('/')[1], out t3); success |= int.TryParse(faceparts[0].Split('/')[2], out n1); success |= int.TryParse(faceparts[1].Split('/')[2], out n2); success |= int.TryParse(faceparts[2].Split('/')[2], out n3); } else { if (texs.Count > v1 && texs.Count > v2 && texs.Count > v3) { t1 = v1; t2 = v2; t3 = v3; } else { t1 = 0; t2 = 0; t3 = 0; } if (normals.Count > v1 && normals.Count > v2 && normals.Count > v3) { n1 = v1; n2 = v2; n3 = v3; } else { n1 = 0; n2 = 0; n3 = 0; } } // If any of the parses failed, report the error if (!success) { Console.WriteLine("Error parsing face: {0}", line); } else { TempVertex tv1 = new TempVertex(v1, n1, t1); TempVertex tv2 = new TempVertex(v2, n2, t2); TempVertex tv3 = new TempVertex(v3, n3, t3); face = new Tuple <TempVertex, TempVertex, TempVertex>(tv1, tv2, tv3); faces.Add(face); } } else { Console.WriteLine("Error parsing face: {0}", line); } } } // Create the ObjVolume Mesh loadedModel = new Mesh(); foreach (var face in faces) { FaceVertex v1 = new FaceVertex(verts[face.Item1.Vertex], normals[face.Item1.Normal], texs[face.Item1.Texcoord]); FaceVertex v2 = new FaceVertex(verts[face.Item2.Vertex], normals[face.Item2.Normal], texs[face.Item2.Texcoord]); FaceVertex v3 = new FaceVertex(verts[face.Item3.Vertex], normals[face.Item3.Normal], texs[face.Item3.Texcoord]); Vector2 calculatedUV = new Vector2(texs[face.Item1.Texcoord].X, 1.0f - texs[face.Item1.Texcoord].Y); Vector2 calculatedUV2 = new Vector2(texs[face.Item2.Texcoord].X, 1.0f - texs[face.Item2.Texcoord].Y); Vector2 calculatedUV3 = new Vector2(texs[face.Item3.Texcoord].X, 1.0f - texs[face.Item3.Texcoord].Y); decodedVertices.AddRange(new Vector3[] { verts[face.Item1.Vertex], verts[face.Item2.Vertex], verts[face.Item3.Vertex] }); decodedNormals.AddRange(new Vector3[] { normals[face.Item1.Normal], normals[face.Item2.Normal], normals[face.Item3.Normal] }); decodedUvCoords.AddRange(new Vector2[] { calculatedUV, calculatedUV2, calculatedUV3 }); } loadedModel.Indeces = Enumerable.Range(0, decodedVertices.Count).ToArray(); loadedModel.Vertices = decodedVertices.ToArray(); loadedModel.Normals = decodedNormals.ToArray(); loadedModel.UvCoords = decodedUvCoords.ToArray(); return(loadedModel); }
public static void GenerateCylinder(int axis, double radius, double height, int segments, bool needTop, bool needSide, bool needBottom, out Vector3[] positions, out Vector3[] normals, out Vector4[] tangents, out Vector2[] texCoords, out int[] indices, out Face[] faces) { if (axis < 0 || axis > 2) { Log.Fatal("SimpleMeshGenerator: GenerateCylinder: axis < 0 || axis > 2."); } //if( radius < 0 ) // Log.Fatal( "SimpleMeshGenerator: GenerateCylinder: radius < 0." ); //if( height < 0 ) // Log.Fatal( "SimpleMeshGenerator: GenerateCylinder: height < 0." ); if (segments < 3) { Log.Fatal("SimpleMeshGenerator: GenerateCylinder: segments < 3."); } int topIndex = 0; int topStartIndex = 0; int bottomIndex = 0; int bottomStartIndex = 0; int sideTopIndex = 0; int sideBottomIndex = 0; //positions { int vertexCount = 0; if (needSide) { vertexCount += (segments + 1) * 2; } if (needTop) { vertexCount += segments + 1; } if (needBottom) { vertexCount += segments + 1; } positions = new Vector3[vertexCount]; normals = new Vector3[vertexCount]; tangents = new Vector4[vertexCount]; texCoords = new Vector2[vertexCount]; double[] cosTable = new double[segments + 1]; double[] sinTable = new double[segments + 1]; { double angleStep = Math.PI * 2 / segments; for (int n = 0; n < segments + 1; n++) { double angle = angleStep * n; cosTable[n] = Math.Cos(angle); sinTable[n] = Math.Sin(angle); } } int currentPosition = 0; if (needSide) { sideTopIndex = currentPosition; for (int n = 0; n < segments + 1; n++) { positions[currentPosition] = new Vector3(height * .5, cosTable[n] * radius, sinTable[n] * radius); normals[currentPosition] = new Vector3(0, cosTable[n], sinTable[n]); if (radius < 0 || height < 0) { tangents[currentPosition] = new Vector4(-1, 0, 0, -1); } else { tangents[currentPosition] = new Vector4(1, 0, 0, -1); } texCoords[currentPosition] = new Vector2(1, (double)n / (double)segments * 2); currentPosition++; } sideBottomIndex = currentPosition; for (int n = 0; n < segments + 1; n++) { positions[currentPosition] = new Vector3(-height * .5, cosTable[n] * radius, sinTable[n] * radius); normals[currentPosition] = new Vector3(0, cosTable[n], sinTable[n]); if (radius < 0 || height < 0) { tangents[currentPosition] = new Vector4(-1, 0, 0, -1); } else { tangents[currentPosition] = new Vector4(1, 0, 0, -1); } texCoords[currentPosition] = new Vector2(0, (double)n / (double)segments * 2); currentPosition++; } } if (needTop) { topStartIndex = currentPosition; for (int n = 0; n < segments; n++) { positions[currentPosition] = new Vector3(height * .5f, cosTable[n] * radius, sinTable[n] * radius); normals[currentPosition] = new Vector3(1, 0, 0); tangents[currentPosition] = new Vector4(0, 0, -1, -1); if (radius < 0 || height < 0) { texCoords[currentPosition] = new Vector2(sinTable[n], cosTable[n]) * 0.5 + new Vector2(0.5, 0.5); } else { texCoords[currentPosition] = new Vector2(-sinTable[n], -cosTable[n]) * 0.5 + new Vector2(0.5, 0.5); } currentPosition++; } topIndex = currentPosition; positions[currentPosition] = new Vector3(height * .5, 0, 0); normals[currentPosition] = new Vector3(1, 0, 0); tangents[currentPosition] = new Vector4(0, 0, -1, -1); texCoords[currentPosition] = new Vector2(0.5, 0.5); currentPosition++; } if (needBottom) { bottomStartIndex = currentPosition; for (int n = 0; n < segments; n++) { positions[currentPosition] = new Vector3(-height * .5, cosTable[n] * radius, sinTable[n] * radius); normals[currentPosition] = new Vector3(-1, 0, 0); tangents[currentPosition] = new Vector4(0, 0, -1, -1); if (radius < 0 || height < 0) { texCoords[currentPosition] = new Vector2(sinTable[n], -cosTable[n]) * 0.5 + new Vector2(0.5, 0.5); } else { texCoords[currentPosition] = new Vector2(-sinTable[n], cosTable[n]) * 0.5 + new Vector2(0.5, 0.5); } currentPosition++; } bottomIndex = currentPosition; positions[currentPosition] = new Vector3(-height * .5, 0, 0); normals[currentPosition] = new Vector3(-1, 0, 0); tangents[currentPosition] = new Vector4(0, 0, -1, -1); texCoords[currentPosition] = new Vector2(0.5, 0.5); currentPosition++; } if (positions.Length != currentPosition) { Log.Fatal("SimpleMeshGenerator: GenerateCylinder: positions.Length != currentPosition."); } } //indices and faces { int faceCount = 0; if (needSide) { faceCount += segments; } if (needTop) { faceCount += 1; } if (needBottom) { faceCount += 1; } //side faces - faces[0..segments) ; top - faces[segments]; bottom - faces[segments + 1] faces = new Face[faceCount]; //Vertex indices will be: on top [0..segments), top center [segments], on bottom [segments+1..segments*2+1), bottom center[segments*2+1] const int topVertexStart = 0; int topCenterVertex = segments; int bottomVertexStart = segments + 1; int bottomCenterVertex = segments * 2 + 1; int indexCount = 0; if (needSide) { indexCount += segments * 2 * 3; } if (needTop) { indexCount += segments * 3; } if (needBottom) { indexCount += segments * 3; } indices = new int[indexCount]; int currentIndex = 0; if (needSide) { for (int n = 0; n < segments; n++) { int start = n; int end = (n + 1); // % segments; indices[currentIndex++] = sideTopIndex + end; indices[currentIndex++] = sideTopIndex + start; indices[currentIndex++] = sideBottomIndex + start; indices[currentIndex++] = sideBottomIndex + start; indices[currentIndex++] = sideBottomIndex + end; indices[currentIndex++] = sideTopIndex + end; int endClipped = end % segments; faces[n] = new Face { Triangles = new[] { new FaceVertex(topVertexStart + endClipped, sideTopIndex + end), new FaceVertex(topVertexStart + start, sideTopIndex + start), new FaceVertex(bottomVertexStart + start, sideBottomIndex + start), new FaceVertex(bottomVertexStart + start, sideBottomIndex + start), new FaceVertex(bottomVertexStart + endClipped, sideBottomIndex + end), new FaceVertex(topVertexStart + endClipped, sideTopIndex + end) } }; } } if (needTop) { var faceTriangles = new FaceVertex[segments * 3]; for (int n = 0; n < segments; n++) { int start = n; int end = (n + 1) % segments; int n3 = n * 3; faceTriangles[n3] = new FaceVertex(topVertexStart + start, topStartIndex + start); indices[currentIndex++] = topStartIndex + start; faceTriangles[n3 + 1] = new FaceVertex(topVertexStart + end, topStartIndex + end); indices[currentIndex++] = topStartIndex + end; faceTriangles[n3 + 2] = new FaceVertex(topCenterVertex, topIndex); indices[currentIndex++] = topIndex; } faces[segments] = new Face(faceTriangles); } if (needBottom) { var faceTriangles = new FaceVertex[segments * 3]; for (int n = 0; n < segments; n++) { int start = n; int end = (n + 1) % segments; int n3 = n * 3; faceTriangles[n3] = new FaceVertex(bottomVertexStart + end, bottomStartIndex + end); indices[currentIndex++] = bottomStartIndex + end; faceTriangles[n3 + 1] = new FaceVertex(bottomVertexStart + start, bottomStartIndex + start); indices[currentIndex++] = bottomStartIndex + start; faceTriangles[n3 + 2] = new FaceVertex(bottomCenterVertex, bottomIndex); indices[currentIndex++] = bottomIndex; } faces[segments + 1] = new Face(faceTriangles); } if (indices.Length != currentIndex) { Log.Fatal("SimpleMeshGenerator: GenerateCylinder: indices.Length != currentIndex."); } } positions = RotateByAxis(axis, positions); normals = RotateByAxis(axis, normals); tangents = RotateByAxis(axis, tangents); }
protected void TriangleMeshAdapater(LoadResult objmesh) { HashSet <string> uniqPairs = new HashSet <string> (); List <Face> newFaces = new List <Face> (); foreach (Face face in objmesh.Groups[0].Faces) { // Create vertex/tex pairs list for (int i = 0; i < face.Count; i++) { FaceVertex fv = face [i]; string pairName = string.Format("{0}/{1}", fv.VertexIndex, fv.TextureIndex < 0 ? 0 : fv.TextureIndex); uniqPairs.Add(pairName); } // Split quads into triangles if (face.Count == 4) // a quad //throw new NotImplementedException ("Face needs to be triangulated!"); { Face glface = new Face(); glface.AddVertex(new FaceVertex(face [0].VertexIndex, face [0].TextureIndex, face [0].NormalIndex)); glface.AddVertex(new FaceVertex(face [2].VertexIndex, face [2].TextureIndex, face [2].NormalIndex)); glface.AddVertex(new FaceVertex(face [3].VertexIndex, face [3].TextureIndex, face [3].NormalIndex)); // Added the following in Face.cs //public void RemoveVertexAt (int index) { _vertices.RemoveAt (index); } face.RemoveVertexAt(3); newFaces.Add(glface); } else if (face.Count > 4) { throw new NotImplementedException("Face needs to be triangulated!"); } } ((List <Face>)(objmesh.Groups [0].Faces)).AddRange(newFaces); // Build OpenGL vertex / tex arrrays int nbPairs = uniqPairs.Count; string [] pairs = new string [nbPairs]; uniqPairs.CopyTo(pairs); Points = new Point3DCollection(nbPairs); TexCoords = new PointCollection(nbPairs); foreach (string pairName in pairs) { string [] def = pairName.Split('/'); ObjLoader.Loader.Data.VertexData.Vertex vertex = objmesh.Vertices [Convert.ToInt32(def [0]) - 1]; Points.Add(new Point3D(vertex.X, vertex.Y, vertex.Z)); ObjLoader.Loader.Data.VertexData.Texture t = objmesh.Textures [Convert.ToInt32(def [1]) == 0 ? 0 : Convert.ToInt32(def [1]) - 1]; TexCoords.Add(new System.Windows.Point(t.X, 1.0 - t.Y)); //System.Diagnostics.Debug.Print ("{0}\t- {1},\t{2},\t{3}\t- {4}\t{5}", Points.Count, vertex.X, vertex.Y, vertex.Z, t.X, t.Y) ; } //System.Diagnostics.Debug.Print (" ") ; Normals = new Vector3DCollection(); Indices = new Int32Collection(); foreach (Face face in objmesh.Groups[0].Faces) { for (int i = 0; i < face.Count; i++) { FaceVertex fv = face [i]; string pairName = string.Format("{0}/{1}", fv.VertexIndex, fv.TextureIndex < 0 ? 0 : fv.TextureIndex); int index = Array.IndexOf(pairs, pairName); Indices.Add(index); //System.Diagnostics.Debug.Print ("{0}\t/{1}\t= {2}", i, pairName, index) ; } } }
public static void Read(string fileName, ConversionSettings conversionSettings, ref DisplayList dsp, out Dictionary <string, TextureInfo> allMaterials, out string[] messages) { List <string> messageList = new List <string>(); string currentObject = ""; Subset LastFrame = null; List <Subset> Frames = new List <Subset>(); List <Vertex> Vertices = new List <Vertex>(); List <int> Indices = new List <int>(); List <FaceVertex> faceVertices = new List <FaceVertex>(); List <Vertex> dspVertexBuffer = new List <Vertex>(); List <int[]> dspIndexBuffers = new List <int[]>(); List <int> dspTextureKeys = new List <int>(); int[] dspIndices; int minVertexIndex = 0; List <Vector3> positions = new List <Vector3>(); List <Vector2> texCoords = new List <Vector2>(); List <Vector3> normals = new List <Vector3>(); allMaterials = new Dictionary <string, TextureInfo>(); allMaterials["<Undefined>"] = new TextureInfo(null); string[] fileNameSplit = fileName.Split(new char[] { '/', '\\' }); string fileRelativePath = fileName.Remove(fileName.Length - (fileNameSplit[fileNameSplit.Length - 1].Length), fileNameSplit[fileNameSplit.Length - 1].Length); if (!System.IO.File.Exists(fileName)) { messages = new string[] { "File " + fileName + " was not found." }; return; } StreamReader rd = new StreamReader(fileName); StreamReader materialReader = null; while (!rd.EndOfStream) { string line = rd.ReadLine(); string[] split = line.Split(' '); if (split[0] == "mtllib") { materialReader = new StreamReader(fileRelativePath + line.Remove(0, split[0].Length + 1)); string currentMtl = null; while (!materialReader.EndOfStream) { string matLine = materialReader.ReadLine(); string[] matSplit = matLine.Split(' '); if (matSplit[0] == "newmtl") { currentMtl = matLine.Remove(0, matSplit[0].Length); } if (matSplit[0] == "map_Kd") { TextureInfo newTex; string fullPath = matLine.Remove(0, matSplit[0].Length).Trim(); if (fullPath[1] != ':') { fullPath = fileRelativePath + fullPath; } allMaterials.Add(currentMtl, newTex = new TextureInfo(fullPath)); } } } else if (split[0] == "o") //Object { if (LastFrame == null) { LastFrame = new Subset(); } currentObject = split[1]; } else if (split[0] == "v") // Vertex { positions.Add(cvt.ParseVector3(split, 1)); } else if (split[0] == "vn")// Vertex Normal { normals.Add(cvt.ParseVector3(split, 1)); } else if (split[0] == "vt") // Vertex TexCoord { texCoords.Add(cvt.parseVector2(split, 1)); } else if (split[0] == "usemtl") { LastFrame.VertexBuffer = Vertices.ToArray(); LastFrame.IndexBuffer = Indices.ToArray(); dspIndices = new int[LastFrame.IndexBuffer.Length]; for (int i = 0; i < LastFrame.IndexBuffer.Length; i += 3) { dspIndices[i] = LastFrame.IndexBuffer[i + 2] + minVertexIndex; dspIndices[i + 1] = LastFrame.IndexBuffer[i + 1] + minVertexIndex; dspIndices[i + 2] = LastFrame.IndexBuffer[i] + minVertexIndex; } if (Indices.Count > 0) { dspIndexBuffers.Add(dspIndices); LastFrame.CreatePatches(); Frames.Add(LastFrame); } Indices.Clear(); LastFrame = new Subset(); string mtlName = line.Remove(0, split[0].Length); if (!allMaterials.TryGetValue(mtlName, out LastFrame.Texture)) { messageList.Add("Object " + currentObject + " has unassigned faces."); LastFrame.Texture = allMaterials["<Undefined>"]; } } else if (split[0] == "f") // Face { int i0 = 0, ix = 0; for (int i = 1; i < split.Length; i++) { string[] vertexIndices = split[i].Split('/'); FaceVertex faceVertex = new FaceVertex(); int.TryParse(vertexIndices[0], out faceVertex.Vertex); if (vertexIndices.Length > 1) { int.TryParse(vertexIndices[1], out faceVertex.Texture); } if (vertexIndices.Length > 2) { int.TryParse(vertexIndices[2], out faceVertex.Normal); } int index = 0; foreach (FaceVertex v in faceVertices) { if (v.Vertex == faceVertex.Vertex && v.Texture == faceVertex.Texture && v.Normal == faceVertex.Normal) { break; } index++; } if (i > 3) { Indices.Add(i0); Indices.Add(ix); } Indices.Add(index); if (i == 1) { i0 = index; } ix = index; if (index == faceVertices.Count) { faceVertices.Add(faceVertex); Vertex newVertex; Vector2 texCoord = Vector2.Empty; if (faceVertex.Texture > 0) { texCoord = texCoords[faceVertex.Texture - 1]; } Vector3 normal = Vector3.Empty; if (faceVertex.Normal > 0) { normal = normals[faceVertex.Normal - 1]; } Vertices.Add(newVertex = new Vertex(positions[faceVertex.Vertex - 1], texCoord, normal)); dspVertexBuffer.Add(newVertex); } } } } rd.BaseStream.Close(); materialReader.Close(); LastFrame.IndexBuffer = Indices.ToArray(); LastFrame.VertexBuffer = Vertices.ToArray(); dspIndices = new int[LastFrame.IndexBuffer.Length]; for (int i = 0; i < LastFrame.IndexBuffer.Length; i += 3) { dspIndices[i] = LastFrame.IndexBuffer[i + 2] + minVertexIndex; dspIndices[i + 1] = LastFrame.IndexBuffer[i + 1] + minVertexIndex; dspIndices[i + 2] = LastFrame.IndexBuffer[i] + minVertexIndex; } dspIndexBuffers.Add(dspIndices); LastFrame.CreatePatches(); Frames.Add(LastFrame); dsp.subsets = Frames.ToArray(); messages = messageList.ToArray(); }
public void Push(FaceVertex face, Model_Prefab_Transform[] transforms) { var vIdx = face.VertexIndex - 1; var nIdx = face.NormalIndex - 1; var tIdx = face.TextureIndex - 1; //PLog.Info("vIdx<{0}> nIdx<{1}> tIdx<{2}>", vIdx, nIdx, tIdx); var scaleVec = Vector3.one; if (Model.Vertices.Count > vIdx && vIdx > -1) { var v = Model.Vertices[vIdx]; float sX = 1f, sY = 1f, sZ = 1f; if (transforms != null) { foreach (var trans in transforms) { switch (trans) { case Model_Prefab_Transform.Flip_X: sX = -1f; break; case Model_Prefab_Transform.Flip_Y: sY = -1f; break; case Model_Prefab_Transform.Flip_Z: sZ = -1f; break; default: throw new NotImplementedException($"Model_Prefab_Transform: {Enum.GetName(typeof(Model_Prefab_Transform), trans)} is not yet implemented!"); break; } } } scaleVec = new Vector3(sX, sY, sZ); var vert = new Vector3(v.X, v.Y, v.Z); vert.Scale(scaleVec); var vi = verts.Length; Push_Vert(vert); Push_Indice(vi); } if (Model.Normals.Count > nIdx && nIdx > -1) { var n = Model.Normals[nIdx]; var normal = new Vector3(n.X, n.Y, n.Z); normal.Scale(scaleVec); Push_Normal(normal); } if (Model.Textures.Count <= tIdx || tIdx <= -1) { return; } var u = Model.Textures[tIdx]; Push_UV(new Vector2(u.X, u.Y)); }