Code:
//
// Return the interpolated height of terrain <my_terrain> at world coordinates <px>, <py>.
// Will return the terrain's .z value if we're out of bounds.
//
entity* terrain_height_entity; // Entity pointer
var terrain_vector_ul[3]; // Coordinates for terrain vertices around px, py
var terrain_vector_ur[3];
var terrain_vector_ll[3];
var terrain_vector_lr[3];
var terrain_temp_1[3]; // Use special temp vectors so we don't overwrite
var terrain_temp_2[3]; // the standard "temp" variable
function terrain_height(my_terrain, px, py) {
var terrain_width; // Number of vertices on a side
var terrain_width_quants; // Length of entire terrain's side in quants
var terrain_square_width; // Length of side of a single "square" of terrain
var height; // The interpolated height
// Terrain model's extremities:
var terrain_min_x;
var terrain_max_y;
// The x and y coordinates of the nearest vertex to the "upper-left":
var vertex_x;
var vertex_y;
// Percentage to next vertex for interpolation:
var percent_x;
var percent_y;
// Vertex numbers for the four vertices around our current position:
var terrain_vertex_ul;
var terrain_vertex_ur;
var terrain_vertex_ll;
var terrain_vertex_lr;
// Pointer to the terrain object:
terrain_height_entity = my_terrain;
// Number of vertices on a side:
terrain_width = sqrt(ent_vertices(terrain_height_entity));
// Width of terrain in quants:
vec_for_vertex(terrain_temp_1, terrain_height_entity, 1);
vec_for_vertex(terrain_temp_2, terrain_height_entity, terrain_width); // Should be terrain_width+1 or not?
terrain_width_quants = max( abs(terrain_temp_1.x-terrain_temp_2.x), abs(terrain_temp_1.y-terrain_temp_2.y) );
// Figure out where the model starts based on the its min x and max y:
// (Can also simply do vec_to_vertex() for vertex #1.)
terrain_min_x = min(terrain_temp_1.x, terrain_temp_2.x);
terrain_max_y = max(terrain_temp_1.y, terrain_temp_2.y);
// Width of a single terrain square:
terrain_square_width = terrain_width_quants/(terrain_width-1);
// Get the vertex coordinates for the player's position:
vertex_x = (player.x-terrain_min_x)/terrain_square_width;
vertex_y = (terrain_max_y-player.y)/terrain_square_width;
percent_x = vertex_x-int(vertex_x);
percent_y = vertex_y-int(vertex_y);
vertex_x = int(vertex_x);
vertex_y = int(vertex_y);
// If we're out of bounds, return the terrain's base height:
if(vertex_x<0 || vertex_y<0 || vertex_x>=terrain_width-1 || vertex_y>=terrain_width-1) {
pr("Out of bounds for terrain height calc.");
return(terrain_height_entity.z);
}
// Figure out our four closest vertices:
terrain_vertex_ul = 1+vertex_x+vertex_y*(terrain_width);
terrain_vertex_ur = 1+(vertex_x+1)+vertex_y*(terrain_width);
terrain_vertex_ll = 1+vertex_x+(vertex_y+1)*(terrain_width);
terrain_vertex_lr = 1+(vertex_x+1)+(vertex_y+1)*(terrain_width);
// Get the coordinates of those vertices:
vec_for_vertex(terrain_vector_ul.x, terrain_height_entity, terrain_vertex_ul);
vec_for_vertex(terrain_vector_ur.x, terrain_height_entity, terrain_vertex_ur);
vec_for_vertex(terrain_vector_ll.x, terrain_height_entity, terrain_vertex_ll);
vec_for_vertex(terrain_vector_lr.x, terrain_height_entity, terrain_vertex_lr);
// Interpolate based on where we are between those corners:
height = (terrain_vector_ul.z*(1-percent_x)+terrain_vector_ur.z*(percent_x))*(1-percent_y) + (terrain_vector_ll.z*(1-percent_x)+terrain_vector_lr.z*(percent_x))*(percent_y);
// Return the z coordinate of the terrain at this height:
return(height);
}
The above function will give the
approximate z value of a terrain at point px, py. (So, for example, you could call terrain_height(my_terrain, player.x, player.y) to get the height at the player's current x and y coordinates.)
Damocles had posted in the Future forum requesting such a function, and I've been needing one, so I thought I'd whip something up. A few caveats:
1. It's not optimized even a little bit.
2. It's approximate, as it interpolates smoothly between terrain vertices (whereas the engine actually displays each piece of terrain as a pair of triangles).
3. I've only tested this with the few terrains I'm using for the Galaxy Rage prototype, so your mileage may vary.
Point #2 is less noticable if your terrain is smooth, and the vertices are close together.