public static void CreateHairData(this TressFXHair ext) { ext.m_NumTotalHairVertices = 16; ext.m_NumTotalHairStrands = 1; ext.m_NumOfVerticesPerStrand = 16; ext.m_NumGuideHairVertices = 16; ext.m_NumGuideHairStrands = 1; ext.m_NumFollowHairsPerOneGuideHair = 0; ext.m_pHairStrandType = new int[1] { 0 }; ext.m_pRefVectors = new Vector4[16]; for (int i = 0; i < 16; ++i) { ext.m_pRefVectors[i] = new Vector4(1, 0, 0, 0); } ext.m_pGlobalRotations = new Vector4[16]; for (int i = 0; i < 16; ++i) { ext.m_pGlobalRotations[i] = new Vector4(0, 0, 0, 1); } ext.m_pLocalRotations = new Vector4[16];//没用 for (int i = 0; i < 16; ++i) { ext.m_pLocalRotations[i] = new Vector4(0, 0, 0, 1); } ext.m_pVertices = new Vector4[16]; for (int i = 0; i < 16; ++i) { ext.m_pVertices[i] = new Vector4(0, -i, 0, 1); } ext.m_pVertices[0] = new Vector4(0, 0, 0, 0); ext.m_pVertices[1] = new Vector4(0, -1, 0, 0); ext.m_pTangents = new Vector4[16]; for (int i = 0; i < 16; ++i) { ext.m_pTangents[i] = new Vector4(0, -1, 0, 0); } ext.m_pThicknessCoeffs = new float[16]; for (int i = 0; i < 16; ++i) { ext.m_pThicknessCoeffs[i] = 1; } ext.m_pFollowRootOffset = new Vector4[1]; ext.m_pRestLengths = new float[16]; for (int i = 0; i < 16; ++i) { ext.m_pRestLengths[i] = 1; } ext.hairPartConfig = new HairPartConfig[1]; ext.hairPartConfig[0].Damping = 0.5f; ext.hairPartConfig[0].GlobalShapeMatchingEffectiveRange = 0.5f; ext.hairPartConfig[0].StiffnessForGlobalShapeMatching = 0.5f; ext.hairPartConfig[0].StiffnessForLocalShapeMatching = 0.5f; ext.m_bSphere = new TressFXBoundingSphere(); ext.m_TriangleIndices = new int[3]; ext.m_LineIndices = new int[16]; ext.m_TexCoords = new Vector4[16]; }
public static void CreateTestHair() { TressFXHair newHairData = ScriptableObjectUtility.CreateAsset <TressFXHair>("TestHair"); newHairData.CreateHairData(); EditorUtility.SetDirty(newHairData); AssetDatabase.SaveAssets(); }
public override void OnInspectorGUI() { // Get the tressfx hair instance TressFXHair target = (TressFXHair)this.target; EditorGUILayout.LabelField("Hair Stats"); EditorGUILayout.LabelField("-----------------------------------"); EditorGUILayout.LabelField("Total Vertices: ", target.m_NumTotalHairVertices + ""); EditorGUILayout.LabelField("Total Strands: ", target.m_NumTotalHairStrands + ""); EditorGUILayout.LabelField("Guidance Vertices: ", target.m_NumGuideHairVertices + ""); EditorGUILayout.LabelField("Guidance Strands: ", target.m_NumGuideHairStrands + ""); EditorGUILayout.LabelField("Maximum Verts / strand: ", target.m_NumOfVerticesPerStrand + ""); EditorGUILayout.LabelField("Follow strands per strand: ", target.m_NumFollowHairsPerOneGuideHair + ""); for (int i = 0; i < target.hairPartConfig.Length; i++) { EditorGUILayout.LabelField(""); EditorGUILayout.LabelField("Hair section " + i); EditorGUILayout.LabelField("-----------------------------------"); target.hairPartConfig[i].Damping = EditorGUILayout.FloatField("Damping", target.hairPartConfig[i].Damping); target.hairPartConfig[i].StiffnessForLocalShapeMatching = EditorGUILayout.FloatField("LSM stiffness", target.hairPartConfig[i].StiffnessForLocalShapeMatching); target.hairPartConfig[i].StiffnessForGlobalShapeMatching = EditorGUILayout.FloatField("GSM stiffness", target.hairPartConfig[i].StiffnessForGlobalShapeMatching); target.hairPartConfig[i].GlobalShapeMatchingEffectiveRange = EditorGUILayout.FloatField("GSM effective range", target.hairPartConfig[i].GlobalShapeMatchingEffectiveRange); } // Save hair data if (GUILayout.Button("Save")) { EditorUtility.SetDirty(target); AssetDatabase.SaveAssets(); } /* * // Load new hair data TFXB * if (GUILayout.Button("Load new Hairdata (TFXB)")) * { * // Load new hair file * string hairfilePath = EditorUtility.OpenFilePanel ("Open TressFX Hair data", "", "tfxb"); * target.LoadHairData (Hair.Import(HairFormat.TFXB, hairfilePath)); * * // Save * EditorUtility.SetDirty(target); * AssetDatabase.SaveAssets(); * } * * // Load new hair data ASE * if (GUILayout.Button("Load new Hairdata (ASE)")) * { * // Load new hair file * string hairfilePath = EditorUtility.OpenFilePanel ("Open TressFX Hair data", "", "ase"); * target.LoadHairData (Hair.Import(HairFormat.ASE, hairfilePath)); * * // Save * EditorUtility.SetDirty(target); * AssetDatabase.SaveAssets(); * } */ }
public static void CreateAssetTFXB() { string hairfilePath = EditorUtility.OpenFilePanel("Open TressFX Hair data", "", "tfxb"); string hairfileName = System.IO.Path.GetFileNameWithoutExtension(hairfilePath); // Create new hair asset TressFXHair newHairData = ScriptableObjectUtility.CreateAsset <TressFXHair> (hairfileName); // Open hair data Hair hair = Hair.Import(HairFormat.TFXB, hairfilePath, TressFXEditorWindow.GetImportSettings()); hair.CreateUVs(); newHairData.LoadHairData(hair); EditorUtility.SetDirty(newHairData); AssetDatabase.SaveAssets(); }
public override void OnInspectorGUI() { // Get the tressfx hair instance TressFXHair target = (TressFXHair)this.target; EditorGUILayout.LabelField("Hair Stats"); EditorGUILayout.LabelField("-----------------------------------"); EditorGUILayout.LabelField("Total Vertices: ", target.m_NumTotalHairVertices + ""); EditorGUILayout.LabelField("Total Strands: ", target.m_NumTotalHairStrands + ""); EditorGUILayout.LabelField("Guidance Vertices: ", target.m_NumGuideHairVertices + ""); EditorGUILayout.LabelField("Guidance Strands: ", target.m_NumGuideHairStrands + ""); EditorGUILayout.LabelField("Maximum Verts / strand: ", target.m_NumOfVerticesPerStrand + ""); EditorGUILayout.LabelField("Follow strands per strand: ", target.m_NumFollowHairsPerOneGuideHair + ""); for (int i = 0; i < target.hairPartConfig.Length; i++) { EditorGUILayout.LabelField(""); EditorGUILayout.LabelField("Hair section " + i); EditorGUILayout.LabelField("-----------------------------------"); target.hairPartConfig[i].Damping = EditorGUILayout.FloatField("Damping", target.hairPartConfig[i].Damping); target.hairPartConfig[i].StiffnessForLocalShapeMatching = EditorGUILayout.FloatField("LSM stiffness", target.hairPartConfig[i].StiffnessForLocalShapeMatching); target.hairPartConfig[i].StiffnessForGlobalShapeMatching = EditorGUILayout.FloatField("GSM stiffness", target.hairPartConfig[i].StiffnessForGlobalShapeMatching); target.hairPartConfig[i].GlobalShapeMatchingEffectiveRange = EditorGUILayout.FloatField("GSM effective range", target.hairPartConfig[i].GlobalShapeMatchingEffectiveRange); } // Merge EditorGUILayout.LabelField("Drag tressfx hair here to merge"); TressFXHair mergeHair = (TressFXHair)EditorGUILayout.ObjectField(null, typeof(TressFXHair), false); if (mergeHair != null) { target.MergeIntoThis(mergeHair); } // Save hair data if (GUILayout.Button("Save")) { EditorUtility.SetDirty(target); AssetDatabase.SaveAssets(); } }
public static void CreateAssetOBJ() { string hairfilePath = EditorUtility.OpenFilePanel("Open OBJ Hair data", "", "obj"); string hairfileName = System.IO.Path.GetFileNameWithoutExtension(hairfilePath); // Create new hair asset TressFXHair newHairData = ScriptableObjectUtility.CreateAsset <TressFXHair>(hairfileName); // Open hair data Hair hair = Hair.Import(HairFormat.OBJ, hairfilePath, TressFXEditorWindow.GetImportSettings()); if (TressFXEditorWindow.normalizeVertexCountActive && TressFXEditorWindow.normalizeVertexCount > 2) { hair.NormalizeStrands(TressFXEditorWindow.normalizeVertexCount); } hair = hair.PrepareSimulationParamatersAssetConverter(TressFXEditorWindow.followHairCount, TressFXEditorWindow.maxRadiusAroundGuideHair, Application.dataPath + "/" + EditorPrefs.GetString("TressFXAssetConverterPath")); hair.CreateUVs(); newHairData.LoadHairData(hair); EditorUtility.SetDirty(newHairData); AssetDatabase.SaveAssets(); }
/// <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> /// Merges other into this tressfx hair. /// </summary> /// <param name="other"></param> public void MergeIntoThis(TressFXHair other) { if (this.hairPartConfig.Length + other.hairPartConfig.Length > 4) { throw new Exception("Tressfx merge error! Hair cannot have more than 4 parts"); } // Head info check if (this.m_NumOfVerticesPerStrand != other.m_NumOfVerticesPerStrand) { throw new Exception("Tressfx merge error! Hair vertex count per strand must match!"); } /*int newPartCount = this.hairPartConfig.Length + other.hairPartConfig.Length; * int otherPartCount = other.hairPartConfig.Length;*/ int thisPartCount = this.hairPartConfig.Length; // Create lists List <int> pHairStrandType = new List <int>(this.m_pHairStrandType); List <Vector4> pRefVectors = new List <Vector4>(this.m_pRefVectors); List <Vector4> pGlobalRotations = new List <Vector4>(this.m_pGlobalRotations); List <Vector4> pLocalRotations = new List <Vector4>(this.m_pLocalRotations); List <Vector4> pVertices = new List <Vector4>(this.m_pVertices); List <Vector4> pTangents = new List <Vector4>(this.m_pTangents); List <float> pThicknessCoeffs = new List <float>(this.m_pThicknessCoeffs); List <Vector4> pFollowRootOffset = new List <Vector4>(this.m_pFollowRootOffset); List <float> pRestLengths = new List <float>(this.m_pRestLengths); List <int> triangleIndices = new List <int>(this.m_TriangleIndices); List <int> lineIndices = new List <int>(this.m_LineIndices); List <Vector4> texCoords = new List <Vector4>(this.m_TexCoords); // Prepare new strand types List <int> tmpIntList = new List <int>(); for (int i = 0; i < other.m_pHairStrandType.Length; i++) { tmpIntList.Add(other.m_pHairStrandType[i] + thisPartCount); } // Add up new strand types pHairStrandType.AddRange(tmpIntList); tmpIntList.Clear(); // Prepare indices // TRIANGLES int indexOffset = this.m_pVertices.Length; for (int i = 0; i < other.m_TriangleIndices.Length; i++) { tmpIntList.Add(other.m_TriangleIndices[i] + indexOffset); } // Add new triangle indices triangleIndices.AddRange(tmpIntList); tmpIntList.Clear(); // LINES for (int i = 0; i < other.m_LineIndices.Length; i++) { tmpIntList.Add(other.m_LineIndices[i] + indexOffset); } // Add new triangle indices lineIndices.AddRange(tmpIntList); tmpIntList.Clear(); // Add up static stuff pRefVectors.AddRange(other.m_pRefVectors); pGlobalRotations.AddRange(other.m_pGlobalRotations); pLocalRotations.AddRange(other.m_pLocalRotations); pVertices.AddRange(other.m_pVertices); pTangents.AddRange(other.m_pTangents); pThicknessCoeffs.AddRange(other.m_pThicknessCoeffs); pFollowRootOffset.AddRange(other.m_pFollowRootOffset); pRestLengths.AddRange(other.m_pRestLengths); texCoords.AddRange(other.m_TexCoords); // Write back to this this.m_pHairStrandType = pHairStrandType.ToArray(); this.m_pRefVectors = pRefVectors.ToArray(); this.m_pGlobalRotations = pGlobalRotations.ToArray(); this.m_pLocalRotations = pLocalRotations.ToArray(); this.m_pVertices = pVertices.ToArray(); this.m_pTangents = pTangents.ToArray(); this.m_pThicknessCoeffs = pThicknessCoeffs.ToArray(); this.m_pFollowRootOffset = pFollowRootOffset.ToArray(); this.m_pRestLengths = pRestLengths.ToArray(); this.m_TriangleIndices = triangleIndices.ToArray(); this.m_LineIndices = lineIndices.ToArray(); this.m_TexCoords = texCoords.ToArray(); // Part configs List <HairPartConfig> partConfigs = new List <HairPartConfig>(); partConfigs.AddRange(this.hairPartConfig); partConfigs.AddRange(other.hairPartConfig); this.hairPartConfig = partConfigs.ToArray(); // Recalc header this.m_NumTotalHairVertices = pVertices.Count; this.m_NumTotalHairStrands = this.m_NumTotalHairStrands + other.m_NumTotalHairStrands; this.m_NumGuideHairVertices = this.m_NumGuideHairVertices + other.m_NumGuideHairVertices; this.m_NumGuideHairStrands = this.m_NumGuideHairStrands + other.m_NumGuideHairStrands; // Bounds Bounds newBounds = new Bounds(this.m_bSphere.center, Vector3.one * this.m_bSphere.radius); newBounds.Encapsulate(new Bounds(other.m_bSphere.center, Vector3.one * this.m_bSphere.radius)); this.m_bSphere.center = newBounds.center; this.m_bSphere.radius = Mathf.Max(newBounds.extents.x, newBounds.extents.y, newBounds.extents.z); }
/// <summary> /// Merges other into this tressfx hair. /// </summary> /// <param name="other"></param> public void MergeIntoThis(TressFXHair other) { if (this.hairPartConfig.Length + other.hairPartConfig.Length > 4) throw new Exception("Tressfx merge error! Hair cannot have more than 4 parts"); // Head info check if (this.m_NumOfVerticesPerStrand != other.m_NumOfVerticesPerStrand) throw new Exception("Tressfx merge error! Hair vertex count per strand must match!"); /*int newPartCount = this.hairPartConfig.Length + other.hairPartConfig.Length; int otherPartCount = other.hairPartConfig.Length;*/ int thisPartCount = this.hairPartConfig.Length; // Create lists List<int> pHairStrandType = new List<int>(this.m_pHairStrandType); List<Vector4> pRefVectors = new List<Vector4>(this.m_pRefVectors); List<Vector4> pGlobalRotations = new List<Vector4>(this.m_pGlobalRotations); List<Vector4> pLocalRotations = new List<Vector4>(this.m_pLocalRotations); List<Vector4> pVertices = new List<Vector4>(this.m_pVertices); List<Vector4> pTangents = new List<Vector4>(this.m_pTangents); List<float> pThicknessCoeffs = new List<float>(this.m_pThicknessCoeffs); List<Vector4> pFollowRootOffset = new List<Vector4>(this.m_pFollowRootOffset); List<float> pRestLengths = new List<float>(this.m_pRestLengths); List<int> triangleIndices = new List<int>(this.m_TriangleIndices); List<int> lineIndices = new List<int>(this.m_LineIndices); List<Vector4> texCoords = new List<Vector4>(this.m_TexCoords); // Prepare new strand types List<int> tmpIntList = new List<int>(); for (int i = 0; i < other.m_pHairStrandType.Length; i++) { tmpIntList.Add(other.m_pHairStrandType[i] + thisPartCount); } // Add up new strand types pHairStrandType.AddRange(tmpIntList); tmpIntList.Clear(); // Prepare indices // TRIANGLES int indexOffset = this.m_pVertices.Length; for (int i = 0; i < other.m_TriangleIndices.Length; i++) { tmpIntList.Add(other.m_TriangleIndices[i] + indexOffset); } // Add new triangle indices triangleIndices.AddRange(tmpIntList); tmpIntList.Clear(); // LINES for (int i = 0; i < other.m_LineIndices.Length; i++) { tmpIntList.Add(other.m_LineIndices[i] + indexOffset); } // Add new triangle indices lineIndices.AddRange(tmpIntList); tmpIntList.Clear(); // Add up static stuff pRefVectors.AddRange(other.m_pRefVectors); pGlobalRotations.AddRange(other.m_pGlobalRotations); pLocalRotations.AddRange(other.m_pLocalRotations); pVertices.AddRange(other.m_pVertices); pTangents.AddRange(other.m_pTangents); pThicknessCoeffs.AddRange(other.m_pThicknessCoeffs); pFollowRootOffset.AddRange(other.m_pFollowRootOffset); pRestLengths.AddRange(other.m_pRestLengths); texCoords.AddRange(other.m_TexCoords); // Write back to this this.m_pHairStrandType = pHairStrandType.ToArray(); this.m_pRefVectors = pRefVectors.ToArray(); this.m_pGlobalRotations = pGlobalRotations.ToArray(); this.m_pLocalRotations = pLocalRotations.ToArray(); this.m_pVertices = pVertices.ToArray(); this.m_pTangents = pTangents.ToArray(); this.m_pThicknessCoeffs = pThicknessCoeffs.ToArray(); this.m_pFollowRootOffset = pFollowRootOffset.ToArray(); this.m_pRestLengths = pRestLengths.ToArray(); this.m_TriangleIndices = triangleIndices.ToArray(); this.m_LineIndices = lineIndices.ToArray(); this.m_TexCoords = texCoords.ToArray(); // Part configs List<HairPartConfig> partConfigs = new List<HairPartConfig>(); partConfigs.AddRange(this.hairPartConfig); partConfigs.AddRange(other.hairPartConfig); this.hairPartConfig = partConfigs.ToArray(); // Recalc header this.m_NumTotalHairVertices = pVertices.Count; this.m_NumTotalHairStrands = this.m_NumTotalHairStrands + other.m_NumTotalHairStrands; this.m_NumGuideHairVertices = this.m_NumGuideHairVertices + other.m_NumGuideHairVertices; this.m_NumGuideHairStrands = this.m_NumGuideHairStrands + other.m_NumGuideHairStrands; // Bounds Bounds newBounds = new Bounds(this.m_bSphere.center, Vector3.one * this.m_bSphere.radius); newBounds.Encapsulate(new Bounds(other.m_bSphere.center, Vector3.one * this.m_bSphere.radius)); this.m_bSphere.center = newBounds.center; this.m_bSphere.radius = Mathf.Max(newBounds.extents.x, newBounds.extents.y, newBounds.extents.z); }