/// <summary> /// Loads / imports hair from the given file with given format. /// </summary> /// <param name="format"></param> /// <param name="path"></param> public static Hair Import(HairFormat format, string path, HairImportSettings importSettings = null) { if (importSettings == null) importSettings = HairImportSettings.standard; // Get hair format impl IHairFormat formatImpl = format.GetFormatImplementation(); // Create new hair object Hair hair = new Hair(); // Open the binary reader BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)); // Import the hair data HairMesh[] hairMeshes = null; try { hairMeshes = formatImpl.Import(reader, path, hair, importSettings); } finally { reader.Close(); } reader.Close(); // Validity check if (hairMeshes.Length > 4) throw new IndexOutOfRangeException("TressFX only supports up to 4 hair meshes, the file you tried to import had " + hairMeshes.Length); // Set all meshes for (int i = 0; i < hairMeshes.Length; i++) hair.SetHairMesh(i, hairMeshes[i]); // We're done :> return hair; }
/// <summary> /// Opens the hair data (tfxb) at the given path. /// </summary> /// <param name="path">Path.</param> public static void LoadHairData(this TressFXHair ext, Hair hair) { #if UNITY_EDITOR EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading information...", 0); HairSimulationData hairSimulationData = hair.hairSimulationData; // Load information variables ext.m_NumTotalHairVertices = hairSimulationData.vertexCount; ext.m_NumTotalHairStrands = hairSimulationData.strandCount; ext.m_NumOfVerticesPerStrand = hairSimulationData.maxNumVerticesPerStrand; ext.m_NumGuideHairVertices = hairSimulationData.guideHairVertexCount; ext.m_NumGuideHairStrands = hairSimulationData.guideHairStrandCount; ext.m_NumFollowHairsPerOneGuideHair = hairSimulationData.followHairsPerOneGuideHair; // Load actual hair data EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading strandtypes...", 0); ext.m_pHairStrandType = hairSimulationData.strandTypes.ToArray(); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading reference vectors...", 0.05f); ext.m_pRefVectors = Vector4Import(hairSimulationData.referenceVectors.ToArray()); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading global rotations...", 0.15f); ext.m_pGlobalRotations = QuaternionsToVector4(QuaternionImport(hairSimulationData.globalRotations.ToArray())); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading local rotations...", 0.25f); ext.m_pLocalRotations = QuaternionsToVector4(QuaternionImport(hairSimulationData.localRotations.ToArray())); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading vertices...", 0.35f); ext.m_pVertices = Vector4Import(hairSimulationData.vertices.ToArray()); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading tangents...", 0.4f); ext.m_pTangents = Vector4Import(hairSimulationData.tangents.ToArray()); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading thickness coefficients...", 0.55f); ext.m_pThicknessCoeffs = hairSimulationData.thicknessCoefficients.ToArray(); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading follow hair root offsets...", 0.65f); ext.m_pFollowRootOffset = Vector4Import(hairSimulationData.followRootOffsets.ToArray()); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading rest lengths...", 0.7f); ext.m_pRestLengths = hairSimulationData.restLength.ToArray(); // Determine how much hair strand types are available List<int> strandTypes = new List<int>(); for (int i = 0; i < ext.m_pHairStrandType.Length; i++) { if (!strandTypes.Contains(ext.m_pHairStrandType[i])) { strandTypes.Add(ext.m_pHairStrandType[i]); } } if (ext.hairPartConfig == null || ext.hairPartConfig.Length != strandTypes.Count) ext.hairPartConfig = new HairPartConfig[strandTypes.Count]; EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading bounding sphere...", 0.75f); // Load bounding sphere ext.m_bSphere = new TressFXBoundingSphere (new Vector3(hair.boundingSphere.center.x, hair.boundingSphere.center.y, hair.boundingSphere.center.z), hair.boundingSphere.radius); EditorUtility.DisplayProgressBar("Importing TressFX Hair", "Loading indices...", 0.75f); // Read triangle indices ext.m_TriangleIndices = hair.triangleIndices; // Read line indices ext.m_LineIndices = hair.lineIndices; // Set texcoords ext.m_TexCoords = Vector4Import(hair.texcoords); EditorUtility.ClearProgressBar(); // We are ready! Debug.Log ("Hair loaded. Vertices loaded: " + ext.m_NumTotalHairVertices + ", Strands: " + ext.m_NumTotalHairStrands + ", Triangle Indices: " + ext.m_TriangleIndices.Length + ", Line Indices: " + ext.m_LineIndices.Length); #endif }
/// <summary> /// TEMPORARY FUNCTION! /// THIS WILL GET REMOVED IN THE NEAR FUTURE! /// /// Prepares the simulation parameters by using a binary executable of the assetconverter from amd. /// Will return a new hair instance! /// </summary> /// <param name="followHairs"></param> /// <param name="maxRadiusAround"></param> /// <param name="assetConverterExePath"></param> /// <returns></returns> public Hair PrepareSimulationParamatersAssetConverter(int followHairs, float maxRadiusAround, string assetConverterExePath) { // Get temporary folder string tempPath = Path.GetTempPath() + "/"; List <string> meshPaths = new List <string>(); List <string> meshNames = new List <string>(); // Export all meshes int meshIndex = 0; foreach (HairMesh m in this.meshes) { if (m == null) { continue; } // Create path String path = tempPath + "mesh_" + meshIndex; if (File.Exists(path)) { File.Delete(path); } meshPaths.Add(path); meshNames.Add("mesh_" + meshIndex); // Export m.ExportAsTFX(path, followHairs, maxRadiusAround); meshIndex++; } String assetConverterTempPath = tempPath + "assetconverter.exe"; String outputPath = tempPath + "output.tfxb"; // Copy the asset converter if (File.Exists(assetConverterTempPath)) { File.Delete(assetConverterTempPath); } if (File.Exists(outputPath)) { File.Delete(outputPath); } File.Copy(assetConverterExePath, assetConverterTempPath); // Build commandline String arguments = string.Join(" ", meshNames.ToArray()); arguments += " output.tfxb"; var startInfo = new System.Diagnostics.ProcessStartInfo { WorkingDirectory = Path.GetTempPath(), WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal, FileName = assetConverterTempPath, RedirectStandardInput = true, UseShellExecute = false, Arguments = arguments }; var p = new System.Diagnostics.Process(); p.StartInfo = startInfo; p.Start(); p.WaitForExit(); // Read back the tfxb file return(Hair.Import(HairFormat.TFXB, outputPath)); }
/// <summary> /// Executes the given action on every strand on the hair. /// </summary> /// <param name="hair"></param> /// <param name="action"></param> public static void StrandLevelIteration(Hair hair, Action<HairStrand> action) { foreach (HairMesh m in hair.meshes) if (m != null) foreach (HairStrand s in m.strands) action(s); }
/// <summary> /// Executes the given action on every vertex on the hair. /// </summary> /// <param name="hair"></param> /// <param name="action"></param> public static void StrandLevelIteration(Hair hair, Action<HairStrand, HairStrandVertex> action) { foreach (HairMesh m in hair.meshes) if (m != null) foreach (HairStrand s in m.strands) foreach (HairStrandVertex v in s.vertices) action(s, v); }