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; }
/** * 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); }