10
votes

I've been trying to render a GL_QUAD (which is shaped as a trapezoid) with a square texture. I'd like to try and use OpenGL only to pull this off. Right now the texture is getting heavily distorted and it's really annoying.

Normally, I would load the texture compute a homography but that means a lot of work and an additional linear programming library/direct linear transform function. I'm under the impression OpenGL can simplify this process for me.

I've looked around the web and have seen "Perspective-Correct Texturing, Q Coordinates, and GLSL" and "Skewed/Sheared Texture Mapping in OpenGL".

These all seem to assume you'll do some type of homography computation or use some parts of OpenGL I'm ignorant of ... any advice?

Update:

I've been reading "Navigating Static Environments Using Image-Space Simplification and Morphing" [PDF] - page 9 appendix A.

It looks like they disable perspective correction by multiplying the (s,t,r,q) texture coordinate with the vertex of a model's world space z component.

so for a given texture coordinate (s, r, t, q) for a quad that's shaped as a trapezoid, where the 4 components are:

(0.0f, 0.0f, 0.0f, 1.0f),
(0.0f, 1.0f, 0.0f, 1.0f),
(1.0f, 1.0f, 0.0f, 1.0f),
(1.0f, 0.0f, 0.0f, 1.0f) 

This is as easy as glTexCoord4f (svert.z, rvert.z, t, q*vert.z)? Or am I missing some step? like messing with the GL_TEXTURE glMatrixMode?

Update #2:

That did the trick! Keep it in mind folks, this problem is all over the web and there weren't any easy answers. Most involved directly recalculating the texture with a homography between the original shape and the transformed shape...aka lots of linear algebra and an external BLAS lib dependency.

3
Can you provide link with "wrong" texturing screenshot?przemo_li
I figured out a solution to the problem. Review the linked paper for more on planar texturing.ct_
Are you able to give a better summary of how you fixed the problem?ioquatix
@MrSamuel I'd recommend checking out the page 9 of the linked paper "Navigating Static Environments ..." the section title is "Disabling perspective correction".ct_
Update #1 and #2 saved my day - my week even! One minute of adding three multiplications and voilà! Amazing, I've been wrestling with this for several days already. I would upvote you to president if possible! (Heck, right now I'd even consider donating my house and cars to you.) I've gotta cherish this moment, I'll never be so overjoyed by a stackoverflow question again in my life.Jonas Byström

3 Answers

11
votes

Here is a good explanation of the issue & solution.

http://www.xyzw.us/~cass/qcoord/

working link: http://replay.web.archive.org/20080209130648/http://www.r3.nu/~cass/qcoord/

Partly copied and adapted from above link, created by Cass

One of the more interesting aspects of texture mapping is the space that texture coordinates live in. Most of us like to think of texture space as a simple 2D affine plane. In most cases this is perfectly acceptable, and very intuitive, but there are times when it becomes problematic.

For example, suppose you have a quad that is trapezoidal in its spatial coordinates but square in its texture coordinates.

OpenGL will divide the quad into triangles and compute the slopes of the texture coordinates (ds/dx, ds/dy, dt/dx, dt/dy) and use those to interpolate the texture coordinate over the interior of the polygon. For the lower left triangle, dx = 1 and ds = 1, but for the upper right triangle, dx < 1 while ds = 1. This makes ds/dx for the upper right triangle greater than ds/dx for the lower one. This produces an unpleasant image when texture mapped.

Texture space is not simply a 2D affine plane even though we generally leave the r=0 and q=1defaults alone. It's really a full-up projective space (P3)! This is good, because instead of specifying the texture coordinates for the upper vertices as (s,t) coordinates of (0, 1) and (1, 1), we can specify them as (s,t,r,q) coordinates of (0, width, 0, width) and (width, width, 0, width)! These coordinates correspond to the same location in the texture image, but LOOK at what happened to ds/dx - it's now the same for both triangles!! They both have the same dq/dx and dq/dy as well.

Note that it is still in the z=0 plane. It can become quite confusing when using this technique with a perspective camera projection because of the "false depth perception" that this produces. Still, it may be better than using only (s,t). That is for you to decide.

1
votes

I would guess that most people wanting to fit a rectangular texture on a trapezoid are thinking of one of two results:

  1. perspective projection: the trapezoid looks like a rectangle seen from an oblique angle.
  2. "stretchy" transformation: the trapezoid looks like a rectangular piece of rubber that has been stretched/shrunk into shape.

Most solutions here on SO fall into the first group, whereas I recently found myself in the second.

The easiest way I found to achieve effect 2. was to split the trapezoid into a rectangle and right triangles. In my case the trapezoid was regular, so a quad and two triangles solved the problem.

0
votes

Hope this can help: Quoted from the paper: " At each pixel, a division is performed using the interpolated values of (s=w; t=w; r=w; q=w), yielding (s=q; t=q), which are the final texture coordinates. To disable this effect, which is not possible in OpenGL directly. "

In GLSL, (now at least) this is possible. You can add:

noperspective out vec4 v_TexCoord;

there's an explanation: https://www.geeks3d.com/20130514/opengl-interpolation-qualifiers-glsl-tutorial/