// matrix to transform point on a primitive from bake space into space of the shape static float4x4 GetPrimitiveBakeToShapeMatrix( float4x4 localToWorld, float4x4 shapeToWorld, ref float3 center, ref EulerAngles orientation, float3 scale, int3 basisPriority ) { if ( basisPriority.x == basisPriority.y || basisPriority.x == basisPriority.z || basisPriority.y == basisPriority.z ) { throw new ArgumentException(nameof(basisPriority)); } var localToBasis = float4x4.TRS(center, orientation, scale); // correct for imprecision in cases of no scale to prevent e.g., convex radius from being altered if (scale.Equals(new float3(1f))) { localToBasis.c0 = math.normalizesafe(localToBasis.c0); localToBasis.c1 = math.normalizesafe(localToBasis.c1); localToBasis.c2 = math.normalizesafe(localToBasis.c2); } var localToBake = math.mul(localToWorld, localToBasis); if (localToBake.HasNonUniformScale() || localToBake.HasShear()) { // deskew second longest axis with respect to longest axis localToBake[basisPriority[1]] = DeskewSecondaryAxis(localToBake[basisPriority[0]], localToBake[basisPriority[1]]); // recompute third axes from first two var n2 = math.normalizesafe( new float4(math.cross(localToBake[basisPriority[0]].xyz, localToBake[basisPriority[1]].xyz), 0f) ); localToBake[basisPriority[2]] = n2 * math.dot(localToBake[basisPriority[2]], n2); } var bakeToShape = math.mul(math.inverse(shapeToWorld), localToBake); // transform baked center/orientation (i.e. primitive basis) into shape space orientation.SetValue( quaternion.LookRotationSafe(bakeToShape[basisPriority[0]].xyz, bakeToShape[basisPriority[1]].xyz) ); center = bakeToShape.c3.xyz; return(bakeToShape); }