Skip to main content
GameDev.net gamedev.net
🔒 Locked

Terrain Collision Detection

Started by playworker Apr 26, 2003 at 4:01 PM 6 replies 2.1k views
Original Post
playworker
playworker
It''s me again guys! Now that my camera is working properly, I need to get some objects into my game, I''m just not sure how to get an object to "sit" on the terrain properly. As far as I can work out, the theory is to calculate the height of the object by interpolating between the vertices of the triangle that the object is currently sat on, and then if I align the object so that it''s up vector is the same as the normal of the triangle then it should look right... Is the above approach correct or not? If it is should I use the normal of the triangle or attempt to interpolate between the vertex normals to create a smoother angle change as the object moves across the landscape? Can anybody point be in the direction of some code examples - I''m really not too sure how to begin coding the interpolation. Thanks again guys. Matt
_nomad_
_nomad_
http://www.gametutorials.com has some tutorials that might help.

nomad | nomad forum
666_1337
666_1337
...

  
/* for vertex-arrays, the height field is stored as one dimensional array (float*)
*/

GLfloat terrain :: getHeightAt(GLfloat xPos, GLfloat zPos)
{
xPos += TERRAIN_GRID_WIDTH/2;
zPos += TERRAIN_GRID_HEIGHT/2;

if(xPos < 0)
xPos = 0;
else if(xPos >= TERRAIN_GRID_WIDTH)
xPos = TERRAIN_GRID_WIDTH-1;

if(zPos < 0)
zPos = 0;
else if(zPos >= TERRAIN_GRID_HEIGHT)
zPos = TERRAIN_GRID_HEIGHT-1;

GLfloat heights[4] =
{
heightField[(int)(xPos)*TERRAIN_GRID_WIDTH + (int)(zPos)],
heightField[(int)(xPos+1)*TERRAIN_GRID_WIDTH + (int)(zPos)],
heightField[(int)(xPos+1)*TERRAIN_GRID_WIDTH + (int)(zPos+1)],
heightField[(int)(xPos)*TERRAIN_GRID_WIDTH + (int)(zPos+1)]
};
GLfloat ht = (heights[1] - heights[0]) * fmod(xPos, 1.0f) + heights[0];
GLfloat htt = (heights[2] - heights[3]) * fmod(xPos, 1.0f) + heights[3];
GLfloat h = (htt - ht) * fmod(zPos, 1.0f) + ht;

return h;
}


this should work, if the data is structed propertly
our new version has many new and good features. sadly, the good nes are not new and the new nes are not good oo
playworker
playworker
Thank you very much, whoever you are, this looks like it might just do the trick!
playworker
playworker
Ah, it seems I may have been a bit hasty...

Does this solution give a rough estimate of where the height of the terrain is or have I implemented it wrongly?

It seems to give a result NEAR to the terrain, but not accurate enough for my original plans...
Trienco
Trienco
theres another problem to consider.. if your object is big it might span more than just one triangle.. things get more complicated and you would have to find all the points beneath the object, use the three highest and align it with that plane. for objects smaller than one triangle you can interpolate (btw. a lot of games dont care to align and the feet vanish in the terrain or they are slightly floating above it...which you''ll never notice until playing an ant ,-) )
f@dzhttp://festini.device-zero.de
666_1337
666_1337
well... i don''t know why this should be wrong... mathematically, it''s correct...

point you search is P(xLocation, getHeightAt(xLocation, zLocation), zLocation), if the origin of the map is supposed to be at it''s center.

about implementation: i think i post the whole classes...
don''t blame me about "this could be better" or "this is missing..."

terrain.h

  
#ifndef __terrain_header_
#define __terrain_header_
#define GL_GLEXT_LEGACY /* the function glXGetProcAddressEXT() doesn''t work properly...*/
#include <GL/gl.h>
#include "viewFrustum.h"
#include "configuration.h"

#define TERRAIN_GENERATE_FAULT 1
#define TERRAIN_GENERATE_CIRCLE 2

class terrainShaddowMapper; /* this doesn''t work */
class objectRoot; /* and this is some kind of a manager object */



