Пример #1
0
        /// <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
        }
Пример #2
0
        public virtual void Export(BinaryWriter writer, string path, Hair hair)
        {
            // Get simulation data
            HairSimulationData simulationData = hair.hairSimulationData;

            int vertexCount = hair.vertexCount;

            // Write the header
            writer.Write(vertexCount);
            writer.Write(hair.strandCount);
            writer.Write(hair.maxNumVerticesPerStrand);
            writer.Write(simulationData.guideHairVertexCount);
            writer.Write(simulationData.guideHairStrandCount);
            writer.Write(simulationData.followHairsPerOneGuideHair);

            // Write data
            foreach (int strandType in simulationData.strandTypes)
            {
                writer.Write(strandType);
            }

            // Reference vectors
            foreach (Vector4 refVector in simulationData.referenceVectors)
            {
                WriteVector4(writer, refVector);
            }

            // Global rotations
            foreach (Quaternion globalRot in simulationData.globalRotations)
            {
                WriteQuaternion(writer, globalRot);
            }

            // Local rotations
            foreach (Quaternion localRot in simulationData.localRotations)
            {
                WriteQuaternion(writer, localRot);
            }

            // Position vectors
            foreach (Vector4 vertex in simulationData.vertices)
            {
                WriteVector4(writer, vertex);
            }

            // Tangent vectors
            foreach (Vector4 tangent in simulationData.tangents)
            {
                WriteVector4(writer, tangent);
            }

            // Write binary 0 as triangle vertices as they arent used anyway.
            for (int i = 0; i < vertexCount; i++)
            {
                WriteVector3(writer, Vector3.Zero); // Positions
                WriteVector3(writer, Vector3.Zero); // Tangents
                WriteVector4(writer, Vector4.Zero); // Texcoord
            }

            // Thickness coeffs
            foreach (float thicknessCoeff in simulationData.thicknessCoefficients)
            {
                writer.Write(thicknessCoeff);
            }

            // Follow root offsets vectors
            foreach (Vector4 followRootOffset in simulationData.followRootOffsets)
            {
                WriteVector4(writer, followRootOffset);
            }

            // Rest lengths
            foreach (float restLength in simulationData.restLength)
            {
                writer.Write(restLength);
            }

            // Write bounding sphere
            WriteVector3(writer, hair.boundingSphere.center);
            writer.Write(hair.boundingSphere.radius);

            // Triangle indices
            writer.Write(hair.triangleIndices.Length);
            foreach (int triangleIndices in hair.triangleIndices)
            {
                writer.Write(triangleIndices);
            }

            // Line indices
            writer.Write(hair.lineIndices.Length);
            foreach (int lineIndices in hair.lineIndices)
            {
                writer.Write(lineIndices);
            }
        }
Пример #3
0
        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;
        }
Пример #4
0
        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);
        }