How can I modify the UV co-ordinates on a texture so they converge to a point?

I'm building a roof visualiser app, where someone can take a picture of their roof, define its outline, then visualise a new roof texture on it.

I'm generating a 3D plane that matches the roof outline points, but I'd like the 3D planes material's UV's to match the perspective of the existing roof (i.e the lines converge into the distance as they move away from the user.

Is this possible?

The alternative solution is to figure out how to rotate the generated 3D plane to match the roof outline points, while matching the perspective too, but I'm thinking this may be more complicated.

Step 1 - Define roof oultine with points

Step 2 - Texture 3D plane with UV's mapped to maintain roof perspective based on slant defined in the 4 points

Any tips on how to solve this?

• Rotating to match the roof angle is the easiest way to do this, since then you get the perspective-correct texture interpolation for free out of the hardware. The math of doing it in a shader is trickier, since you're most often working in triangles but the amount of perspective to apply depends on all four points of the quad, requiring that we somehow encode that information some other way. Jun 25, 2015 at 12:18
• DMGRegory I thought about rotating the quad, but then the problem comes with the quad's 4 points no longer lining up with the 4 points the user defined over the roofing area. Unless you know a trick to handle this? Jun 25, 2015 at 21:49
• Also the UX people don't want anyone rotating quads, they just want the user to draw a simple outline. Jun 25, 2015 at 22:04
• What the user does and how the program interprets it are two completely different things. In this case, the user can draw a converging trapezoid and the program can interpret it as a rotated quad - if that's your goal. Note though that there's an ambiguity, in how much convergence is due to perspective and how much is due to the roof actually narrowing. If you need exact results, you'll need a means to disambiguate these two factors. Jun 25, 2015 at 22:09

If you map the UV coordinates of a square texture to that quad it will automatically give you the effect you're looking for.

In other words, map the texture the same as you would for the face of a cube;

Upper-left:  0, 0
Upper-right: 1, 0
Lower-left:  0, 1
Lower-right: 1, 1


Unfortunately, doing it this way will cause perspective issues because you're working with a trapezoid. See the Accepted answer here (Perspective correct texturing of trapezoid in OpenGL ES 2.0) for what else you'll need to do - which is provide a depth coordinate to your process;

You need to provide more than a 2D texture coordinate to make this work - you need to provide a 3D (or rather, projective) texture coordinate, and perform the perspective divide in the fragment shader, post-interpolation (or else use a texture lookup function which will do the same).

Having said that, my gut feeling is that you would probably be better off just using a 3D square plane and rotating it backwards a bit, which will also solve your problem and not require any extra gymnastics.

• But the plane I have generated is currently vertical. If I do that, I will just get pure vertical roof lines showing from top to bottom, with no perspective. Jun 25, 2015 at 2:24
• Have you tried it? Because I just did, and it does what you ask... almost. I'll modify my answer and link to my findings. Jun 25, 2015 at 18:05
• I may be doing something wrong with the vertices and UV's of the plane I am generating, so I will double check that. Regarding your gut feeling, rotating a plane was my first thought, but the problem is rotating the plane while keeping it overlayed to the the 4 points on the roof defined by the user. Jun 25, 2015 at 21:52
• Apologies, you were correct in your assumption, I was doing something wrong in my vertex/uv co-ordinate generation that was causing issues. But these are fixed now. Thanks :) Jun 25, 2015 at 23:39
• If I had a nickel for every time that happened to me... good luck on your project! Jun 25, 2015 at 23:41