class terrain
{
private:
GLfloat *heightField, vaTerrain, *surfaceColours, *normals, *surfaceTexture, TERRAIN_MAX_HEIGHT, TERRAIN_MIN_HEIGHT;
unsigned int TERRAIN_GRID_WIDTH, TERRAIN_GRID_HEIGHT;
GLboolean hasVertexArrays, hasMultiTexture, normalizationEnabled;
GLfloat normMaxHeight, normMinHeight;
configuration *config;
terrainShaddowMapper *terrain_shaddow_mapper;
objectRoot* rootnode;
void makeTerrainTexture(void);
public:
terrain(objectRoot*);
~terrain(void);

void reset(void);
void generate(GLuint width, GLuint height, GLuint MODE);
void loadHeightField(char *filename);
unsigned int getWidth(void);
unsigned int getHeight(void);

void normalize(GLfloat minHeight, GLfloat maxHeight);
void calculateSurfaceNormals(void);
void calculateSurfaceColours(GLuint light_index);

void enableNormalization(GLfloat, GLfloat);
void disableNormalization(void);
void init(void);
GLfloat getHeightAt(GLfloat xPos, GLfloat zPos);
GLfloat* getHeightFieldPointer(void) {return heightField;}

void draw(viewFrustum*);
};

#endif


terrain.cpp

  
#include "../include/terrain.h"
#include "../include/terrainUtils.h"
#include "../include/pngloader.h"
#include "../include/bmploader.h"
#include "../include/texture.h"
#include "../include/terrainShaddowingHeader.h"
#include "../include/mt19937.h"
#include "../include/root.h"

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <GL/glu.h>

#define assert_heightfield_existence assert(heightField || !"memory allocation fault")
#define assert_normal_array_existence assert(normals || !"memory allocation fault")
#define assert_colour_array_existence assert(surfaceColours || !"memory allocation fault")

struct terrain_octree_node
{
GLfloat xPos, yPos, zPos, radius;
GLint *indices, displayListsID;
} *occ_nodes;


terrain :: terrain (objectRoot* rootnode)
{
this -> rootnode = rootnode;
this -> config = rootnode -> getConfigurationPointer();

terrain_shaddow_mapper = new terrainShaddowMapper(this);
}

terrain :: ~terrain(void)
{
free(heightField);
free(surfaceColours);
free(normals);
free(config);
}

void terrain :: generate(GLuint width, GLuint height, GLuint mode)
{
if(!heightField)
{
heightField = (float*)malloc(sizeof(float) * width * height);
TERRAIN_GRID_WIDTH = width;
TERRAIN_GRID_HEIGHT = height;
}
for(int i = 0; i < TERRAIN_GRID_WIDTH*TERRAIN_GRID_HEIGHT; i++)
{
heightField[i] = 0.0f;
}

assert((mode < 3) || (!"terrain::generate has been called with an unknown parameter"));
assert_heightfield_existence;

for(int i = 0; i < TERRAIN_GRID_WIDTH*TERRAIN_GRID_HEIGHT; i++)
{
heightField[i] = 0.0f;
}

if(mode == TERRAIN_GENERATE_FAULT)
{
for(int i = TERRAIN_GRID_HEIGHT+TERRAIN_GRID_WIDTH; i > 0; i--)
runFaultAlgorithm(TERRAIN_GRID_WIDTH, TERRAIN_GRID_HEIGHT, heightField);
}
else if(mode == TERRAIN_GENERATE_CIRCLE)
{
for(int i = TERRAIN_GRID_HEIGHT+TERRAIN_GRID_WIDTH; i > 0; i--)
runCircleAlgorithm(TERRAIN_GRID_WIDTH, TERRAIN_GRID_HEIGHT, heightField);
}
}

unsigned int terrain :: getWidth(void) { return TERRAIN_GRID_WIDTH; }
unsigned int terrain :: getHeight(void) { return TERRAIN_GRID_HEIGHT; }

