Esempio n. 1
0
        protected override void _SimulationStep(float timestep)
        {
            HairStrand[] strands    = this.instance.strands.cpuReference;
            Vector3[]    vertices   = this.instance.vertices.cpuReference;
            uint[]       movability = this.instance.movability.cpuReference;

            for (int s = 0; s < strands.Length; s++)
            {
                HairStrand strand = strands[s];
                for (int j = strand.firstVertex + 1; j <= strand.lastVertex; j++)
                {
                    if (!HairMovability.IsMovable(j, movability))
                    {
                        continue;
                    }

                    float   nDist = this.lengths[j];
                    Vector3 p = vertices[j], pPrev = vertices[j - 1], pDir = (p - pPrev);
                    float   dist     = pDir.magnitude;
                    float   distDiff = (nDist - dist);

                    vertices[j] = p + ((pDir / dist) * (distDiff * this.stiffness * timestep));
                }
            }

            this.instance.vertices.SetGPUDirty();
        }
Esempio n. 2
0
        private void CalculateTransforms(HairStrand[] strands, Vector3[] vertices, NativeArray <quaternion> localTransforms, NativeArray <quaternion> globalTransforms, NativeArray <float3> referenceVectors)
        {
            for (int i = 0; i < strands.Length; i++)
            {
                HairStrand strand = strands[i];
                int        j;

                // First vertex
                Quaternion local;
                local = globalTransforms[strand.firstVertex] = localTransforms[strand.firstVertex] = Quaternion.LookRotation((vertices[strand.firstVertex + 1] - vertices[strand.firstVertex]).normalized);

                for (j = strand.firstVertex + 1; j < strand.lastVertex; j++)
                {
                    Vector3 p1 = vertices[j - 1], p2 = vertices[j], d = (p2 - p1);
                    Vector3 vec = Quaternion.Inverse(globalTransforms[j - 1]) * d;
                    if (vec.magnitude < 0.001f)
                    {
                        local = Quaternion.identity;
                    }
                    else
                    {
                        local = Quaternion.LookRotation(vec.normalized);
                    }

                    referenceVectors[j] = vec;
                    globalTransforms[j] = globalTransforms[j - 1] * local;
                    localTransforms[j]  = local;
                }
            }
        }
Esempio n. 3
0
            public void Execute(int index)
            {
                HairStrand strand    = this.strands[index];
                quaternion rotGlobal = this.globalTransform[strand.firstVertex];

                for (int j = strand.firstVertex + 1; j < strand.lastVertex - 1; j++)
                {
                    quaternion rotGlobalWorld = math.mul(rotation, rotGlobal);

                    float3 p1 = vertices[j], p2 = vertices[j + 1];
                    float3 orgP2 = math.mul(rotGlobalWorld, this.referenceVectors[j + 1]) + p1;
                    float3 delta = stiffness * (orgP2 - p2);

                    if (HairMovability.IsMovable(j, movability))
                    {
                        p1 -= delta;
                    }
                    if (HairMovability.IsMovable(j + 1, movability))
                    {
                        p2 += delta;
                    }

                    float3 vec = (p2 - p1);

                    rotGlobal       = math.mul(rotGlobal, quaternion.LookRotation(math.normalize(math.mul(math.inverse(rotGlobalWorld), vec)), new float3(0, 1, 0)));
                    vertices[j]     = p1;
                    vertices[j + 1] = p2;
                }
            }
        protected override void _SimulationStep(float timestep)
        {
            NativeArray <float3>     vertices   = this.instance.vertices.CpuReference;
            NativeArray <uint>       movability = this.instance.movability.CpuReference;
            NativeArray <HairStrand> strands    = this.instance.strands.CpuReference;

            Matrix4x4 matrix = this.transform.localToWorldMatrix;

            for (int j = 0; j < strands.Length; j++)
            {
                HairStrand strand = strands[j];
                int        target = Mathf.Min(strand.firstVertex + this.vertexRange, strand.lastVertex);
                for (int i = strand.firstVertex; i <= target; i++)
                {
                    if (!HairMovability.IsMovable(i, movability))
                    {
                        continue;
                    }

                    Vector3 iV = this.simulation.initialVertices[i], v = vertices[i];
                    iV = matrix.MultiplyPoint3x4(iV);

                    Vector3 delta = (iV - v);
                    vertices[i] = v + (delta * this.stiffness * timestep);
                }
            }

            this.instance.vertices.SetGPUDirty();
        }
