Game Development Community

UV mapping a quad

by James Ford · in Technical Issues · 07/10/2008 (10:44 am) · 7 replies

I have an arbitrary quad... That is, it is a trapezoid not a quadrilateral. Eg. Some are getting narrower from bottom to top, some are getting wider, and some could be staying the same width. I want the corners of the quad to correspond to these texture UVs...

0,1 ----------  1,1
|               |
|               |
|               |
0,0 ----------  1,0

If it helps to visualize the problem or isolate it to a particular field, what I am actually doing here is texture mapping a square decal to a stretched/nonsquare shape.

Note that the change in width is NOT because of a perspective projection, its because it is just changing in width. Any perspective projection will be applied automatically after all of this.

So far I am getting decent results using bilinear interpolation. But sometimes the texture along the center of the quad appears to be "wavy". eg... if there was a line down the center of the quad, it might appear like this...

0,1 ---------  1,1
|       \       |
|       /       |
|       \       |
0,0 ---------  1,0

So the questions...

1. Could this waviness be a by-product of bilinear interpolation or does that sound like an error elsewhere?
2. I have not heard of bilinear interpolation being used for this purpose before, so, is there something else more appropriate?

#1
07/10/2008 (12:14 pm)
What app is this happening in ?
can you post some images ?

typically, if you've got an arbitrary (but planar!) quadrilateral
with the regular unit texture coords at the corners (00 10 11 01),
it should render nice and smoothly stretched.
#2
07/10/2008 (1:11 pm)
Ok actually I left out some of the complexity. There are really a lot more verts than those corner four because this is a decal that is applied to the terrain, we are capturing and clipping the terrain polys. So to build my vertex buffer I have to calculate textCoords for each of those verts. That is the reason for using bilinear interpolation.

X------------X
|  o         |
|        o   |
|    o       | 
X------------X

So here I have the verts represented by o(s) scattered throughout the quad, and I need to calculate their UVs relative to the known corner UVs.

Note: This quad is not necessarily planar, but this flat projection of the texture is the best we can do. The "wavy" problem can occur on completely flat terrain.
#3
07/10/2008 (1:45 pm)
Ah i gotcha.
hm,
since opposite edges of the quad are not parallel,
i'm not sure that bilinear interpolation will work.

hm.

just taking a stab here, but i would maybe try something like this:

let's call the top edge of the quad T, the right R, the bottom B, and the left L.
P is the point in question.
* project P onto T, R, B, and L.
* let Ut be the U-value at the projected point on T.
* let Ub be the U-value at the projected point on B.
* let Vl be the V-value at the projected point on L.
* let Vr be the V-value at the projected point on R.
* let PT be the distance from P to T.
* let PR be the distance from P to R.
* let PB be the distance from P to B.
* let PL be the distance from P to L.

then

* Up = [Ut * (PT / (PT + PB)] + [Ub * (PB / (PT + PB)].
* Vp = [Vr * (PR / (PR + PL)] + [Vl * (PR / (PR + PL)].

(this of course can be optimized, but i think this is the clearest expression)
#4
07/10/2008 (3:20 pm)
That makes sense... As you reach a distance of 1 from one of the opposing edges, the P(s) U/V value becomes the U/V of that edge.

But how do you do the projection in the first place? I guess to do a projection on the top/bottom edges I need a projection vector - the direction to do the projection. If the left/right edges were parallel then it would make since to use that direction for the projection, but we do not necessarily have any parallel edges.

If the left/right edge direction vectors differ, then we would want to project onto the top/bottom edges using the left edge vector when P is at distance zero from that edge, and use the right edge vector when P is at distance zero from that edge. And interpolate between the two in the area between.

But how do we know the distance from the left/right edges? Well we have to do a projection onto them, which requires we have already done the projection on the top/bottom ....
#5
07/10/2008 (3:52 pm)
> But how do you do the projection in the first place?
i should have been more clear. these are all perpendicular projections.
if a line has two points A and B, to project point P perpendicularly onto it:

AB  = vector from A to B
ABn = AB normalized
AP  = vector from A to P

Q   = the perpendicular projection of P onto AB = A + (ABn * (ABn DOT AP))

fwiw, Q is also the point on AB which is closest to P.
#6
07/10/2008 (4:07 pm)
While we're at it, if ABn DOT AP is < 0 or > 1, then the perpendicular projection of the point does not lie between A & B, which will happen sometimes in the above algorithm, but which should be fine.