void terrain :: loadHeightField(char *filename)
{
/**/
char *s = filename + strlen(filename) - 4;

unsigned char *data;
GLuint width, height;
if(s[0] == ''.'' && s[1] == ''p'' && s[2] == ''n'' && s[3] == ''g'')
{
pngImage png;
assert(!loadPNGImage(filename, &png) || !"could not load heightmap from file");
width = png.width;
height = png.height;
data = png.data;
}
else { assert(!"you should never get here");}
printf("width = %i, height = %i\n", width, height);

if(!heightField)
heightField = (float*)malloc(sizeof(float) * width * height);
TERRAIN_GRID_WIDTH = width;
TERRAIN_GRID_HEIGHT = height;
for(int i = 0; i < width*height; i++)
{
heightField[i] = (float)data[i*3];
}
}

void terrain :: normalize(GLfloat min, GLfloat max)
{
assert_heightfield_existence;
TERRAIN_MAX_HEIGHT = max;
TERRAIN_MIN_HEIGHT = min;

int i, j;
GLfloat min1 = 10000.0f, max1 = -10000.0f;
for(i = TERRAIN_GRID_WIDTH-1; i >= 0; i--)
{
for(j = TERRAIN_GRID_HEIGHT-1; j >= 0; j--)
{
if(heightField[i*TERRAIN_GRID_HEIGHT + j] < min1)
min1 = heightField[i*TERRAIN_GRID_HEIGHT + j];

else if(heightField[i*TERRAIN_GRID_HEIGHT + j] > max1)
max1 = heightField[i*TERRAIN_GRID_HEIGHT + j];

}
}
GLfloat range = (max - min)/(max1 - min1);
for(i = TERRAIN_GRID_WIDTH-1; i >= 0; i--)
{
for(j = TERRAIN_GRID_HEIGHT-1; j >= 0; j--)
{
heightField[i*TERRAIN_GRID_HEIGHT + j] -= min1;
heightField[i*TERRAIN_GRID_HEIGHT + j] *= range;
heightField[i*TERRAIN_GRID_HEIGHT + j] += min;
}
}
}

void terrain :: calculateSurfaceNormals(void)
{
if(normals)
free(normals);
normals = (float*)malloc(sizeof(float) * TERRAIN_GRID_WIDTH * TERRAIN_GRID_HEIGHT * 3);
assert_normal_array_existence;
assert_heightfield_existence;

int i, j;
vector4f v, u, w;
for(i = 0; i < TERRAIN_GRID_WIDTH-1; i++)
{
for(j = 0; j < TERRAIN_GRID_HEIGHT-1; j++)
{
v = vector4f(1, ( heightField[(i+1)*TERRAIN_GRID_WIDTH + j]) - ( heightField[i*TERRAIN_GRID_WIDTH + j]), 0);
u = vector4f(0, ( heightField[i*TERRAIN_GRID_WIDTH + j + 1]) - ( heightField[i*TERRAIN_GRID_WIDTH + j]), 1);
w.outerProduce(v, u);
w.normalize();
normals[i*TERRAIN_GRID_WIDTH*3 + j*3 + 0] = w.x;
normals[i*TERRAIN_GRID_WIDTH*3 + j*3 + 1] = w.y;
normals[i*TERRAIN_GRID_WIDTH*3 + j*3 + 2] = w.z;
}
}

if(hasVertexArrays)
{
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
}
}

#define LIGHT_SOFTNESS 0.5f
#define MAX_BRIGHT 0.95f
#define MIN_BRIGHT 0.3f