Esempio n. 5
0
        public override void InitializeSimulation()
        {
            this.lengths = new float[this.instance.vertexCount];
            HairStrand[] strands  = this.instance.strands.cpuReference;
            Vector3[]    vertices = this.instance.vertices.cpuReference;

            for (int s = 0; s < strands.Length; s++)
            {
                HairStrand strand = strands[s];
                for (int j = strand.firstVertex + 1; j < strand.lastVertex; j++)
                {
                    this.lengths[j] = Vector3.Distance(vertices[j], vertices[j - 1]);
                }
            }
        }
Esempio n. 6
0
        public override void InitializeSimulation()
        {
            this.lengths = new NativeArray <float>(this.instance.vertexCount, Allocator.Persistent);
            NativeArray <HairStrand> strands  = this.instance.strands.CpuReference;
            NativeArray <float3>     vertices = this.instance.vertices.CpuReference;

            for (int s = 0; s < strands.Length; s++)
            {
                HairStrand strand = strands[s];
                for (int j = strand.firstVertex + 1; j < strand.lastVertex; j++)
                {
                    this.lengths[j] = math.distance(vertices[j], vertices[j - 1]);
                }
            }
        }
Esempio n. 7
0
        protected override void _SimulationStep(float timestep)
        {
            float stiffness = .5f * Mathf.Min(this.stiffness * timestep, .95f);

            HairStrand[] strands    = this.instance.strands.cpuReference;
            Vector3[]    vertices   = this.instance.vertices.cpuReference;
            uint[]       movability = this.instance.movability.cpuReference;
            Quaternion   rotation   = this.transform.rotation;

            // Apply local shape constraint
            for (int i = 0; i < strands.Length; i++)
            {
                HairStrand strand    = strands[i];
                Quaternion rotGlobal = this.globalTransform[strand.firstVertex];

                realtimeDebug[strand.firstVertex] = rotGlobal;
                for (int j = strand.firstVertex + 1; j < strand.lastVertex - 1; j++)
                {
                    Quaternion rotGlobalWorld = rotation * rotGlobal;

                    Vector3 p1 = vertices[j], p2 = vertices[j + 1];
                    Vector3 orgP2 = rotGlobalWorld * this.referenceVectors[j + 1] + p1;
                    Vector3 delta = stiffness * (orgP2 - p2);

                    if (HairMovability.IsMovable(j, movability))
                    {
                        p1 -= delta;
                    }
                    if (HairMovability.IsMovable(j + 1, movability))
                    {
                        p2 += delta;
                    }

                    Vector3 vec = (p2 - p1);

                    rotGlobal        = rotGlobal * Quaternion.LookRotation((Quaternion.Inverse(rotGlobalWorld) * vec).normalized);
                    vertices[j]      = p1;
                    vertices[j + 1]  = p2;
                    realtimeDebug[j] = rotGlobal;
                }
                realtimeDebug[strand.lastVertex] = rotGlobal;
            }

            this.instance.vertices.SetGPUDirty();
        }
            public void Execute(int index)
            {
                HairStrand strand = this.strands[index];

                for (int j = strand.firstVertex + 1; j <= strand.lastVertex; j++)
                {
                    if (!HairMovability.IsMovable(j, movability))
                    {
                        continue;
                    }

                    float  nDist = this.lengths[j];
                    float3 p = vertices[j], pPrev = vertices[j - 1], pDir = (p - pPrev);
                    float  dist     = math.length(pDir);
                    float  distDiff = (nDist - dist);

                    vertices[j] = p + ((pDir / dist) * (distDiff * this.stiffness * timestep));
                }
            }
