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

I have a triangle, each point of which is defined by a position (X,Y,Z) and a UV coordinate (U,V):

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

With this function, I am able to get the UV coordinate at a specific XYZ position:

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;
}

I attempted to reverse-engineer this to make a function that gets the XYZ coordinate from a specific UV position:

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;
}

This works MOST of the time. However, it seems to exponentially "approach" the right-angled corner of the triangle-- or something. I'm not really sure what's going on except that the result gets wildly inaccurate the closer it gets to the right-angle.

What do I need to do to this TriangleUVtoXYZ function to make it return accurate results?



Solution 1:[1]

I haven't tested your implementation, but you only need to compute two parametric coordinates - the third being redundant since they should sum to 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());
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1