Exemple #1
0
        private float GetFaceMappingError(MasterFace triangle,
                                          SlaveVertex vertex,
                                          Vector3 normal)
        {
            // initialize the error with barycentric coords error (larger the further away we are from the triangle's limits):
            float bary_error = GetBarycentricError(vertex.position.barycentricCoords) * barycentricWeight;
            float error      = bary_error;

            // calculate deviation of point normal from face normal, use it to weight normal barycentric error:
            float normal_deviation = Mathf.Clamp01(0.5f * (1.0f - Mathf.Abs(Vector3.Dot(triangle.faceNormal, normal))));

            error += normal_deviation * GetBarycentricError(vertex.normal.barycentricCoords) * normalAlignmentWeight;

            // make height relative to triangle size, and calculate error weight based on barycentric error:
            float height_val = vertex.position.height / triangle.size;
            float height_w   = 0.3f + 2.5f * bary_error;

            error += height_w * Mathf.Abs(height_val) * elevationWeight;

            return(error);
        }
Exemple #2
0
        private bool BindToFace(int slaveIndex,
                                MasterFace triangle,
                                Vector3 position,
                                Vector3 normalPoint,
                                Vector3 tangentPoint,
                                out SlaveVertex skinning)
        {
            skinning = SlaveVertex.empty;

            BarycentricPoint posBary;

            if (FindSkinBarycentricCoords(triangle, position, 24, 0.001f, out posBary))
            {
                BarycentricPoint normBary;
                BarycentricPoint tangentBary;
                FindSkinBarycentricCoords(triangle, normalPoint, 16, 0.005f, out normBary);
                FindSkinBarycentricCoords(triangle, tangentPoint, 16, 0.005f, out tangentBary);

                skinning = new SlaveVertex(slaveIndex, triangle.index, posBary, normBary, tangentBary);

                return(true);
            }
            return(false);
        }
Exemple #3
0
        public IEnumerator Bind()
        {
            Clear();

            if (master == null || slave == null)
            {
                yield break;
            }

            Vector3[] slavePositions = slave.vertices;
            Vector3[] slaveNormals   = slave.normals;
            Vector4[] slaveTangents  = slave.tangents;

            Matrix4x4 s2world       = m_SlaveTransform.GetMatrix4X4();
            Matrix4x4 s2worldNormal = s2world.inverse.transpose;

            // count active triangles normals:
            int activeDeformableTriangles = 0;

            for (int i = 0; i < master.deformableTriangles.Length; i += 3)
            {
                int t1 = master.deformableTriangles[i];
                int t2 = master.deformableTriangles[i + 1];
                int t3 = master.deformableTriangles[i + 2];

                if (t1 >= master.activeParticleCount || t2 >= master.activeParticleCount || t3 >= master.activeParticleCount)
                {
                    continue;
                }

                activeDeformableTriangles++;
            }


            // generate master triangle info:
            MasterFace[] masterFaces = new MasterFace[activeDeformableTriangles];
            int          count       = 0;

            for (int i = 0; i < master.deformableTriangles.Length; i += 3)
            {
                MasterFace face = new MasterFace();

                int t1 = master.deformableTriangles[i];
                int t2 = master.deformableTriangles[i + 1];
                int t3 = master.deformableTriangles[i + 2];

                if (t1 >= master.activeParticleCount || t2 >= master.activeParticleCount || t3 >= master.activeParticleCount)
                {
                    continue;
                }

                face.p1 = master.positions[t1];
                face.p2 = master.positions[t2];
                face.p3 = master.positions[t3];

                face.n1 = master.restNormals[t1];
                face.n2 = master.restNormals[t2];
                face.n3 = master.restNormals[t3];

                face.master = m_MasterChannels[t1] |
                              m_MasterChannels[t2] |
                              m_MasterChannels[t3];

                face.size = ((face.p1 - face.p2).magnitude +
                             (face.p1 - face.p3).magnitude +
                             (face.p2 - face.p3).magnitude) / 3.0f;

                face.faceNormal = Vector3.Cross(face.p2 - face.p1, face.p3 - face.p1).normalized;

                face.index = i;
                face.CacheBarycentricData();

                masterFaces[count++] = face;

                if (i % 10 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("Generating master faces...", count / (float)masterFaces.Length));
                }
            }

            // for each slave vertex, find the best fitting master triangle:
            for (int i = 0; i < slavePositions.Length; ++i)
            {
                // if vertex slave channel is deactivated, don´t skin it.
                if (m_SlaveChannels[i] == 0)
                {
                    continue;
                }

                // initialize best triangle error and index:
                float       bestError    = float.MaxValue;
                SlaveVertex bestSkinning = SlaveVertex.empty;

                Vector3 worldPos          = s2world.MultiplyPoint3x4(slavePositions[i]);
                Vector3 worldNormalDir    = s2worldNormal.MultiplyVector(slaveNormals[i]).normalized;
                Vector3 worldNormalPoint  = worldPos + worldNormalDir * 0.05f;
                Vector3 worldTangentPoint = worldPos + s2worldNormal.MultiplyVector(new Vector3(slaveTangents[i].x, slaveTangents[i].y, slaveTangents[i].z).normalized) * 0.05f;

                // find the best fitting master face:
                for (int j = 0; j < masterFaces.Length; ++j)
                {
                    MasterFace face = masterFaces[j];

                    // if the triangle master channel and the target slave channel do not overlap, skip it.
                    if ((face.master & m_SlaveChannels[i]) == 0)
                    {
                        continue;
                    }

                    // calculate skinning data for this face:
                    SlaveVertex skinning = BindToFace(i, face, worldPos, worldNormalPoint, worldTangentPoint);

                    // calculate mapping error for this triangle:
                    float error = GetFaceMappingError(face, skinning, worldNormalDir);

                    // if the error is less than the best, update it.
                    if (error < bestError)
                    {
                        bestError    = error;
                        bestSkinning = skinning;
                    }
                }

                // skin target vertex to the best source triangle found, if any:
                if (!bestSkinning.isEmpty)
                {
                    skinnedVertices.Add(bestSkinning);
                }

                if (i % 5 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("Skinning slave vertices (" + i + "/" + slavePositions.Length + ")...", i / (float)slavePositions.Length));
                }
            }

            bound = true;

#if UNITY_EDITOR
            EditorUtility.SetDirty(this);
#endif
        }