给定三角形上的 UV,如何找到 XYZ?

How to, given UV on a triangle, find XYZ?

我有一个三角形,它的每个点都由一个位置 (X,Y,Z) 和一个 UV 坐标 (U,V) 定义:

struct Vertex
{
    Vector mPos;
    Point mUV;
    inline Vector& ToVector() {return mPos;}
    inline Vector& ToUV() {return mUV;}
};

通过这个函数,我可以获取特定 XYZ 位置的 UV 坐标:

Point Math3D::TriangleXYZToUV(Vector thePos, Vertex* theTriangle)
{
    Vector aTr1=theTriangle->ToVector()-(theTriangle+1)->ToVector();
    Vector aTr2=theTriangle->ToVector()-(theTriangle+2)->ToVector();
    Vector aF1 = theTriangle->ToVector()-thePos;
    Vector aF2 = (theTriangle+1)->ToVector()-thePos;
    Vector aF3 = (theTriangle+2)->ToVector()-thePos;
    float aA=aTr1.Cross(aTr2).Length();
    float aA1=aF2.Cross(aF3).Length()/aA;
    float aA2=aF3.Cross(aF1).Length()/aA;
    float aA3=aF1.Cross(aF2).Length()/aA;
    Point aUV=(theTriangle->ToUV()*aA1)+((theTriangle+1)->ToUV()*aA2)+((theTriangle+2)->ToUV()*aA3);
    return aUV;
}

我试图对其进行逆向工程以创建一个从特定 UV 位置获取 XYZ 坐标的函数:

Vector Math3D::TriangleUVToXYZ(Point theUV, Vertex* theTriangle)
{
    Point aTr1=theTriangle->ToUV()-(theTriangle+1)->ToUV();
    Point aTr2=theTriangle->ToUV()-(theTriangle+2)->ToUV();
    Point aF1 = theTriangle->ToUV()-theUV;
    Point aF2 = (theTriangle+1)->ToUV()-theUV;
    Point aF3 = (theTriangle+2)->ToUV()-theUV;
    float aA=gMath.Abs(aTr1.Cross(aTr2)); // NOTE: Point::Cross looks like this: const float Cross(const Point &thePoint) const {return mX*thePoint.mY-mY*thePoint.mX;}
    float aA1=aF2.Cross(aF3)/aA;
    float aA2=aF3.Cross(aF1)/aA;
    float aA3=aF1.Cross(aF2)/aA;
    Vector aXYZ=(theTriangle->ToVector()*aA1)+((theTriangle+1)->ToVector()*aA2)+((theTriangle+2)->ToVector()*aA3);
    return aXYZ;
}

这在大多数情况下都有效。然而,它似乎以指数方式“接近”三角形的直角角——或类似的东西。我不太确定发生了什么,只是结果越接近直角就变得非常不准确。

我需要对这个 TriangleUVtoXYZ 函数做些什么才能使其 return 获得准确的结果?

我没有测试你的实现,但你只需要计算两个参数坐标——第三个是多余的,因为它们的总和应该为1。

Vector Math3D::TriangleUVToXYZ(Point theUV, Vertex* theTriangle)
{
    // T2-T1, T3-T1, P-T1
    Point aTr12 = theTriangle[1].ToUV() - theTriangle[0].ToUV();
    Point aTr13 = theTriangle[2].ToUV() - theTriangle[0].ToUV();
    Point aP1 = theUV - theTriangle[0].ToUV();
    
    // don't need Abs() for the denominator
    float aA23 = aTr12.Cross(aTr13);
    
    // parametric coordinates [s,t]
    // s = (P-T1)x(T2-T1) / (T3-T1)x(T2-T1)
    // t = (P-T1)x(T3-T1) / (T2-T1)x(T3-T1)
    float aA12 = aP1.Cross(aTr12) / -aA23;
    float aA13 = aP1.Cross(aTr13) /  aA23;
    
    // XYZ = V1 + s(V2-V1) + t(V3-V1)
    return theTriangle[0].ToVector()
       + aA12 * (theTriangle[1].ToVector() - theTriangle[0].ToVector())
       + aA13 * (theTriangle[2].ToVector() - theTriangle[0].ToVector());
}