Search code examples
3dtexture-mappingtrilateration

undistorted texture coordinates


How do you calculate UV coordinates for points on a plane?

I have a polygon - 3 or 4 or more points - that is on a plane - that is to say, all the points are on a plane. But it can be at any angle in space.

One side of this polygon - two points - are to be mapped to two corresponding 2D points in a texture - I know these two points in advance. I also know the x and y scale for the texture, and that no points fall outside the texture extent or other 'edge cases'.

Here's an image where the up-most textured quad is distorted:

enter image description here

I outlined a bad quad in yellow. Imagine that I know the UV coordinates of those two bottom-most corners on that quad, and want to calculate the proper UV coordinates of the other two points...

How do you calculate the UV coordinates of all the other points in the plane relative to these two points?

Imagine my texture is a piece of paper in real life, and I want to texture your (flat) car door. I place two dots on my paper, which I line up with two dots on your car door. How do I calculate where the other locations on the car door are under the paper?

Can you use trilateration? What would the pseudo-code look like for two known points in 2D space?


Success using brainjam's code:

def set_texture(self,texture,a_ofs,a,b):
    self.texture = texture
    self.colour = (1,1,1)
    self.texture_coords = tx = []
    A, B = self.m[a_ofs:a_ofs+2]
    for P in self.m:
        if P == A:
            tx.append(a)
        elif P == B:
            tx.append(b)
        else:
            scale = P.distance(A)/B.distance(A)
            theta = (P-A).dot((B-A)/(P.distance(A)*B.distance(A)))
            theta = math.acos(theta)
            x, y = b[0]-a[0], b[1]-a[1]
            x, y = x*math.cos(theta) - y*math.sin(theta), \
                x*math.sin(theta) + y*math.cos(theta)
            x, y = a[0]+ x*scale, a[1]+ y*scale
            tx.append((x,y))

enter image description here


Solution

  • Label the vertices of your 3D polygon in counter-clockwise order, starting with the two vertices whose UV coordinates are known. Call these labels A, B, C, D. The labels of the corresponding vertices in UV space are a, b, c, d, where a and b are known.

    The problem you've stated is, for a point P in the original polygon, to determine the corresponding UV coordinate p. (I believe that you only care about calculating the UV coordinates c and d for the points C and D, but the general solution for P is the same.)

    First, calculate the angle θ between P-A and B-A. This is easily done using the dot product of the normalized vectors, and acos.

    α = (P-A)⋅(B-A)/(|P-A||B-A|)

    θ = acos(α)

    We also calculate the ratio of the lengths:

    σ = |P-A|/|B-A|

    Now to calculate p in UV space, we simply rotate the vector b-a by angle θ (keeping a fixed) and scale by σ.

    Let R, the matrix for a rotation by angle θ, be

    | +cos(θ) -sin(θ) |
    | +sin(θ) +cos(θ) |

    Then p = a + σR( b-a).

    And you're done.