Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Texture mapping a trapezoid

Credits go to Bob and Tobias Dammers for helping out!
This thread is locked; no one can reply to it. rss feed Print
Texture mapping a trapezoid
HoHo
Member #4,534
April 2004
avatar

I've been struggling with it for a few hours today. I have very little OpenGL experience and I wouldn't be surprised to know there is something really basic I'm missing.

Problem is simple:
I have to map a rectangular texture onto a trapezoid without producing ugly artifacts.

For the reference, here are the original quad, trapezoid I get and trapezoid-like thing I would like to get:
http://www.allegro.cc/files/attachment/592463
Notice how the straight lines are no longer straight but "broken":
http://www.allegro.cc/files/attachment/592464
Just imagine that only the quad is in perspective and not the window, I'm no expert in Gimp :P
http://www.allegro.cc/files/attachment/592465

Is something like this at all possible with two triangles? If not then how can I achieve such look.

In the end the program will look 2D top-down. Performance isn't probably a problem but ease of implementation would be a major plus :)

Code to draw the trapezoid is this. To get a quad just replace 0.2 with 1.0:

1 const float coords[4][3]= {
2 {-1.0f, -0.2f, 0.0f},
3 {-1.0f, 0.2f, 0.0f},
4 {1.0f, 1.f, 0.0f},
5 {1.0f, -1.0f, 0.0f},
6 };
7 const float texcoords[4][2]={
8 {0.0f,0.0f},
9 {0.0f,1.0f},
10 {1.0f,1.0f},
11 {1.0f,0.0f},
12 };
13 glBindTexture(GL_TEXTURE_2D, textures[0]);
14 glBegin(GL_QUADS);
15 for (int i=0;i<4;i++){
16 glTexCoord2fv(texcoords<i>);
17 glVertex3fv(coords<i>);
18 }
19 glEnd();

Initialization code:

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glViewport((width - side) / 2, (height - side) / 2, side, side);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.5, +1.5, +1.5, -1.5, 4.0, 15.0);
    glMatrixMode(GL_MODELVIEW);

The code is a part of a QT OpenGL example (opengl/textures). I can post the entire project if you like, just let me know.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Tobias Dammers
Member #2,604
August 2002
avatar

You need to specify z coordinates. With perspective-corrected texture mapping, the two triangles should look OK.
Alternatively, divide the quad into smaller chunks that map better.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

HoHo
Member #4,534
April 2004
avatar

You mean I should simply use a quad with one edge having Z coordinates that are way back to make it look like a trapezoid? Are there any other ways? I would like is the polygon to be on one plane on the screen, it would make things a bit easier for me.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Bob
Free Market Evangelist
September 2000
avatar

Break up your quad manually into 4 triangles by picking the center (or center of mass) of the trapezoid.

The GPU will subdivide quads into 2 triangles, but you may not like the axis of separation.

Using perspective will not help you here. The problem is really that the 2 triangles generated for your quad don't have the same area, and thus will distort the texture differently.

--
- Bob
[ -- All my signature links are 404 -- ]

HoHo
Member #4,534
April 2004
avatar

Now that I think of it, dividing to four triangles should work well. Though I didn't go that way since calculating texture coordinates might be a bit tricky (read: I'm too lazy to work out the math).

In the end I did what Tobias said and made a cilinder I view top-down. It works really well for me. End result is here:
{"name":"592467","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/9\/59a99f19cc7390029b2b0b1367c94534.png","w":595,"h":524,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/9\/59a99f19cc7390029b2b0b1367c94534"}592467
With little tilting it is easy to see it really is 3D
{"name":"592468","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/7\/07a69dc30dc7c8033b4ae0e2b4a873cd.png","w":537,"h":487,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/7\/07a69dc30dc7c8033b4ae0e2b4a873cd"}592468

Thanks for all your help!

Changed code is like this:

1 
2 glViewport(0,0,glcanvas->getWidth(),glcanvas->getHeight());
3 
4 glClearColor(1.0,1.0,1.0,1.0);
5 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
6 glEnable(GL_DEPTH_TEST);
7 
8 glDisable(GL_DITHER);
9 
10 glMatrixMode(GL_PROJECTION);
11 glLoadIdentity();
12 gluPerspective(30.,aspect,1.,100.);
13 
14 glMatrixMode(GL_MODELVIEW);
15 glLoadIdentity();
16 gluLookAt(0.,0.,-15.,0.,0.,0.,0.,1.,0.);

1 for ( float i=0.f, phi=2*pi; phi>0.0f;phi-=STEP, i+=1.0f){
2 inside.x=sin(phi-STEP);
3 inside.y=cos(phi-STEP);
4 outside.x=sin(phi);
5 outside.y=cos(phi);
6 
7 lastInner.x=inside.x;
8 lastInner.y=inside.y;
9 lastOuter.x=outside.x;
10 lastOuter.y=outside.y;
11 
12 tx=(1.f/NUM_STEPS)*(i+1);
13 txl=(1.f/NUM_STEPS)*(i);
14 
15 texture.draw(lastOuter, lastInner, inside, outside, txl, 0.0f, tx, 1.0f, true, true);
16 }

It is rather inefficient and looks ugly but it will get some serious refactoring later.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

Using perspective will not help you here. The problem is really that the 2 triangles generated for your quad don't have the same area, and thus will distort the texture differently.

Provided the unprojected shape (in 3-space) is a rectangle, it does help, as you see. The triangles do have equal area in 3-space, so the texcoords align nicely. After proper perspective correction, this is still the case.
Attached GIF illustrates it nicely. The red dot shows the position to which texcoords (0.5, 0.5) are mapped.
Figure A is a plain rectangle, for which linear and perspective-corrected mapping are equivalent.
Figure B shows what happens when the rectangle is distorted by moving the left vertices in the Y direction, but not in the Z direction. The resulting mapping is linear, the red dot still remains centered in the X-direction, but moves up due to the fact that the edge that divides the two triangles remains linear. This leads to the other diagonal being bent, and the mapping shows artifacts.
Figure C shows what happens when correct perspective mapping is applied: the vertices aren't moved in the Y-direction, but rather along the Z axis, and then projected. The mapping now isn't linear anymore, but takes perspective foreshortening into account, leading to correct behaviour: both diagonals remain intact, because texcoords(0.5, 0.5) are now mapped to the point where both diagonals meet. This, of course, only works when the projected Y coordinates are equivalent to the result of a suitable perspective projection (Y' = Y/Z).

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Bob
Free Market Evangelist
September 2000
avatar

Quote:

Provided the unprojected shape (in 3-space) is a rectangle, it does help, as you see.

But it's not. The question was: How to texture a trapezoid. It was not "how to texture a tilted rectangle". The math for the two is different and the resulting images will also be different.

--
- Bob
[ -- All my signature links are 404 -- ]

Tobias Dammers
Member #2,604
August 2002
avatar

From the screenshots, I was assuming that a tilted square were the right solution, since that is what we see in mockshot 3.
Of course they are different, but depending on what is needed, perspective-projected may look satisfying, especially if the object in question really represents a tilted rect (even though in a 2d top-down view). Also, the incorrectness of perspective-corrected is way easier on the eye than that of the original (non-)solution. If it looks OK, I'd just use it, otherwise dividing into smaller triangles would be the best solution.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Go to: