Original Post
I bought the "MOGLGP" book and am trying to implement the frustum culling that is covered. I am having some issues with the terrain rendering correclty... If I take out the if() to check for what patches are in view the whole terrain renders just fine, as one whole patch. Now I am guessing it has to do with the frutsum calculation code? Here is what I am using and maybe its correct and I am doing something else wrong? I am calling this in my rendering function everytime I render my terrain patch Any help or ideas would be great.
#ifndef CFRUSTUM_H
#define CFRUSTUM_H
class CFrustum
{
public:
float frustum[6][4];
CFrustum(void)
{
}
~CFrustum(void)
{
}
void multMatrix(float a[16], float b[16], float r[16])
{
r[0] = (a[0] *b[0]) + (a[1] *b[4]) + (a[2] *b[8] ) + (a[3] *b[12]);
r[1] = (a[0] *b[1]) + (a[1] *b[5]) + (a[2] *b[9] ) + (a[3] *b[13]);
r[2] = (a[0] *b[2]) + (a[1] *b[6]) + (a[2] *b[10]) + (a[3] *b[14]);
r[3] = (a[0] *b[3]) + (a[1] *b[7]) + (a[2] *b[11]) + (a[3] *b[15]);
r[4] = (a[4] *b[0]) + (a[5] *b[4]) + (a[6] *b[8] ) + (a[7] *b[12]);
r[5] = (a[4] *b[1]) + (a[5] *b[5]) + (a[6] *b[9] ) + (a[7] *b[13]);
r[6] = (a[4] *b[2]) + (a[5] *b[6]) + (a[6] *b[10]) + (a[7] *b[14]);
r[7] = (a[4] *b[3]) + (a[5] *b[7]) + (a[6] *b[11]) + (a[7] *b[15]);
r[8] = (a[8] *b[0]) + (a[9] *b[4]) + (a[10]*b[8] ) + (a[11]*b[12]);
r[9] = (a[8] *b[1]) + (a[9] *b[5]) + (a[10]*b[9] ) + (a[11]*b[13]);
r[10]= (a[8] *b[2]) + (a[9] *b[6]) + (a[10]*b[10]) + (a[11]*b[14]);
r[11]= (a[8] *b[3]) + (a[9] *b[7]) + (a[10]*b[11]) + (a[11]*b[15]);
r[12]= (a[12]*b[0]) + (a[13]*b[4]) + (a[14]*b[8] ) + (a[15]*b[12]);
r[13]= (a[12]*b[1]) + (a[13]*b[5]) + (a[14]*b[9] ) + (a[15]*b[13]);
r[14]= (a[12]*b[2]) + (a[13]*b[6]) + (a[14]*b[10]) + (a[15]*b[14]);
r[15]= (a[12]*b[3]) + (a[13]*b[7]) + (a[14]*b[11]) + (a[15]*b[15]);
}
void normPlane(float plane[4], float result[4])
{
// Find the magnitude of the vector.
double mag = sqrt((plane[0] * plane[0]) + (plane[1] * plane[1]) + (plane[2] * plane[2]));
// Divide the values by the length.
result[0] = float(plane[0] / mag);
result[1] = float(plane[1] / mag);
result[2] = float(plane[2] / mag);
result[3] = float(plane[3] / mag);
}
void calculateFrustum(void)
{
// Get the projection matrix.
float projection[16];
glGetFloatv(GL_PROJECTION_MATRIX, projection);
// Get the modelview matrix.
float modelview[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
// Before we can extract the sides of the frustum, we need to
// multiply the projection and modelview matrices together.
float result[16];
multMatrix(modelview, projection, result);
// Extract each side of the frustum and normalize that side.
// Right side:
frustum[0][0] = result[3] - result[0];
frustum[0][1] = result[7] - result[4];
frustum[0][2] = result[11] - result[8];
frustum[0][3] = result[15] - result[12];
normPlane(frustum[0], frustum[0]);
// Left side:
frustum[1][0] = result[3] + result[0];
frustum[1][1] = result[7] + result[4];
frustum[1][2] = result[11] + result[8];
frustum[1][3] = result[15] + result[12];
normPlane(frustum[1], frustum[1]);
// Bottom:
frustum[2][0] = result[3] + result[1];
frustum[2][1] = result[7] + result[5];
frustum[2][2] = result[11] + result[9];
frustum[2][3] = result[15] + result[13];
normPlane(frustum[2], frustum[2]);
// Top:
frustum[3][0] = result[3] - result[1];
frustum[3][1] = result[7] - result[5];
frustum[3][2] = result[11] - result[9];
frustum[3][3] = result[15] - result[13];
normPlane(frustum[3], frustum[3]);
// Back:
frustum[4][0] = result[3] - result[2];
frustum[4][1] = result[7] - result[6];
frustum[4][2] = result[11] - result[10];
frustum[4][3] = result[15] - result[14];
normPlane(frustum[4], frustum[4]);
// Front:
frustum[5][0] = result[3] + result[2];
frustum[5][1] = result[7] + result[6];
frustum[5][2] = result[11] + result[10];
frustum[5][3] = result[15] + result[14];
normPlane(frustum[5], frustum[5]);
}
bool pointInFrustum(float x, float y, float z)
{
// Loop through the sides of the frustum.
for(int i = 0; i < 6; i++)
{
// Calculate the distance to the side.
float dist = frustum[0] * x +
frustum[1] * y +
frustum[2] * z +
frustum[3];
// If the distance was negative, the point is outside the frustum.
if(dist <= 0)
return false;
}
// the point was inside the frustum.
return true;
}
};
#endif
glPushMatrix();
frustum.calculateFrustum();
glPopMatrix();
float maxX = 0.0f, maxY = 0.0f, maxZ = 0.0f;
float minX = 0.0f, minY = 0.0f, minZ = 0.0f;
SetupTexturesTerrain();
// Loop through the chunks.
for(unsigned int z = 0; z < mapData.map_Z / (PATCH_SIZE - 1); z++)
{
for(unsigned int x = 0; x < mapData.map_X / (PATCH_SIZE - 1); x++)
{
maxX = patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].maxX;
maxY = patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].maxY;
maxZ = patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].maxZ;
minX = patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].minX;
minY = patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].minY;
minZ = patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].minZ;
// Check to see if the corners of the chunk are within the frustum.
if (!frustum.pointInFrustum(maxX, maxY, maxZ) &&
!frustum.pointInFrustum(minX, maxY, minZ) &&
!frustum.pointInFrustum(minX, maxY, maxZ) &&
!frustum.pointInFrustum(maxX, maxY, minZ) &&
!frustum.pointInFrustum(maxX, minY, maxZ) &&
!frustum.pointInFrustum(minX, minY, minZ) &&
!frustum.pointInFrustum(minX, minY, maxZ) &&
!frustum.pointInFrustum(maxX, minY, minZ))
continue;
// bind the buffer and draw the chunk.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, patch[z * (mapData.map_Z / (PATCH_SIZE - 1)) + x].index_buffer);
glDrawElements(GL_TRIANGLE_STRIP, numberIndices, GL_UNSIGNED_INT, NULL);
}
}