Esempio n. 9
0
            public void Execute(int j)
            {
                HairStrand strand = strands[j];
                int        target = Mathf.Min(strand.firstVertex + this.vertexRange, strand.lastVertex);

                for (int i = strand.firstVertex; i <= target; i++)
                {
                    if (!HairMovability.IsMovable(i, movability))
                    {
                        continue;
                    }

                    float3 iV = initialVertices[i], v = vertices[i];
                    float4 iV4 = new float4(iV.x, iV.y, iV.z, 1);
                    iV = math.mul(matrix, iV4).xyz;

                    float3 delta = (iV - v);
                    vertices[i] = v + (delta * this.stiffness * timestep);
                }
            }
        private void UpdateMeshInitial()
        {
            this._indices.Clear();
            this.instance.strands.cpuReference.CopyTo(this._strands, 0);

            int sLen = _strands.Length;

            for (int i = 0; i < sLen; i++)
            {
                HairStrand strand = this._strands[i];
                for (int j = strand.firstVertex; j < strand.lastVertex; j++)
                {
                    this._indices.Add(j);
                    this._indices.Add(j + 1);
                }
            }

            UpdateMesh();
            mesh.SetIndices(this._indices.ToArray(), MeshTopology.Lines, 0);
        }
            public void Execute(int index)
            {
                HairStrand strand = this.strands[index];
                float3     lastFramePosWS, lastFramePosOS, posWS, newPos;

                lastFramePosOS = lastFramePosWS = posWS = newPos = new float3();

                // First vertex is immovable
                float3 initialPos = initialVertices[strand.firstVertex];

                vertices[strand.firstVertex] = math.mul(matrix, new float4(initialPos.x, initialPos.y, initialPos.z, 1)).xyz;

                for (int i = strand.firstVertex; i <= strand.lastVertex; i++)
                {
                    if (!HairMovability.IsMovable(i, movability))
                    {
                        continue;
                    }

                    lastFramePosWS = vertices[i];
                    float4 lastFramePosWS4 = new float4(lastFramePosWS.x, lastFramePosWS.y, lastFramePosWS.z, 1);
                    lastFramePosOS = math.mul(invPrevMatrix, lastFramePosWS4).xyz;
                    float4 lastFramePosOS4 = new float4(lastFramePosOS.x, lastFramePosOS.y, lastFramePosOS.z, 1);

                    posWS = math.mul(matrix, lastFramePosOS4).xyz;

                    // Unoptimized:
                    // newPos = posWS + (lastFramePosWS - posWS) + (gravity * (timestep * timestep));

                    // Optimized version:
                    newPos.x = posWS.x + (lastFramePosWS.x - posWS.x) + (gravity.x * timestepSqr);
                    newPos.y = posWS.y + (lastFramePosWS.y - posWS.y) + (gravity.y * timestepSqr);
                    newPos.z = posWS.z + (lastFramePosWS.z - posWS.z) + (gravity.z * timestepSqr);

                    vertices[i] = newPos;
                }
            }
Esempio n. 12
0
 /// <summary>
 /// Allocates and returns a copy of <see cref="strands"/>
 /// </summary>
 public HairStrand[] GetStrandData()
 {
     HairStrand[] strands = new HairStrand[this.strands.Length];
     System.Array.Copy(this.strands, strands, strands.Length);
     return(strands);
 }
Esempio n. 13
0
        public void Start()
        {
            List <FollowHairStrand> followHairs = new List <FollowHairStrand>();



            List <TriangulatedSegment> segments = new List <TriangulatedSegment>();

            // Triangulate
            var strands = this.instance.strands.cpuReference;

            {
                int vCtr = 0;
                for (int sIndex = 0; sIndex < strands.Length; sIndex++)
                {
                    HairStrand strand = strands[sIndex];
                    for (int vIndex = strand.firstVertex; vIndex < strand.lastVertex - 1; vIndex++)
                    {
                        // Build segment
                        TriangulatedSegment segment = new TriangulatedSegment()
                        {
                            hairVertexIndex1 = vIndex,
                            hairVertexIndex2 = vIndex + 1,
                            v1                 = vCtr++,
                            v2                 = vCtr++,
                            v3                 = vCtr++,
                            v4                 = vCtr++,
                            strandIndex        = sIndex,
                            strandVertexIndex1 = vIndex - strand.firstVertex,
                            strandVertexIndex2 = (vIndex + 1) - strand.firstVertex
                        };

                        segments.Add(segment);
                    }
                }
            }
            this.segments = new NativeArray <TriangulatedSegment>(segments.Count, Allocator.Persistent);
            this.segments.CopyFrom(segments.ToArray());

            // Distribute uv and indices
            this.uvs         = new NativeArray <float3>(segments.Count * 4, Allocator.Persistent);
            this.normals     = new NativeArray <float3>(segments.Count * 4, Allocator.Persistent);
            this.triVertices = new NativeArray <float3>(segments.Count * 4, Allocator.Persistent);
            this.indices     = new NativeArray <int>(segments.Count * 6, Allocator.Persistent);

            for (int i = 0; i < segments.Count; i++)
            {
                var segment = segments[i];

                // Calc uv
                float3 uv1, uv2, uv3, uv4;
                uv1 = uv2 = uv3 = uv4 = float3.zero;
                switch (this.uvDistStrat)
                {
                case UVDistributionStrategy.ALONG_STRAND_Y:
                {
                    HairStrand hs = strands[segment.strandIndex];
                    float      y  = segment.strandVertexIndex1 / (hs.lastVertex - hs.firstVertex);
                    float      y2 = segment.strandVertexIndex2 / (hs.lastVertex - hs.firstVertex);

                    uv1 = new float3(0, y, 0);
                    uv2 = new float3(1, y, 0);
                    uv3 = new float3(0, y2, 0);
                    uv4 = new float3(1, y2, 0);
                }
                break;
                }

                this.uvs[segment.v1] = uv1;
                this.uvs[segment.v2] = uv2;
                this.uvs[segment.v3] = uv3;
                this.uvs[segment.v4] = uv4;

                // Write indices
                this.indices[(i * 6)]     = segment.v1;
                this.indices[(i * 6) + 1] = segment.v2;
                this.indices[(i * 6) + 2] = segment.v4;
                this.indices[(i * 6) + 3] = segment.v4;
                this.indices[(i * 6) + 4] = segment.v3;
                this.indices[(i * 6) + 5] = segment.v1;
            }

            this.uvs.CopyFrom(uvs.ToArray());
            this.indices.CopyFrom(indices.ToArray());

            this.splineVertices = new NativeArray <float3>(this.instance.asset.vertexCount, Allocator.Persistent);
            NoAllocHelpers.SetMesh(this.mesh, this.triVertices, this.uvs, this.normals, this.indices);
        }