void terrain :: calculateSurfaceColours(GLuint light)
{
if(surfaceColours)
free(surfaceColours);
surfaceColours = (float*)malloc(sizeof(float) * TERRAIN_GRID_WIDTH * TERRAIN_GRID_HEIGHT * 3);
assert_colour_array_existence;
assert_normal_array_existence;
assert_heightfield_existence;

float *lightpos = (float*)malloc(sizeof(float) * 4), *lightcolour = (float*)malloc(sizeof(float) * 4), *matcolour = (float*)malloc(sizeof(float) * 4);
float kc, kl, kq;
glGetLightfv(light, GL_POSITION, lightpos);
glGetLightfv(light, GL_DIFFUSE, lightcolour);
glGetLightfv(light, GL_CONSTANT_ATTENUATION, &kc);
glGetLightfv(light, GL_LINEAR_ATTENUATION, &kl);
glGetLightfv(light, GL_QUADRATIC_ATTENUATION, &kq);
glGetMaterialfv(GL_FRONT, GL_DIFFUSE, matcolour);

int i, j;
for(i = 0; i < TERRAIN_GRID_WIDTH; i++)
{
for(j = 0; j < TERRAIN_GRID_HEIGHT; j++)
{
vector4f n(normals[i*TERRAIN_GRID_WIDTH*3 + j*3], normals[i*TERRAIN_GRID_WIDTH*3 + j*3 + 1], normals[i*TERRAIN_GRID_WIDTH*3 + j*3 + 2]);
point4f p((float)i - (float)TERRAIN_GRID_WIDTH/2.0f, heightField[i*TERRAIN_GRID_WIDTH + j], (float)j - (float)TERRAIN_GRID_HEIGHT/2.0f);
point4f q(lightpos[0], lightpos[1], lightpos[2]);
vector4f l = q.vectorTo(p);
float length = l.length();
l.normalize();
n.normalize();
float f = l.innerProduce (l, n);
if(f < 0.0f)
f = 0.0f;
f /= kc + kl*length + kq*length*length;
surfaceColours[i*TERRAIN_GRID_WIDTH*3 + j*3 + 0] = f*lightcolour[0]*matcolour[0];
surfaceColours[i*TERRAIN_GRID_WIDTH*3 + j*3 + 1] = f*lightcolour[1]*matcolour[1];
surfaceColours[i*TERRAIN_GRID_WIDTH*3 + j*3 + 2] = f*lightcolour[2]*matcolour[2];
//printf("%1.3f, %1.3f, %1.3f\n", surfaceColours[i*TERRAIN_GRID_WIDTH*3 + j*3 + 0], surfaceColours[i*TERRAIN_GRID_WIDTH*3 + j*3 + 1], surfaceColours[i*TERRAIN_GRID_WIDTH*3 + j*3 + 2]);

}
}

if(config -> hasVertexArrays)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 0, surfaceColours);
}

free(lightpos);
free(lightcolour);
free(matcolour);
}

static float *temp;
GLuint textures[2]; GLuint groundTex, detailTex;

void terrain :: init(void)
{
GLboolean multiTexture, vertexArrays;
GLint texture_envs;
glGetBooleanv(GL_EXT_vertex_array, &vertexArrays);
glGetBooleanv(GL_ARB_multitexture, &multiTexture);
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &texture_envs);
this -> config -> hasVertexArrays = vertexArrays;
this -> config -> hasMultiTexture = multiTexture;
if(! vertexArrays)
fprintf(stdout, "warning: no hardware supported vertex arrays (EXT_vertex_array). switching to software.\n");
if(! multiTexture)
fprintf(stdout, "warning: no hardware supported multitexturing (ARB_multitexture). will need an aditional render pass.\n");

if((!multiTexture) || (texture_envs < 2))
this -> config -> hasMultiTexture = 0;

assert_heightfield_existence;
if(normalizationEnabled == GL_TRUE)
normalize(normMinHeight, normMaxHeight);

if(vertexArrays)
{
temp = (float*)malloc(sizeof(float)*TERRAIN_GRID_WIDTH*TERRAIN_GRID_HEIGHT*3);
for(int x = 0; x < TERRAIN_GRID_WIDTH; x++)
{
for(int z = 0; z < TERRAIN_GRID_HEIGHT; z++)
{
temp[x*TERRAIN_GRID_WIDTH*3 + z*3+0] = (float)x - (float)TERRAIN_GRID_WIDTH/2.0;
temp[x*TERRAIN_GRID_WIDTH*3 + z*3+1] = heightField[x*TERRAIN_GRID_WIDTH + z];
temp[x*TERRAIN_GRID_WIDTH*3 + z*3+2] = (float)z - (float)TERRAIN_GRID_HEIGHT/2.0;
}
}

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, temp);
calculateSurfaceNormals();
//calculateSurfaceColours(GL_LIGHT0);

}

