Mapping irregular shapes or other polygons (cartoons, sprites) to triangles in OpenGL ES

拥有回忆 提交于 2019-12-23 13:03:28

问题


I don't understand the concept of showing sprites mapped into OpenGL Triangles.

If OpenGL ES only draws triangles and points, How do you display/map non-triangular shapes?

Why would a shape mapped to a triangle not be distorted?

To explain:

In my mind, mapping, say, a sprite of Mario, to a triangle would produce a distorted or cropped Mario. In such a case, the head would be squished or invisible.


回答1:


If I've understood the concern correctly: you simply divide the square into two triangles, and use texture coordinates to divide the texture up correspondingly. If you do it right, you get the texture drawn on screen, 1:1, as if it were a sprite. (Of course you also have the option of rotation and stretching and whatnot.)

0     1  <-- If your square is divided up like this, say, set texcoord
+-----+      for point 0 to be the top left of the sprite; for point 3, the
|\    |      bottom right of the sprite; and correspondingly, for points
| \   |      1 and 2.
|  \  |
|   \ |
|    \|
+-----+
2     3

As it turns out, you won't get a squished sprite in quite the way you're expecting. I imagine you're picturing drawing the triangle 0-3-2 from my picture above, say, mapped in the obvious fashion, and getting the top scanline infinitely squeezed into one point (point 0)? But in fact this won't happen, because there's only one texture coordinate for point 0, so (if points 2 and 3 are mapped appropriately) you'll only ever get the cut-out part of the sprite.

(That said, you could assign the same texcoord to two points, though, or make the texture cross over itself, and get it wrong that way -- there's still plenty of scope for making a mess, don't worry.)

This is explained in the OpenGL programming guide, though it's years and years since I learnt this stuff so I'm not sure how helpful it will be if you're having difficulty: http://glprogramming.com/red/chapter09.html




回答2:


Quite simply, the texture won't be distorted because you'll only be picking three texture coordinates - one per vertex. You'll have to use two triangles as outlined above, and "clip" different portions of the texture.

Pardon my horrible use of ASCII art here, and in the rest of this post:

  Polygon     Texture        ADB        ACD
  A-----C  |  x-----x  |  x        |  x-----x
  |\    |  |  | ___ |  |  |        |    ___ |
  | \   |  |  |<o.o>|  |  |<o      |     .o>|
  |  \  |  |  | ### |  |  | ##     |      # |
  |   \ |  |  | -|- |  |  | -|-    |        |
  |    \|  |  | / \ |  |  | / \    |        |
  B-----D  |  x-----x  |  x-----x  |        x

You'd make two triangles - ADB and ACD. Point A maps to the top-left of the texture, B to the bottom-left, C to the top-right, and D to the bottom-right. If you only map one triangle or the other, you only get half of the sprite (or texture, for a more complex shape.) The same applies for larger or more complex polygons. The texture can be a single unified piece, but the texture coordinates of each vertex has to slice it up in the same manner as the geometry itself.

More complex example, a hexagon:

   a   b
    ___
   /   \
f /  .  \ c
  \  g  /
   \___/
  e     d

If you add a middle point of "G" and slice it up into six triangles (ABG, BCG, CDG, etc) you'll have to make sure that whatever texture you're using is sliced up coordinate-wise to match. This doesn't matter if you're just using GL_TRIANGLES, since it's easiest to just leave the texture in its hexagonal shape, but once you start drawing strips or fans you can flip, skew, or duplicate if you don't keep close track of what vertex is mapping to what part of the texture, due to the drawing order.

As an aside, if you're just concerned with 2D screen-aligned quads - which is what sprites are generally for - use the OES_Draw_Texture extension available on the iPhone and save yourself a load of heartache while picking up a significant speed boost.

int rect[4] = {0, 0, 64, 64}; 
glBindTexture(GL_TEXTURE_2D, texMario); 
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, rect); 
glDrawTexiOES(playerX, playerY, spriteZ, width, height); 

The rect defines the coordinates of the texture you're going to snip out (in pixels, so this would be a 64x64 sprite) and then the actual call to glDrawTexiOES plops it right into the screen view with its lower-left corner on playerX and playerY.

Goodness, even I get the feeling of "tl;dr" here. I apologize for that.




回答3:


The reason is in the rendering pipeline at the lowest level it is all triangles. More complicated shapes like polygons and the like are transformed into a collection of triangles through a process called tessellation.

So if you want to model your complicated Mario character the trick is actually to make him into a collection of triangles, not a single one.

I see in another answer you mentioned transparent pixels. I have not used the newest versions of openGL but the traditional definition a collision is based on intersecting the surface and the texture, even a transparent one, was not taken into account.

EDIT:

A quick google turned up a solution using a GL_TRIANGLE_STRIP off of iDevGames.com The Url is http://www.idevgames.com/forum/showpost.php?p=143983&postcount=6

Here is the relevant draw method:

- (void)drawView {

    // Replace the implementation of this method to do your own custom drawing

    const GLfloat squareVertices[] = {
        -0.5f, -0.5f,
        0.5f,  -0.5f,
        -0.5f,  0.5f,
        0.5f,   0.5f,
    };

    GLshort genericTexCoords[] = { 0, 1, 1, 1, 0, 0, 1, 0 };

    [EAGLContext setCurrentContext:context];

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glRotatef(3.0f, 0.0f, 0.0f, 1.0f);

    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glTexCoordPointer(2, GL_SHORT, 0, genericTexCoords);

    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, sprite);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}



回答4:


You could use transparent pixels.

In OpenGL ES, how do I load a texture that has transparent pixels?




回答5:


openGL can actually draw polygons, but it's usually safer not to use them, specially in complex shapes. Polygons can "twist" on themselves and make an invalid shape that can't be correctly rendered. With triangles, this never happens. That's why people usually break up complex shapes to triangles.

See http://www.glprogramming.com/red/chapter02.html#name2 for a better, more complete explanation.



来源:https://stackoverflow.com/questions/2842339/mapping-irregular-shapes-or-other-polygons-cartoons-sprites-to-triangles-in-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!