public HairMesh[] Import(BinaryReader reader, string path, Hair hair, HairImportSettings importSettings) { reader.Close(); // Initialize the import // Load the ase file content // Create a List for all meshes // Create a list for the current-mesh strands string[] aseContent = File.ReadAllLines(path); List <HairMesh> hairMeshes = new List <HairMesh>(); List <HairStrand> currentStrands = new List <HairStrand>(); // Init "state"-variables int currentStrand = 0; int currentHairId = -1; float texcoordMultiplier = 0; // Now the hard part begins... for (int i = 0; i < aseContent.Length; i++) { string[] tokens = aseContent[i].Split('\t'); if (aseContent[i].Contains("*SHAPE_LINECOUNT")) { tokens = tokens[1].Split(' '); } else if (aseContent[i].Contains("SHAPE_LINE")) { tokens = tokens[1].Split(' '); } if (tokens.Length >= 2) { if (tokens[0] == "*SHAPE_LINECOUNT") { if (currentStrand > 0) { // Start parsing next mesh after flushing the current strands buffer currentHairId++; currentStrand = 0; // Add to mesh list / flush current strands buffer HairMesh hairMesh = new HairMesh(); foreach (HairStrand strand in currentStrands) { hairMesh.strands.Add(strand); } hairMeshes.Add(hairMesh); // Clear current strands currentStrands.Clear(); texcoordMultiplier = 1.0f / (float)int.Parse(tokens[1]); } } else if (tokens[0] == "*SHAPE_LINE") { HairStrand strand = new HairStrand(); strand.isGuidanceStrand = true; string[] vertexCountTokens = aseContent[i + 1].Split(' '); // Parse the current line int vertexCount = int.Parse(vertexCountTokens[1]); // Parse vertices for (int j = 0; j < vertexCount; j++) { string[] vertexTokens = aseContent[i + 2 + j].Replace('.', ',').Split('\t'); if (vertexTokens[2] == "*SHAPE_VERTEX_INTERP") { continue; } System.Globalization.NumberFormatInfo nf = new System.Globalization.NumberFormatInfo() { NumberGroupSeparator = "." }; vertexTokens[4] = vertexTokens[4].Replace(',', '.'); vertexTokens[5] = vertexTokens[5].Replace(',', '.'); vertexTokens[6] = vertexTokens[6].Replace(',', '.'); Vector3 position = new Vector3(float.Parse(vertexTokens[4], nf), float.Parse(vertexTokens[6], nf), float.Parse(vertexTokens[5], nf)); position = Vector3.Multiply(position, importSettings.scale); HairStrandVertex v = new HairStrandVertex(position, Vector3.Zero, Vector4.Zero); if (strand.vertices.Count == 0) { v.isMovable = false; } strand.vertices.Add(v); } currentStrands.Add(strand); // Increment file-line-pointer i = i + 1 + vertexCount; currentStrand++; } } } // Get last mesh HairMesh lastMesh = new HairMesh(); lastMesh.strands.AddRange(currentStrands); hairMeshes.Add(lastMesh); return(hairMeshes.ToArray()); }
public virtual HairMesh[] Import(BinaryReader reader, string path, Hair hair, HairImportSettings importSettings) { // TODO: Implement import settings HairMesh[] returnData = null; // Load header information int numVertices = reader.ReadInt32(); int numStrands = reader.ReadInt32(); // maxVerticesPerStrand is what amd calls it // Actually this should be vertices per strand, as tressfx needs a uniform vertex count on every strand // We will assume that the input file is has a uniform vertex count. // If it doesnt, the import will fail. int maxVerticesPerStrand = reader.ReadInt32(); int numGuideHairVertices = reader.ReadInt32(); int numGuideHairStrands = reader.ReadInt32(); /*int numFollowHairsPerOneGuideHair = */reader.ReadInt32(); // Load hair data information int[] strandTypes = ReadIntegerArray(reader, numStrands); Vector4[] referenceVectors = ReadVector4Array(reader, numVertices); Quaternion[] globalRotations = ReadQuaternionArray(reader, numVertices); Quaternion[] localRotations = ReadQuaternionArray(reader, numVertices); Vector4[] vertices = ReadVector4Array(reader, numVertices); Vector4[] tangents = ReadVector4Array(reader, numVertices); // Read the triangle vertices // Actually those are __NEVER__ used anywhere. // So, we are going to skip / ignore them ReadVector3Array(reader, numVertices); ReadVector3Array(reader, numVertices); ReadVector4Array(reader, numVertices); float[] thicknessCoefficients = ReadFloatArray(reader, numVertices); Vector4[] followRootOffsets = ReadVector4Array(reader, numStrands); float[] restLengths = ReadFloatArray(reader, numVertices); // Get bounding sphere hair.InitializeBoundingSphere(ReadVector3(reader), reader.ReadSingle()); // Load indices int indexTmp = reader.ReadInt32(); int[] triangleIndices = ReadIntegerArray(reader, indexTmp); indexTmp = reader.ReadInt32(); int[] lineIndices = ReadIntegerArray(reader, indexTmp); // Init indices hair.InitializeIndices(lineIndices, triangleIndices); // Set simulation data HairSimulationData simulationData = new HairSimulationData(); simulationData.followRootOffsets = followRootOffsets.ToList(); simulationData.globalRotations = globalRotations.ToList(); simulationData.guideHairStrandCount = numGuideHairStrands; simulationData.guideHairVertexCount = numGuideHairVertices; simulationData.maxNumVerticesPerStrand = maxVerticesPerStrand; simulationData.localRotations = localRotations.ToList(); simulationData.referenceVectors = referenceVectors.ToList(); simulationData.strandTypes = strandTypes.ToList(); simulationData.tangents = tangents.ToList(); simulationData.thicknessCoefficients = thicknessCoefficients.ToList(); simulationData.vertices = vertices.ToList(); simulationData.restLength = restLengths.ToList(); hair.InitializeSimulationData(simulationData); // So, the data is read now. // Next, we are going to construct the hair meshes. HairMesh[] hairMeshes = new HairMesh[4]; // Current list "pointer" int vertexPointer = 0; int strandPointer = 0; List<HairStrand> strandReferences = new List<HairStrand>(); foreach (int meshIndex in strandTypes) { // Check if we got a valid strand types array if (meshIndex < 0 || meshIndex > 3) throw new FormatException("Mesh ids (strand types) < 0 or > 3 are not supported by TressFX!"); // Get mesh and create it if it doesnt exist if (hairMeshes[meshIndex] == null) hairMeshes[meshIndex] = new HairMesh(); HairMesh mesh = hairMeshes[meshIndex]; // Create new strand HairStrand strand = new HairStrand(); strandReferences.Add(strand); strand.followRootOffset = followRootOffsets[strandPointer]; if (strand.followRootOffset.x != 0 || strand.followRootOffset.y != 0 || strand.followRootOffset.z != 0) { // This is a follow hair strand.guidanceStrand = strandReferences[(int)strand.followRootOffset.w]; strand.isGuidanceStrand = false; } else { // This is a guidance hair strand.isGuidanceStrand = true; } // Read all vertices for (int i = 0; i < maxVerticesPerStrand; i++) { // Read vertex data // As texcoord we will create a coordinate which projects the hair along the x-axis based on the strand index // and the y-axis based on the vertex index inside of the current strand HairStrandVertex vertex = new HairStrandVertex(new Vector3(vertices[vertexPointer].X, vertices[vertexPointer].Y, vertices[vertexPointer].Z), new Vector3(tangents[vertexPointer].X, tangents[vertexPointer].Y, tangents[vertexPointer].Z), new Vector4(strandPointer / (float)numStrands, i / (float)maxVerticesPerStrand, 0, 0)); // Set movable flag vertex.isMovable = (vertices[vertexPointer].W > 0); // Set simulation data vertex.globalRotation = globalRotations[vertexPointer]; vertex.localRotation = localRotations[vertexPointer]; vertex.referenceVector = referenceVectors[vertexPointer]; vertex.restLength = restLengths[vertexPointer]; vertex.thicknessCoefficient = thicknessCoefficients[vertexPointer]; // Add to strand strand.vertices.Add(vertex); vertexPointer++; } // Add strand to mesh mesh.strands.Add(strand); strandPointer++; } // Construct return array List<HairMesh> meshes = new List<HairMesh>(); for (int i = 0; i < hairMeshes.Length; i++) if (hairMeshes[i] == null) { // We're done reading break; } else { // Read the mesh meshes.Add(hairMeshes[i]); } returnData = hairMeshes.ToArray(); return returnData; }
public HairMesh[] Import(BinaryReader reader, string path, Hair hair, HairImportSettings importSettings) { reader.Close(); // Initialize the import // Load the ase file content // Create a List for all meshes // Create a list for the current-mesh strands string[] aseContent = File.ReadAllLines(path); List<HairMesh> hairMeshes = new List<HairMesh>(); List<HairStrand> currentStrands = new List<HairStrand>(); // Init "state"-variables int currentStrand = 0; int currentHairId = -1; float texcoordMultiplier = 0; // Now the hard part begins... for (int i = 0; i < aseContent.Length; i++) { string[] tokens = aseContent[i].Split('\t'); if (aseContent[i].Contains("*SHAPE_LINECOUNT")) { tokens = tokens[1].Split(' '); } else if (aseContent[i].Contains("SHAPE_LINE")) { tokens = tokens[1].Split(' '); } if (tokens.Length >= 2) { if (tokens[0] == "*SHAPE_LINECOUNT") { if (currentStrand > 0) { // Start parsing next mesh after flushing the current strands buffer currentHairId++; currentStrand = 0; // Add to mesh list / flush current strands buffer HairMesh hairMesh = new HairMesh(); foreach (HairStrand strand in currentStrands) { hairMesh.strands.Add(strand); } hairMeshes.Add(hairMesh); // Clear current strands currentStrands.Clear(); texcoordMultiplier = 1.0f / (float)int.Parse(tokens[1]); } } else if (tokens[0] == "*SHAPE_LINE") { HairStrand strand = new HairStrand(); strand.isGuidanceStrand = true; string[] vertexCountTokens = aseContent[i + 1].Split(' '); // Parse the current line int vertexCount = int.Parse(vertexCountTokens[1]); // Parse vertices for (int j = 0; j < vertexCount; j++) { string[] vertexTokens = aseContent[i + 2 + j].Replace('.', ',').Split('\t'); if (vertexTokens[2] == "*SHAPE_VERTEX_INTERP") continue; System.Globalization.NumberFormatInfo nf = new System.Globalization.NumberFormatInfo() { NumberGroupSeparator = "." }; vertexTokens[4] = vertexTokens[4].Replace(',', '.'); vertexTokens[5] = vertexTokens[5].Replace(',', '.'); vertexTokens[6] = vertexTokens[6].Replace(',', '.'); Vector3 position = new Vector3(float.Parse(vertexTokens[4], nf), float.Parse(vertexTokens[6], nf), float.Parse(vertexTokens[5], nf)); position = Vector3.Multiply(position, importSettings.scale); HairStrandVertex v = new HairStrandVertex(position, Vector3.Zero, Vector4.Zero); if (strand.vertices.Count == 0) v.isMovable = false; strand.vertices.Add(v); } currentStrands.Add(strand); // Increment file-line-pointer i = i + 1 + vertexCount; currentStrand++; } } } // Get last mesh HairMesh lastMesh = new HairMesh(); lastMesh.strands.AddRange(currentStrands); hairMeshes.Add(lastMesh); return hairMeshes.ToArray(); }
public virtual HairMesh[] Import(BinaryReader reader, string path, Hair hair, HairImportSettings importSettings) { // TODO: Implement import settings HairMesh[] returnData = null; // Load header information int numVertices = reader.ReadInt32(); int numStrands = reader.ReadInt32(); // maxVerticesPerStrand is what amd calls it // Actually this should be vertices per strand, as tressfx needs a uniform vertex count on every strand // We will assume that the input file is has a uniform vertex count. // If it doesnt, the import will fail. int maxVerticesPerStrand = reader.ReadInt32(); int numGuideHairVertices = reader.ReadInt32(); int numGuideHairStrands = reader.ReadInt32(); /*int numFollowHairsPerOneGuideHair = */ reader.ReadInt32(); // Load hair data information int[] strandTypes = ReadIntegerArray(reader, numStrands); Vector4[] referenceVectors = ReadVector4Array(reader, numVertices); Quaternion[] globalRotations = ReadQuaternionArray(reader, numVertices); Quaternion[] localRotations = ReadQuaternionArray(reader, numVertices); Vector4[] vertices = ReadVector4Array(reader, numVertices); Vector4[] tangents = ReadVector4Array(reader, numVertices); // Read the triangle vertices // Actually those are __NEVER__ used anywhere. // So, we are going to skip / ignore them ReadVector3Array(reader, numVertices); ReadVector3Array(reader, numVertices); ReadVector4Array(reader, numVertices); float[] thicknessCoefficients = ReadFloatArray(reader, numVertices); Vector4[] followRootOffsets = ReadVector4Array(reader, numStrands); float[] restLengths = ReadFloatArray(reader, numVertices); // Get bounding sphere hair.InitializeBoundingSphere(ReadVector3(reader), reader.ReadSingle()); // Load indices int indexTmp = reader.ReadInt32(); int[] triangleIndices = ReadIntegerArray(reader, indexTmp); indexTmp = reader.ReadInt32(); int[] lineIndices = ReadIntegerArray(reader, indexTmp); // Init indices hair.InitializeIndices(lineIndices, triangleIndices); // Set simulation data HairSimulationData simulationData = new HairSimulationData(); simulationData.followRootOffsets = followRootOffsets.ToList(); simulationData.globalRotations = globalRotations.ToList(); simulationData.guideHairStrandCount = numGuideHairStrands; simulationData.guideHairVertexCount = numGuideHairVertices; simulationData.maxNumVerticesPerStrand = maxVerticesPerStrand; simulationData.localRotations = localRotations.ToList(); simulationData.referenceVectors = referenceVectors.ToList(); simulationData.strandTypes = strandTypes.ToList(); simulationData.tangents = tangents.ToList(); simulationData.thicknessCoefficients = thicknessCoefficients.ToList(); simulationData.vertices = vertices.ToList(); simulationData.restLength = restLengths.ToList(); hair.InitializeSimulationData(simulationData); // So, the data is read now. // Next, we are going to construct the hair meshes. HairMesh[] hairMeshes = new HairMesh[4]; // Current list "pointer" int vertexPointer = 0; int strandPointer = 0; List <HairStrand> strandReferences = new List <HairStrand>(); foreach (int meshIndex in strandTypes) { // Check if we got a valid strand types array if (meshIndex < 0 || meshIndex > 3) { throw new FormatException("Mesh ids (strand types) < 0 or > 3 are not supported by TressFX!"); } // Get mesh and create it if it doesnt exist if (hairMeshes[meshIndex] == null) { hairMeshes[meshIndex] = new HairMesh(); } HairMesh mesh = hairMeshes[meshIndex]; // Create new strand HairStrand strand = new HairStrand(); strandReferences.Add(strand); strand.followRootOffset = followRootOffsets[strandPointer]; if (strand.followRootOffset.x != 0 || strand.followRootOffset.y != 0 || strand.followRootOffset.z != 0) { // This is a follow hair strand.guidanceStrand = strandReferences[(int)strand.followRootOffset.w]; strand.isGuidanceStrand = false; } else { // This is a guidance hair strand.isGuidanceStrand = true; } // Read all vertices for (int i = 0; i < maxVerticesPerStrand; i++) { // Read vertex data // As texcoord we will create a coordinate which projects the hair along the x-axis based on the strand index // and the y-axis based on the vertex index inside of the current strand HairStrandVertex vertex = new HairStrandVertex(new Vector3(vertices[vertexPointer].X, vertices[vertexPointer].Y, vertices[vertexPointer].Z), new Vector3(tangents[vertexPointer].X, tangents[vertexPointer].Y, tangents[vertexPointer].Z), new Vector4(strandPointer / (float)numStrands, i / (float)maxVerticesPerStrand, 0, 0)); // Set movable flag vertex.isMovable = (vertices[vertexPointer].W > 0); // Set simulation data vertex.globalRotation = globalRotations[vertexPointer]; vertex.localRotation = localRotations[vertexPointer]; vertex.referenceVector = referenceVectors[vertexPointer]; vertex.restLength = restLengths[vertexPointer]; vertex.thicknessCoefficient = thicknessCoefficients[vertexPointer]; // Add to strand strand.vertices.Add(vertex); vertexPointer++; } // Add strand to mesh mesh.strands.Add(strand); strandPointer++; } // Construct return array List <HairMesh> meshes = new List <HairMesh>(); for (int i = 0; i < hairMeshes.Length; i++) { if (hairMeshes[i] == null) { // We're done reading break; } else { // Read the mesh meshes.Add(hairMeshes[i]); } } returnData = hairMeshes.ToArray(); return(returnData); }