Constructing Bounding Shapes

In this example, I simply constructed the bounding shapes by hand based on Bob's image. But Bob's image is given in pixels, and our world might operate in, say, meters. The solutions to this problem involve normalization and model space. Imagine the two triangles we'd use for Bob in model space when we'd render him with OpenGL. The rectangle is centered at the origin in model space and has the same aspect ratio (width/height) as Bob's texture image (e.g., 32x32 pixels in the texture map as compared to 2x2 meters in model space). Now we can apply Bob's texture and figure out where in model space the points of the bounding shape are. Figure 8-10 shows how we can construct the bounding shapes around Bob in model space.

Figure 8-10. Bounding shapes around Bob in model space

Figure 8-10. Bounding shapes around Bob in model space

This process may seem a little cumbersome, but the steps involved are not all that hard. The first thing we have to remember is how texture mapping works. We specify the texture coordinates for each vertex of Bob's rectangle (which is composed of two triangles) in texture space. The upper-left corner of the texture image in texture space is at (0,0), and the lower-left corner is at (1,1), no matter the actual width and height of the image in pixels. To convert from the pixel space of our image to texture space, we can thus use this simple transformation:

u = x / imageWidth v = y / imageHeight where u and v are the texture coordinates of the pixel given by x and y in image space. The imageWidth and imageHeight are set to the image's dimensions in pixels (32x32 in Bob's case). Figure 8-11 shows how the center of Bob's image maps to texture space.

Figure 8-11. Mapping a pixel from image space to texture space

The texture is applied to a rectangle that we define in model space. In Figure 8-10 we have an example with the upper-left corner at (-1,1) and the lower-right corner at (1,-1). We use meters as the units in our world, so the rectangle has a width and height of 2 meters each. Additionally we know that the upper-left corner has the texture coordinates (0,0) and the lower-right corner has the texture coordinates (1,1), so we map the complete texture to Bob. This won't always be the case, as you'll see in one of the next sections.

So let's come up with a generic way to map from texture to model space. We can make our lives a little easier by constraining our mapping to only axis-aligned rectangles in texture and model space. This means we assume that an axis-aligned rectangular region in texture space is mapped to an axis-aligned rectangle in model space. For the transformation we need to know the width and height of the rectangle in model space and the width and height of the rectangle in texture space. In our Bob example we have a 2x2 rectangle in model space and a 1 x1 rectangle in texture space (since we map the complete texture to the rectangle). We also need to know the coordinates of the upper-left corner of each rectangle in its respective space. For the model space rectangle, that's (-1,1), and for the texture space rectangle it's (0,0) (again, since we map the complete texture, not just a portion). With this information and the u- and v-coordinates of the pixel we want to map to model space, we can do the transformation with these two equations:

my = (1 - ((v - minV) / (tHeight)) x mHeight - minY

The variables u and v are the coordinates we calculated in the last transformation from pixel to texture space. The variables minU and minV are the coordinates of the top-left corner of the region we map from texture space. The variables tWidth and tHeight are the width and height of our texture space region. The variables mWidth and mHeight are the width and height of our model space rectangle. The variables minX and minY are— you guessed it—the coordinates of the top-left corner of the rectangle in model space. Finally we have mx and my, which are the transformed coordinates in model space.

These equations take the u- and v-coordinates, map them to the range 0 to 1, and then scale and position them in model space. Figure 8-12 shows a texel in texture space and how it is mapped to a rectangle in model space. On the sides you see tWidth and tHeight, and mWidth and mHeight, respectively. The top-left corner of each rectangle corresponds to (minU, minV) in texture space and (minX, minY) in model space.

Figure 8-12. Mapping from texture space to model space

1 (1,1) Texture Space

Figure 8-12. Mapping from texture space to model space

Substituting the first two equations we can directly go from pixel space to model space:

mx = ((x/imageWidth) - minU) / (tWidth) * mWidth + minX my = (l - (((y/imageHeight) - minV) / (tHeight)) * mHeight minY

We can use these two equations to calculate the bounding shapes of our objects based on the image we map to their rectangles via texture mapping. In the case of the triangle mesh, this can get a little tedious; the bounding rectangle and bounding circle cases are a lot easier. Usually we don't go this hard route, but instead try to create our textures so that at least the bounding rectangles have the same aspect ratio as the rectangle we render for the object via OpenGL ES. This way we can construct the bounding rectangle from the object's image dimension directly. The same is true for the bounding circle. I just wanted to show you how you can construct an arbitrary bounding shape given an image that gets mapped to a rectangle in model space.

You should now know how to construct a nicely fitting bounding shape for your 2D objects. But remember, we define those bounding shape sizes manually, when we create our graphical assets and define the units and sizes of our objects in the game world. We then use these sizes in our code to collide objects with each other.

0 0

Post a comment