occ_nodes = new terrain_octree_node[(TERRAIN_GRID_WIDTH-1)/8 * (TERRAIN_GRID_HEIGHT-1)/8];

int i, j, k, l;
unsigned int m = 0;
GLint width_2 = TERRAIN_GRID_WIDTH/2;
GLint height_2 = TERRAIN_GRID_HEIGHT/2;
GLfloat max_height;

makeTerrainTexture();

glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB(GL_TEXTURE0_ARB);
texture tex(TERRAIN_GRID_WIDTH-1, TERRAIN_GRID_HEIGHT-1, GL_RGB, surfaceTexture);
groundTex = rootnode -> getTextureManagerPointer() -> addTexture(&tex, GL_TEXTURE_2D, GL_TRUE);
rootnode -> getTextureManagerPointer() -> activateTexture(groundTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);


glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB(GL_TEXTURE1_ARB);
texture multiTexTexture ("textures/noise.png", PNG_TEXTURE);
detailTex = rootnode -> getTextureManagerPointer() -> addTexture(&multiTexTexture, GL_TEXTURE_2D, GL_TRUE);
rootnode -> getTextureManagerPointer() -> activateTexture(detailTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);

multiTexTexture.loadMipmapsUp();

for(i = 0; i < TERRAIN_GRID_WIDTH-1; i+=8)
{
for(j = 0; j < TERRAIN_GRID_HEIGHT-1; j+=8)
{
m = 0;
max_height = -1e5f;
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].indices = (int*)malloc(sizeof(int)*144);
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].displayListsID = glGenLists(1);
glNewList(occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].displayListsID, GL_COMPILE);

for(k = 0; k < 8; k++)
{
glBegin(GL_TRIANGLE_STRIP);
for(l = 0; l < 9; l++)
{
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].indices[m] = (i+k)*TERRAIN_GRID_HEIGHT + j+l;
m++;
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].indices[m] = (i+k+1)*TERRAIN_GRID_HEIGHT+j+l;
m++;
if(heightField[(i+k)*TERRAIN_GRID_HEIGHT + j+l] > max_height)
max_height = heightField[(i+k)*TERRAIN_GRID_HEIGHT + j+l];
else if(heightField[(i+k+1)*TERRAIN_GRID_HEIGHT+j+l] > max_height)
max_height = heightField[(i+k+1)*TERRAIN_GRID_HEIGHT+j+l];

if(vertexArrays)
{
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f - (float)(i+k)/(float)TERRAIN_GRID_WIDTH, 1.0f - (float)(j+l)/(float)TERRAIN_GRID_HEIGHT);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f + (float)(i+k), 0.0f + (float)(j+l));
glArrayElement((i+k)*TERRAIN_GRID_WIDTH + j+l);

glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f - (float)(i+k+1)/(float)TERRAIN_GRID_WIDTH, 1.0f - (float)(j+l)/(float)TERRAIN_GRID_HEIGHT);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f + (float)(i+k+1), 0.0f + (float)(j+l));
glArrayElement((i+k+1)*TERRAIN_GRID_WIDTH+j+l);
}
else
{
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0 - (float)(i+k)/(float)TERRAIN_GRID_WIDTH, 1.0 - (float)(j+l)/(float)TERRAIN_GRID_HEIGHT);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 16.0*(float)(i+k)/(float)TERRAIN_GRID_WIDTH, 16.0*(float)(j+l)/(float)TERRAIN_GRID_HEIGHT);
glColor3fv(&surfaceColours[(i+k)*TERRAIN_GRID_WIDTH*3 + (j+l)*3]);
glNormal3fv(&normals[(i+k)*TERRAIN_GRID_WIDTH*3 + (j+l)*3]);
glVertex3f((i+k)-width_2, heightField[(i+k)*TERRAIN_GRID_WIDTH + j+l], (j+l)-height_2);

glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0 - (float)(i+k+1)/(float)TERRAIN_GRID_WIDTH, 1.0 - (float)(j+l)/(float)TERRAIN_GRID_HEIGHT);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 16.0*(float)(i+k+1)/(float)TERRAIN_GRID_WIDTH, 16.0*(float)(j+l)/(float)TERRAIN_GRID_HEIGHT);
glColor3fv(&surfaceColours[(i+k+1)*TERRAIN_GRID_WIDTH*3 + (j+l)*3]);
glNormal3fv(&normals[(i+k+1)*TERRAIN_GRID_WIDTH*3 + (j+l)*3]);
glVertex3f((i+k)-(width_2-1), heightField[(i+k+1)*TERRAIN_GRID_WIDTH+j+l], (j+l)-height_2);
}
}
glEnd();
}

glEndList();
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].radius = 10;
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].xPos = i+4-width_2;
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].yPos = max_height;
occ_nodes[i*(TERRAIN_GRID_WIDTH-1)/64 + j/8].zPos = j+4-height_2;
}
}
#define testloc 0,15.0f,0
}

float rotation_light0 = 0.0f;

void terrain :: draw(viewFrustum* vf)
{
GLfloat width_2 = TERRAIN_GRID_WIDTH*0.5f;
GLfloat height_2 = TERRAIN_GRID_HEIGHT*0.5f;

glPointSize(50.0f);

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

float lightpos[4] = {sin(rotation_light0 += 0.005f), 35.0, cos(rotation_light0), 1.0f};

glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
glEnable(GL_NORMALIZE);

glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB(GL_TEXTURE0_ARB);
rootnode -> getTextureManagerPointer() -> activateTexture(groundTex);

glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB(GL_TEXTURE1_ARB);
rootnode -> getTextureManagerPointer() -> activateTexture(detailTex);

for(int i = 0; i < TERRAIN_GRID_WIDTH * TERRAIN_GRID_HEIGHT / 64; i++)
{
if(vf -> sphereIsInside(point4f(occ_nodes[i].xPos, occ_nodes[i].yPos, occ_nodes[i].zPos), occ_nodes[i].radius))
glCallList(occ_nodes[i].displayListsID);
}

glDisable(GL_TEXTURE_2D);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);

glColor3f(1.0f, 1.0f, 1.0f);
}

void terrain :: makeTerrainTexture()
{
if(surfaceTexture)
free(surfaceTexture);
surfaceTexture = (GLfloat*)malloc(sizeof(GLfloat)*(TERRAIN_GRID_WIDTH-1)*(TERRAIN_GRID_WIDTH-1)*3);
int i, j, k;

for(i = 0; i < TERRAIN_GRID_WIDTH-1; i++)
{
for(j = 0; j < TERRAIN_GRID_HEIGHT-1; j++)
{
surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3] = pow(((heightField[i*TERRAIN_GRID_WIDTH +j]-TERRAIN_MIN_HEIGHT)/(TERRAIN_MAX_HEIGHT-TERRAIN_MIN_HEIGHT)), 3)+0.25f;

if(surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3] > 1.0f)
surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3] = 1.0f - 0.1f*genrand();
else if(surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3] < 0.0f)
surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3] = 0.0f;

surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3+1] = 1.0f;
surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3+2] = surfaceTexture[i*(TERRAIN_GRID_WIDTH-1)*3 + j*3];

}
}
}

GLfloat terrain :: getHeightAt(GLfloat xPos, GLfloat zPos)
{
xPos += TERRAIN_GRID_WIDTH/2;
zPos += TERRAIN_GRID_HEIGHT/2;

if(xPos < 0)
xPos = 0;
else if(xPos >= TERRAIN_GRID_WIDTH)
xPos = TERRAIN_GRID_WIDTH-1;

if(zPos < 0)
zPos = 0;
else if(zPos >= TERRAIN_GRID_HEIGHT)
zPos = TERRAIN_GRID_HEIGHT-1;

GLfloat heights[4] =
{
heightField[(int)(xPos)*TERRAIN_GRID_WIDTH + (int)(zPos)],
heightField[(int)(xPos+1)*TERRAIN_GRID_WIDTH + (int)(zPos)],
heightField[(int)(xPos+1)*TERRAIN_GRID_WIDTH + (int)(zPos+1)],
heightField[(int)(xPos)*TERRAIN_GRID_WIDTH + (int)(zPos+1)]
};
GLfloat ht = (heights[1] - heights[0]) * fmod(xPos, 1.0f) + heights[0];
GLfloat htt = (heights[2] - heights[3]) * fmod(xPos, 1.0f) + heights[3];
GLfloat h = (htt - ht) * fmod(zPos, 1.0f) + ht;

return h;
}

