in

This site is all about the amazingly cool stuff you can do with VB.NET.

The VB.NET XNA Project

Heightmap Collision Sample posted

This one was a real pain, but it's the second sample I've done with a custom ContentProcessor. Grab the vb.net code here.

Heightmap Collision

This sample demonstrates how to move objects along a heightmap. It is based on the Generated Geometry sample, which creates a landscape from a bitmap. We build upon that sample, showing how to quickly calculate the height of any point on that heightmap.

Sample Overview

The Generated Geometry sample introduced the concept of a heightmap. In that sample, a content processor reads a bitmap and uses the intensity of its pixels as height values on a terrain. A logical next step to this technique is to place objects on the terrain. This sample demonstrates that technique by placing a ball on the generated terrain.

Minimum Shader Profile

Vertex Shader Model 1.1 Pixel Shader Model 1.1

Sample Controls

This sample uses the following keyboard and gamepad controls.

Action Keyboard Control Gamepad Control
Move the ball.

UP ARROW, DOWN ARROW, LEFT ARROW, and RIGHT ARROW

or W, A, S, and D

Left thumb stick or D-Pad
Exit the sample. ESC or ALT+F4 BACK

How the Sample Works

This sample is based on the Generated Geometry sample. To support the added functionality, the original sample has been modified in several ways. For clarity, the sky has also been removed.

Changes to the Terrain Processor

The TerrainProcessor has been modified slightly for this new sample. First, the algorithm that gives the vertices their XZ position has been modified slightly from the generated geometry sample. In the new version, the positions are calculated so that the heightmap is always centered around the origin. This change simplifies the math at run time.

In addition, the processor is responsible for creating a class called HeightMapInfoContent, which contains data about the height of the points of the heightmap, as well as the distance between them. This information is attached to the finished terrain model's .Tag property, and will be read when the game loads.

Finally, the SkyProcessor and SkyContent classes have been removed from the pipeline assembly.

Rolling Around on the Terrain

The user is now given direct control over a small sphere, which can roll over the terrain. The camera, which used to move in a fixed circular pattern around the terrain, is now tied to follow the sphere. To make it more obvious which code is new, we removed the Sky class from the sample.

To keep both the sphere and the camera on top of the terrain, we use the GetHeight function on HeightMapInfo. GetHeight is the most complicated part of this sample. This function accepts a position as an argument and returns the height of the heightmap at that position.

In this diagram, we are trying to calculate the height of the red circle. The grid represents our heightmap. In this example, our heightmap is 4×4. Note that this means that the heightmap's width and height are only 3 * TerrainScale. We'll call the white space between gridlines "cells."

To calculate the red circle's height at any point on a cell, we use bilinear interpolation. This is a lot simpler than it sounds. To understand how it works, let's first examine the simpler case, linear interpolation.

In this diagram, we know the (x,y) coordinates of two points on the red line: (2,1) and (8,4). We want to find out the y-coordinate at x = 4. (The diagram isn't to scale at all, so don't get out your rulers; you'll be disappointed.) To find the missing value, we can use linear interpolation. There are several different ways to do this. We'll use a method that, when ported to C# code, lets us make use of MathHelper.Lerp (linear interpolate) and will be fairly efficient.

The process is relatively straightforward. We know the x-coordinates of all three points, and we can see that the x-coordinate of the center point, which we are trying to find, is 1/3 of the way between the x-coordinate of the other two points. (In other words, the distance from x = 2 to x = 4 is 1/3 of the distance from x = 2 to x = 8.) Since the points are all on a straight line, the y-coordinate must also be 1/3 of the way.

The distance between the two y-coordinates, y = 1 and y = 4, is 3. So, if the y-coordinate at (4,?) is 1/3 of that distance away from the point on the left, our missing value is:

1 + (1/3) × 3 = 2

Simple enough. Bilinear interpolation will extend that principle further.

In this diagram, we are again on a heightmap, trying to calculate the height of our red circle. We know all of the heights at the corners of the cell, since we read those in from the bitmap, remember? We also know the x- and z-coordinates of the red circle. What we don't know is the height, y.

So first, we do a linear interpolation on the top edge of the cell. We go from the (left,top) corner to the (left+1,top) corner, and find the height at point A. Then, we do the same thing on the bottom edge of the cell, calculating the height at point B. Now we know the heights at A and B, both of which are on a straight line with the circle! To find the height of the circle, we do one more linear interpolation between A and B, and we've got our height.

Note that this technique is not perfect: on steep hills, it is still possible that parts of the sphere may clip through the terrain. To avoid this, we would have to perform a much more expensive collision check. Our technique, although imperfect, is inexpensive, and yields results that will suffice for many games.

Extending the Sample

  • The camera in this sample is fairly simple. Try taking the camera from the Chase Camera sample, and putting it into this one.
  • When moving objects over a heightmap, you may also want to align them to the slope of the terrain. To do this, you'll need to calculate the heightmap's normal vectors in the TerrainProcessor. A GetNormal function would work similarly to GetHeight, except all three components of the vector would have to be interpolated separately and then renormalized. Using this normal vector, you can calculate an orientation matrix for your object.

Comments

No Comments

About admin

Chris Williams is a Technology Evangelist for Magenic. He is the founder of several .NET User Groups on the east coast, and most recently the Twin Cities XNA User Group (www.twincitiesxnausergroup.com) in Minneapolis, MN. He is a VB.NET MVP, rabid blogger and owner of www.ILoveVB.NET. He's also a MCT, MCSD (.NET) Early Adopter, MCAD, freelance game developer, occasional author, tech editor, code camp & user group speaker, vintage arcade game collector and plays a pretty mean guitar in Rock Band.
Copyright 2008 - ILoveVB.NET
Powered by Community Server (Commercial Edition), by Telligent Systems