Example #1
0
 public SlaveVertex(int slaveIndex, int masterTriangleIndex, BarycentricPoint position, BarycentricPoint normal, BarycentricPoint tangent)
 {
     this.slaveIndex          = slaveIndex;
     this.masterTriangleIndex = masterTriangleIndex;
     this.position            = position;
     this.normal  = normal;
     this.tangent = tangent;
 }
Example #2
0
        /**
         * We need to find the barycentric coordinates of point such that the interpolated normal at that point passes trough our target position.
         *
         *            X
         *  \        /  /
         *   \------/--/
         *
         * This is necessary to ensure curvature changes in the surface affect skinned points away from the face plane.
         * To do so, we use an iterative method similar to Newton´s method for root finding:
         *
         * - Project the point on the triangle using an initial normal.
         * - Get interpolated normal at projection.
         * - Intersect line from point and interpolated normal with triangle, to find a new projection.
         * - Repeat.
         */
        BarycentricPoint FindSkinBarycentricCoords(MasterFace triangle,
                                                   Vector3 position,
                                                   int max_iterations,
                                                   float min_convergence)
        {
            BarycentricPoint barycentricPoint = BarycentricPoint.zero;

            // start at center of triangle:
            Vector3 trusted_bary = Vector3.one / 3.0f;
            Vector3 temp_normal  = ObiUtils.BarycentricInterpolation(triangle.n1,
                                                                     triangle.n2,
                                                                     triangle.n3,
                                                                     trusted_bary);

            int   it          = 0;
            float trust       = 1.0f;
            float convergence = float.MaxValue;

            while (it++ < max_iterations)
            {
                Vector3 point;
                if (!Obi.ObiUtils.LinePlaneIntersection(triangle.p1, triangle.faceNormal, position, temp_normal, out point))
                {
                    break;
                }

                // get bary coords at intersection:
                Vector3 bary = Vector3.zero;
                if (!triangle.BarycentricCoords(point, ref bary))
                {
                    break;
                }

                // calculate error:
                Vector3 error = bary - trusted_bary;     // distance from current estimation to last trusted estimation.
                convergence = Vector3.Dot(error, error); // get a single convergence value.

                // weighted sum of bary coords:
                trusted_bary = (1.0f - trust) * trusted_bary + trust * bary;

                // update normal
                temp_normal = ObiUtils.BarycentricInterpolation(triangle.n1,
                                                                triangle.n2,
                                                                triangle.n3,
                                                                trusted_bary);

                if (convergence < min_convergence)
                {
                    break;
                }

                trust *= 0.8f;
            }

            Vector3 pos_on_tri = trusted_bary[0] * triangle.p1 +
                                 trusted_bary[1] * triangle.p2 +
                                 trusted_bary[2] * triangle.p3;

            float height = Vector3.Dot(position - pos_on_tri, temp_normal);

            barycentricPoint.barycentricCoords = trusted_bary;
            barycentricPoint.height            = height;

            return(barycentricPoint);
        }