// 線形補間
private Vector2 Lerp(Vector2 start, Vector2 end, float t)
{
return start + t * (end - start);
}
// 三次元空間内の四角形のUV座標を計算
public Vector2 CalculateUV(Vector3 A, Vector3 B, Vector3 C, Vector3 D,
Vector3 E, Vector3 F, Vector3 G, Vector3 H, Vector3 I)
{
// 上面ABCDの平面における点Iの投影を計算
Vector3 normalABCD = Vector3.Cross(B - A, C - A).normalized;
Vector3 projectionIOnABCD = I - Vector3.Dot(I - A, normalABCD) * normalABCD;
// 下面EFGHの平面における点Iの投影を計算
Vector3 normalEFGH = Vector3.Cross(F - E, G - E).normalized;
Vector3 projectionIOnEFGH = I - Vector3.Dot(I - E, normalEFGH) * normalEFGH;
// 上面と下面の投影点からUV座標を計算
Vector2 uvABCD = CalculateUVOnPlane(A, B, C, D, projectionIOnABCD);
Vector2 uvEFGH = CalculateUVOnPlane(E, F, G, H, projectionIOnEFGH);
// 点Iが上面と下面の間でどの位置にあるかに基づいてUV座標を補間
float distanceToABCD = Vector3.Distance(I, projectionIOnABCD);
float distanceToEFGH = Vector3.Distance(I, projectionIOnEFGH);
float totalDistance = distanceToABCD + distanceToEFGH;
float weightABCD = distanceToEFGH / totalDistance;
float weightEFGH = distanceToABCD / totalDistance;
// 重み付けされたUV座標を算出
return Lerp(uvEFGH, uvABCD, weightABCD);
}
// 平面上の四角形内の点のUV座標を計算
private Vector2 CalculateUVOnPlane(Vector3 A, Vector3 B, Vector3 C, Vector3 D, Vector3 P)
{
// 辺ABとCDに沿った補間
Vector3 AB = B - A;
Vector3 CD = D - C;
float tAB = Vector3.Dot(P - A, AB) / AB.sqrMagnitude;
float tCD = Vector3.Dot(P - C, CD) / CD.sqrMagnitude;
Vector3 AB_P = A + tAB * AB;
Vector3 CD_P = C + tCD * CD;
// 辺ADとBCに沿った補間
Vector3 AD = D - A;
Vector3 BC = C - B;
float tAD = Vector3.Dot(P - A, AD) / AD.sqrMagnitude;
float tBC = Vector3.Dot(P - B, BC) / BC.sqrMagnitude;
Vector3 AD_P = A + tAD * AD;
Vector3 BC_P = B + tBC * BC;
// 辺に沿った補間からUV座標を計算
float u = (P - AB_P).magnitude / (CD_P - AB_P).magnitude;
float v = (P - AD_P).magnitude / (BC_P - AD_P).magnitude;
// 最終的なUV座標を算出
return new Vector2(u, v);
}