Esempio n. 14
0
        public void Start()
        {
            List <TriangulatedSegment> segments = new List <TriangulatedSegment>();

            // Triangulate
            var strands = this.instance.strands.CpuReference;

            {
                int vCtr = 0;
                for (int sIndex = 0; sIndex < strands.Length; sIndex++)
                {
                    HairStrand strand = strands[sIndex];
                    for (int vIndex = strand.firstVertex; vIndex < strand.lastVertex - 1; vIndex++)
                    {
                        // Build segment
                        TriangulatedSegment segment = new TriangulatedSegment()
                        {
                            hairVertexIndex1 = vIndex,
                            hairVertexIndex2 = vIndex + 1,
                            v1                 = vCtr++,
                            v2                 = vCtr++,
                            v3                 = vCtr++,
                            v4                 = vCtr++,
                            strandIndex        = sIndex,
                            strandVertexIndex1 = vIndex - strand.firstVertex,
                            strandVertexIndex2 = (vIndex + 1) - strand.firstVertex
                        };

                        segments.Add(segment);
                    }
                }
            }
            this.segments = new NativeArray <TriangulatedSegment>(segments.Count, Allocator.Persistent);
            this.segments.CopyFrom(segments.ToArray());

            // Distribute uv and indices
            this.uvs         = new NativeArray <float2>(segments.Count * 4, Allocator.Persistent);
            this.normals     = new NativeArray <float3>(segments.Count * 4, Allocator.Persistent);
            this.triVertices = new NativeArray <float3>(segments.Count * 4, Allocator.Persistent);
            this.indices     = new NativeArray <int>(segments.Count * 6, Allocator.Persistent);

            for (int i = 0; i < segments.Count; i++)
            {
                var segment = segments[i];

                // Calc uv
                float2 uv1, uv2, uv3, uv4;
                uv1 = uv2 = uv3 = uv4 = float2.zero;
                switch (this.uvDistStrat)
                {
                case UVDistributionStrategy.ALONG_STRAND_Y:
                {
                    HairStrand hs = strands[segment.strandIndex];
                    float      y  = segment.strandVertexIndex1 / (hs.lastVertex - hs.firstVertex);
                    float      y2 = segment.strandVertexIndex2 / (hs.lastVertex - hs.firstVertex);

                    uv1 = new float2(0, y);
                    uv2 = new float2(1, y);
                    uv3 = new float2(0, y2);
                    uv4 = new float2(1, y2);
                }
                break;
                }

                this.uvs[segment.v1] = uv1;
                this.uvs[segment.v2] = uv2;
                this.uvs[segment.v3] = uv3;
                this.uvs[segment.v4] = uv4;

                // Write indices
                this.indices[(i * 6)]     = segment.v1;
                this.indices[(i * 6) + 1] = segment.v2;
                this.indices[(i * 6) + 2] = segment.v4;
                this.indices[(i * 6) + 3] = segment.v4;
                this.indices[(i * 6) + 4] = segment.v3;
                this.indices[(i * 6) + 5] = segment.v1;
            }

            this.uvs.CopyFrom(uvs.ToArray());
            this.indices.CopyFrom(indices.ToArray());

            this.splineVertices = new NativeArray <float3>(this.instance.asset.VertexCount, Allocator.Persistent);

            // Init mesh
            this.mesh.SetVertices <float3>(triVertices);
            this.mesh.SetUVs <float2>(0, uvs);
            this.mesh.SetNormals <float3>(normals);
            this.mesh.SetIndices <int>(indices, MeshTopology.Triangles, 0);

            LateUpdate();
            this.mesh.RecalculateBounds();
            this.mesh.bounds = new Bounds(this.mesh.bounds.center, Vector3.Scale(transform.lossyScale, this.mesh.bounds.size) * 3f);             // Approximation, real bounding box calculation is difficult to do fast.
        }