Learning and Applying Mathematics using Computing

In our last post, we drew a 3D view of being in a maze-like grid of blocks. But all the walls were of single uniform colour, which is quite dull. The early 3D games that used our 3D technique, raycasting, almost immediately switched to using images for the walls rather than plain colours. These images were referred to as textures, and the technique for drawing them is known as texture mapping.

Texture mapping with raycasting is actually very simple. The idea is that each wall-block being drawn has an image on it. While drawing the wall-block pixel-by-pixel in 3D, texture mapping amounts to finding the corresponding pixel in the source image to use. We can label the face of each of the blocks in the world as having coordinates somewhere between (0, 0) and (1, 1):

The challenge is then for a given pixel, such as the red circle in the picture above, to find out which texture coordinates to use. These coordinates are typically labelled (u, v) to avoid confusion with other (x, y) coordinates. In raycasting, it’s quite easy to determine the (u, v). The u component is a matter of recording where exactly on the wall the ray hit. We already record the x and y coordinate of impact, and we know which face we hit. The u coordinate is just the fractional part of the appropriate x or y coordinate. If the ray hits the horizontal face of a block at (x, y) = 3.45, 6.00 then the u coordinate is 0.45.

As for the v coordinate: that is the relative height within the block we are currently drawing. In each column, we already know how tall the block appears. So the v coordinate is just a proportion of that total block height as we draw downwards.

Once we know the (u, v) coordinates, we just pick out the appropriate pixel from our texture image. If our texture is 256 by 256, and our (u, v) = (0.45, 0.29), then we use the pixel at (115, 74). (This is called nearest-neighbour texture mapping, and is fastest, but it can look a bit “jagged”. Most games now use some form of linear texture mapping that looks smoother)

Here’s the code:

            for (int wallY = 0; wallY <= 2 * height; wallY++)
            {
                double v = (double)wallY / (double)(2 * height);
                double u = r.getImageOffset();
                
                GreenfootImage texture = ((RaycastingWorld)getWorld()).getTextureFor(r.getX(), r.getY());
                
                Color c = texture.getColorAt((int)(u * (texture.getWidth() - 1)), (int)(v * (texture.getHeight() - 1)));
                
                int y = img.getHeight()/2 - height + wallY;
                if (y >= 0 && y < img.getHeight())
                {
                    img.setColorAt((int)column, y, c);
                }
            }

Here’s the texture:

And here’s a screenshot of what it looks like when used for texture-mapping:

You can play with the scenario yourself to see what it looks like as you turn round.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s