void terrain :: enableNormalization(GLfloat minHeight, GLfloat maxHeight)
{
normMinHeight = minHeight;
normMaxHeight = maxHeight;
normalizationEnabled = GL_TRUE;
}

void terrain :: disableNormalization(void)
{
normalizationEnabled = GL_FALSE;
} else if(zPos >= TERRAIN_GRID_HEIGHT)
zPos = TERRAIN_GRID_HEIGHT-1;

GLfloat heights[4] =
{
heightField[(int)(xPos)*TERRAIN_GRID_WIDTH + (int)(zPos)],
heightField[(int)(xPos+1)*TERRAIN_GRID_WIDTH + (int)(zPos)],
heightField[(int)(xPos+1)*TERRAIN_GRID_WIDTH + (int)(zPos+1)],
heightField[(int)(xPos)*TERRAIN_GRID_WIDTH + (int)(zPos+1)]
};
GLfloat ht = (heights[1] - heights[0]) * fmod(xPos, 1.0f) + heights[0];
GLfloat htt = (heights[2] - heights[3]) * fmod(xPos, 1.0f) + heights[3];
GLfloat h = (htt - ht) * fmod(zPos, 1.0f) + ht;

return h;
}

void terrain :: enableNormalization(GLfloat minHeight, GLfloat maxHeight)
{
normMinHeight = minHeight;
normMaxHeight = maxHeight;
normalizationEnabled = GL_TRUE;
}

void terrain :: disableNormalization(void)
{
normalizationEnabled = GL_FALSE;
}


yeah... DON''T B(/F)LAME ME FOR THIS!!!

and it''s use:

  
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
{
glLoadIdentity();
/* this let''s the camera rotate on an radius of 15 untis about the center (0, 0, 0)
- and the height is set to be always 2 untis above it''s current location */

cam -> position.x = 15.0f * sin(glutGet(GLUT_ELAPSED_TIME) * 0.00025f);
cam -> position.z = 15.0f * cos(glutGet(GLUT_ELAPSED_TIME) * 0.00025f);
cam -> position.y = 2.0f + objroot.getTerrainPointer() -> getHeightAt(cam->position.x, cam->position.z);
/* objroot is a singleton object that stores the pointer to the heightfield */
cam -> yRot = -90.0f + glutGet(GLUT_ELAPSED_TIME) * 0.00025f * 57.2978f; /* 180 / pi = 57.2978*/


glRotatef(-cam -> xRot, 1, 0, 0);
glRotatef(-cam -> yRot, 0, 1, 0);
glRotatef(-cam -> zRot, 0, 0, 1);
glTranslatef( -cam->position.x, -cam->position.y, -cam->position.z);

glGetFloatv(GL_PROJECTION_MATRIX, proj);
glGetFloatv(GL_MODELVIEW_MATRIX, modl);
view_frustum -> redefine(proj, modl);

heightmap -> draw(view_frustum);
cam -> drawFps();
}

glutSwapBuffers();
}


now where you have the source, can anyone imagine why only those vertices with a z-coord equal or greater than the lights get lit? (that is the reason why there is a function to calculate a lightmap) ? <- i already posted this on other forums, but no-one has known why...
our new version has many new and good features. sadly, the good nes are not new and the new nes are not good oo
666_1337
666_1337
my function is maybe not working if you use roam, terrain-mipmaping or spline-up the triangles...
but it is at least much better than the algorithm of gametutorials'' terrain-class...
our new version has many new and good features. sadly, the good nes are not new and the new nes are not good oo

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.