# OpenGL OpenGL Frustum Culling Problem

## Recommended Posts

Hello everybody. I have a rather complex scene I want to cull via the frustum. However, for some strange reason my implementation is not working (nothing is drawn). I have looked at *many* of other people implementations, and it seems as if they are identical to mine. Here are my various data structures:
struct Plane
{
f32 a, b, c, d;
};

struct Matrix4x4
{
f32 m[16];
};

struct vector3df
{
f32 x, y, z;
};

Here are various mathematical functions:
FASTCALL struct Matrix4x4 multiplyMatrix4x4(struct Matrix4x4 a, struct Matrix4x4 b)
{
struct Matrix4x4 c;

c.m[0]  = a.m[0] * b.m[0] + a.m[1] * b.m[4] + a.m[2] * b.m[8] + a.m[3] * b.m[12];
c.m[1]  = a.m[0] * b.m[1] + a.m[1] * b.m[5] + a.m[2] * b.m[9] + a.m[3] * b.m[13];
c.m[2]  = a.m[0] * b.m[2] + a.m[1] * b.m[6] + a.m[2] * b.m[10] + a.m[3] * b.m[14];
c.m[3]  = a.m[0] * b.m[3] + a.m[1] * b.m[7] + a.m[2] * b.m[11] + a.m[3] * b.m[15];

c.m[4]  = a.m[4] * b.m[0] + a.m[5] * b.m[4] + a.m[6] * b.m[8] + a.m[7] * b.m[12];
c.m[5]  = a.m[4] * b.m[1] + a.m[5] * b.m[5] + a.m[6] * b.m[9] + a.m[7] * b.m[13];
c.m[6]  = a.m[4] * b.m[2] + a.m[5] * b.m[6] + a.m[6] * b.m[10] + a.m[7] * b.m[14];
c.m[7]  = a.m[4] * b.m[3] + a.m[5] * b.m[7] + a.m[6] * b.m[11] + a.m[7] * b.m[15];

c.m[8]  = a.m[8] * b.m[0] + a.m[9] * b.m[4] + a.m[10] * b.m[8] + a.m[11] * b.m[12];
c.m[9]  = a.m[8] * b.m[1] + a.m[9] * b.m[5] + a.m[10] * b.m[9] + a.m[11] * b.m[13];
c.m[10] = a.m[8] * b.m[2] + a.m[9] * b.m[6] + a.m[10] * b.m[10] + a.m[11] * b.m[14];
c.m[11] = a.m[8] * b.m[3] + a.m[9] * b.m[7] + a.m[10] * b.m[11] + a.m[11] * b.m[15];

c.m[12] = a.m[12] * b.m[0] + a.m[13] * b.m[4] + a.m[14] * b.m[8] + a.m[15] * b.m[12];
c.m[13] = a.m[12] * b.m[1] + a.m[13] * b.m[5] + a.m[14] * b.m[9] + a.m[15] * b.m[13];
c.m[14] = a.m[12] * b.m[2] + a.m[13] * b.m[6] + a.m[14] * b.m[10] + a.m[15] * b.m[14];
c.m[15] = a.m[12] * b.m[3] + a.m[13] * b.m[7] + a.m[14] * b.m[11] + a.m[15] * b.m[15];

return c;
}

FASTCALL void normalizePlane(struct Plane * plane)
{
f32 mag = sqrtf(plane->a * plane->a + plane->b * plane->b + plane->c * plane->c);

if(mag)
{
plane->a /= mag;
plane->b /= mag;
plane->c /= mag;
plane->d /= mag;
}
}

Here is the global frustum planes declaration:
struct Plane frustumPlane[6];

Here is the frustum extraction function:
FASTCALL void updateFrustum()
{
struct Matrix4x4 proj, modl, clip;
struct Plane * p;

glPushMatrix();

glGetFloatv(GL_PROJECTION_MATRIX, &proj.m[0]);
glGetFloatv(GL_MODELVIEW_MATRIX, &modl.m[0]);

glPopMatrix();

clip = multiplyMatrix4x4(proj, modl);

printf("{%f, %f, %f, %f\n %f, %f, %f, %f\n %f, %f, %f, %f\n %f, %f, %f, %f}\n\n",
clip.m[0], clip.m[1], clip.m[2], clip.m[3],
clip.m[4], clip.m[5], clip.m[6], clip.m[7],
clip.m[8], clip.m[9], clip.m[10], clip.m[11],
clip.m[12], clip.m[13], clip.m[14], clip.m[15]);

p = &frustumPlane[RIGHT];
p->a = clip.m[3]  - clip.m[0];
p->b = clip.m[7]  - clip.m[4];
p->c = clip.m[11] - clip.m[8];
p->d = clip.m[15] - clip.m[12];

p = &frustumPlane[LEFT];
p->a = clip.m[3]  + clip.m[0];
p->b = clip.m[7]  + clip.m[4];
p->c = clip.m[11] + clip.m[8];
p->d = clip.m[15] + clip.m[12];

p = &frustumPlane[BOTTOM];
p->a = clip.m[3]  + clip.m[1];
p->b = clip.m[7]  + clip.m[5];
p->c = clip.m[11] + clip.m[9];
p->d = clip.m[15] + clip.m[13];

p = &frustumPlane[TOP];
p->a = clip.m[3]  - clip.m[1];
p->b = clip.m[7]  - clip.m[5];
p->c = clip.m[11] - clip.m[9];
p->d = clip.m[15] - clip.m[13];

p = &frustumPlane[BACK];
p->a = clip.m[3]  - clip.m[2];
p->b = clip.m[7]  - clip.m[6];
p->c = clip.m[11] - clip.m[10];
p->d = clip.m[15] - clip.m[14];

p = &frustumPlane[FRONT];
p->a = clip.m[3]  + clip.m[2];
p->b = clip.m[7]  + clip.m[6];
p->c = clip.m[11] + clip.m[10];
p->d = clip.m[15] + clip.m[14];

u8 i;
for (i = 0; i < 6; i++)
normalizePlane(&frustumPlane[i]);
}

Here is the function to test if a vertex is in the frustum:
FASTCALL bool isVector3dfInFrustum(struct vector3df d)
{
if(frustumPlane[RIGHT].a * d.x + frustumPlane[RIGHT].b * d.y + frustumPlane[RIGHT].c * d.z + frustumPlane[RIGHT].d > 0)
return false;

if(frustumPlane[LEFT].a * d.x + frustumPlane[LEFT].b * d.y + frustumPlane[LEFT].c * d.z + frustumPlane[LEFT].d > 0)
return false;

if(frustumPlane[BACK].a * d.x + frustumPlane[BACK].b * d.y + frustumPlane[BACK].c * d.z + frustumPlane[BACK].d > 0)
return false;

if(frustumPlane[FRONT].a * d.x + frustumPlane[FRONT].b * d.y + frustumPlane[FRONT].c * d.z + frustumPlane[FRONT].d > 0)
return false;

if(frustumPlane[TOP].a * d.x + frustumPlane[TOP].b * d.y + frustumPlane[TOP].c * d.z + frustumPlane[TOP].d > 0)
return false;

if(frustumPlane[BOTTOM].a * d.x + frustumPlane[BOTTOM].b * d.y + frustumPlane[BOTTOM].c * d.z + frustumPlane[BOTTOM].d > 0)
return false;

return true;
}

And a simple test case scenario:
    glBegin(GL_POINTS);
glPointSize(5.0f);

s32 x, y, z;
u32 count = 0;
for(x = -100; x < 100; x++)
for(y = -100; y < 100; y++)
for(z = -100; z < 100; z++)
if(isVector3dfInFrustum(makeVector3df(x, y, z)))
{
glVertex3i(x, y, z);
count++;
}

glEnd();

printf("%lu\n", count);

This test case scenario renders 0 of the points, regardless of the camera orientation. Any ideas on what I might be doing wrong? [Edited by - n0obAtroN on June 10, 2009 2:39:47 AM]

##### Share on other sites
Edited last post, added test case scenario.

Anyone?

##### Share on other sites
Couple of things:

1. In updateFrustum(), you're not setting the matrix mode before pushing the matrix stack, so it's not clear which stack is being manipulated. Also, since you're loading the identity matrix before querying for the projection and modelview matrices, I would think that one of the two would always come back as identity (which would definitely be wrong in the case of the projection matrix, and is likely to be wrong in the case of the modelview matrix).

2. I'd recommend creating a separate function for testing a point against a plane rather than writing the test out manually each time; this will help avoid typos and copy-and-paste errors.

Frustum culling code (especially based on this particular algorithm), as well as math library code in general, is difficult to debug just by looking at it; a single typo (such as a wrong index in a matrix multiplication function) can throw the whole thing off.

Testing the functions and components individually can help. With frustum culling, I recommend confirming visually that the frustum planes are correct before moving on to culling. It can be a bit of a pain to set up, but a fairly straightforward way to generate debug graphics for the frustum is to intersect the planes in sets of three to yield the corners of the frustum, and then render the 6 quadrilaterals making up the frustum. (You'll most likely need to attach the frustum to an object other than the camera in order to see the debug graphics clearly.)

##### Share on other sites
Hi all!
I have a similar problem:
I want to calculate the points of the View frustum (after the transformations of course).

I just don't know why it isn't working.

Calculating code:
float MVM[16];
void Calc_Frustum()
{
float pt[16] = {0,0,0,1, 0,0,0,1, 0,0,0,1, 1,1,1,1};
float out[16];
float inv_MVM[16];

glGetFloatv(GL_MODELVIEW_MATRIX, MVM);
MatrixTranspose(MVM,inv_MVM);

for( int i = 0; i < 5; i++ )
{
pt[0] = Frustum_Points[i][0];
pt[1] = Frustum_Points[i][1];
pt[2] = Frustum_Points[i][2];

MatrixMult(inv_MVM,pt,out);

Frustum_Tarnsformed_Points[i][0] = out[0];
Frustum_Tarnsformed_Points[i][1] = out[1];
Frustum_Tarnsformed_Points[i][2] = out[2];
}
}

void MatrixMult(float *in,float *in2, float *out)
{
out[ 0] = in[0]*in2[0]+in[4]*in2[1]+in[8]*in2[2]+in[12]*in2[3];
out[ 1] = in[1]*in2[0]+in[5]*in2[1]+in[9]*in2[2]+in[13]*in2[3];
out[ 2] = in[2]*in2[0]+in[6]*in2[1]+in[10]*in2[2]+in[14]*in2[3];
out[ 3] = in[3]*in2[0]+in[7]*in2[1]+in[11]*in2[2]+in[15]*in2[3];
out[ 4] = in[0]*in2[4]+in[4]*in2[5]+in[8]*in2[6]+in[12]*in2[7];
out[ 5] = in[1]*in2[4]+in[5]*in2[5]+in[9]*in2[6]+in[13]*in2[7];
out[ 6] = in[2]*in2[4]+in[6]*in2[5]+in[10]*in2[6]+in[14]*in2[7];
out[ 7] = in[3]*in2[4]+in[7]*in2[5]+in[11]*in2[6]+in[15]*in2[7];
out[ 8] = in[0]*in2[8]+in[4]*in2[9]+in[8]*in2[10]+in[12]*in2[11];
out[ 9] = in[1]*in2[8]+in[5]*in2[9]+in[9]*in2[10]+in[13]*in2[11];
out[10] = in[2]*in2[8]+in[6]*in2[9]+in[10]*in2[10]+in[14]*in2[11];
out[11] = in[3]*in2[8]+in[7]*in2[9]+in[11]*in2[10]+in[15]*in2[11];
out[12] = in[0]*in2[12]+in[4]*in2[13]+in[8]*in2[14]+in[12]*in2[15];
out[13] = in[1]*in2[12]+in[5]*in2[13]+in[9]*in2[14]+in[13]*in2[15];
out[14] = in[2]*in2[12]+in[6]*in2[13]+in[10]*in2[14]+in[14]*in2[15];
out[15] = in[3]*in2[12]+in[7]*in2[13]+in[11]*in2[14]+in[15]*in2[15];
} This works well in any other places.

void MatrixTranspose(float *in, float *out)
{
out[ 0] = in[0];
out[ 1] = in[4];
out[ 2] = in[8];
out[ 3] = in[12];

out[ 4] = in[1];
out[ 5] = in[5];
out[ 6] = in[9];
out[ 7] = in[13];

out[ 8] = in[2];
out[ 9] = in[6];
out[10] = in[10];
out[11] = in[14];

out[12] = in[3];
out[13] = in[7];
out[14] = in[11];
out[15] = in[15];
}

The Calc_Frustum() is called at the proper place in the main code, look at the glLoadMatrixf(MVM) for the debugging.
...
SetupView();
Calc_Frustum();
//drawing stuff
...

Drawing the calculated frustum points:
...
Draw_Frustum();
...

There are no transformations in Draw_Frustum(), just drawing the lines.
If the calculation is correct, the frustum should appear as a screen sized rectangle, regardless of the camera orientation.
The rotations apply, but the translations don't, so I see the rectangle, but its position is changing.
Maybe matrix representation of the points are wrong? Or I shouldn't invert the modelview matrix? Or something totally wrong here...

Thanks!

##### Share on other sites
The Modelview matrix isn't orthogonal.
So invert != transposed matrix
SORRY!

##### Share on other sites
The matrix stack being manipulated in updateFrustum() is the modelview matrix (GL_MODELVIEW).

##### Share on other sites
You should try to draw the frustum. This isn't easy, try to draw the normals of the
side planes, then draw the front and back planes as Quads with different colors and backface culling enabled. So you can determine if the orientations are good.

Or you could try (if you haven't yet) to comment all the statements in the isVector3dfInFrustum() function, so the points always pass, then uncomment the statements one by one, and just one at a time. Because if one of them is incorrect, the points will always fail.

The glLoadIdentity() in the updateFrustum() isn't clear for me.

##### Share on other sites
I have updated the code to try to eliminate typos. Here it is:

#define calculateFrustumPlane(a, b, c)     for(i = 0; i < 4; i++)         p->d[i] =  clip.m[a + i * 4] b clip.m[c + i * 4]FASTCALL void updateFrustum(){    struct Matrix4x4 proj, modl, clip;    struct Plane * p;    u8 i; // used in calculateFrustumPlane() macro    glMatrixMode(GL_MODELVIEW);    glPushMatrix();    glGetFloatv(GL_PROJECTION_MATRIX, &proj.m[0]);    glGetFloatv(GL_MODELVIEW_MATRIX, &modl.m[0]);    glPopMatrix();    clip = multiplyMatrix4x4(proj, modl);    p = &frustumPlane[RIGHT];    calculateFrustumPlane(3, -, 0);    p = &frustumPlane[LEFT];    calculateFrustumPlane(3, +, 0);    p = &frustumPlane[BOTTOM];    calculateFrustumPlane(3, +, 1);    p = &frustumPlane[TOP];    calculateFrustumPlane(3, -, 1);    p = &frustumPlane[BACK];    calculateFrustumPlane(3, -, 2);    p = &frustumPlane[FRONT];    calculateFrustumPlane(3, +, 2);    for (i = 0; i < 6; i++)        normalizePlane(&frustumPlane[i]);}FASTCALL bool isVector3dfInFrustum(struct vector3df d){    u8 i;    for(i = 0; i < 6; i++)        if(frustumPlane[BOTTOM].d[0] * d.x + frustumPlane[BOTTOM].d[1] * d.y + frustumPlane[BOTTOM].d[2] * d.z + frustumPlane[BOTTOM].d[3] > 0)            return false;    return true;}

##### Share on other sites
Now you are only testing against a single frustum plane...

##### Share on other sites
As noted above, you're testing against the same plane each time through the loop. Also, you should really make the point-plane test a function; using a loop to eliminate some of the redundant code is a good start, but it would make much more sense to make this a separate function that can be tested in isolation and used elsewhere in your code if needed.

I would also advise against making calculateFrustumPlane a macro. It looks like you're programming in pure C (where use of macros is a little more defensible than in C++), but there are still better, safer alternatives to using a macro (for example, you could use a function rather than a macro, and use a function pointer to abstract away the summation operation).

##### Share on other sites
Thank you for your help. However, I prefer C over C++ for many reasons, and will stick to using macros as it saves a function call (much the way an inline function does).

I have come here for help in debugging frustum culling code, not for the criticism of my coding technique.

The code that has been posted on this forum is a quick test case scenario, that has been broken down into smaller, stringier chunks to make it easier for online debugging here on the forums.

Hence, I openly welcome help on matters pertaining to why the frustum is not being extracted properly.

Thank you.

##### Share on other sites
Quote:
 Thank you for your help. However, I prefer C over C++ for many reasons, and will stick to using macros as it saves a function call (much the way an inline function does).I have come here for help in debugging frustum culling code, not for the criticism of my coding technique.
For the most part, my comments on your coding style were entirely relevant. The types of things you were doing in your originally posted code (typing things out by hand, overlooking opportunities to refactor) are *exactly* the kinds of things that make complex code like this difficult to debug. So I stand by my recommendations: cleaning up the code and addressing technical and stylistic issues can often be an important (sometimes even necessary) first step in fixing this sort of problem.

As for the macro, in most cases, frustum plane extraction code will be called once per frame, maybe a couple of times if you're doing picking or something of that sort. Do you really think the performance difference (if any) between a macro and a function call is going to be measurable in this case? Or is this a premature optimization? Have you profiled the application? If so, does the frustum plane extraction code even show up in the profile?

The reason I mention the macro thing is that in some cases using macros can introduce subtle bugs that can be avoided by using real functions. As such, using a function rather than a macro here could eliminate a possible source of error, thereby making it easier to debug the algorithm as a whole. (Also, note that I said nothing about using C++ rather than C, so I'm not sure what your comment about preferring C is in relation to.)

Again, stylistic and technical analysis of code such as this is often entirely relevant, even when it's not the stated subject of the post. Sorry the suggestions bug you, but they really are intended to help.

##### Share on other sites
The application I am writing is the basis of a multi-computer multi-threaded rendering farm. The culling code is re-used for every refraction rendering pass, every reflection rendering pass, and every normal rendering pass.

To set up a test case scenario to show how much juice the frustum culling code is taking I will (arbitrarily) create a 3D scene of a single house. This house has water running in the sink, 5 candles burning, and lets say 1 mirror, and 1 window. We will render 1 minute of video at 25 FPS.

The flames of each candle is composed of about ~5000 particles. Each particle has a unique light source attached to it, and affects the lighting of objects around it. It also affects the shadow projections of the objects around it. Thats 5x5000 light sources, and 5x5000 textured quads. For each of the particles the scene must be translated to its location, and the scene re-rendered for the shadow pass of the particles light source. Each time the scene is rendered, the culling code is called. Thats approximately 5x5000 calls to eh frustum culling code.

The water in the sink has to refract the scene, and reflect the scene. It must re-render all the geometry for each pass. This multiplies the frustum calls by 3 (original pass, reflection pass, and refraction pass). That is approximately 3x5x5000 calls to the frustum code.

The mirror only reflects the scene, and hence multiplies the frustum calls by 2. That is approximately 2x2x5x5000 calls to the frustum code.

The window both refracts the scene and reflects the scene, and multiplies the number of calls by 3. That is approximately 3x2x2x5x5000 calls to the frustum code.

That is a total of 300,000 calls to the frustum code in a single frame. Running at 25 FPS for 60 seconds, it is a grand total of 450,000,000 calls to the frustum code.

Rendering a scene of a house, with a window, a mirror, and 5 candles for 1 minute has called the frustum code 450,000,000 times. This is not a realistic scenario, as that would include a lot more in the scene and a lot more calls to the frustum code.

As you can see the frustum code may not be the biggest juice sucker, but still uses a massive amount of juice. This is why I am counting the number of function calls I use, limit the number of variables (this includes variables used by loops), and using FASTCALL calling conventions. This results in much stringier code, yes, but also much faster in the long run.

I would love to write it in a less-stringy way, but its not an option.

With that said, any ideas why the frustum is not being extracted correctly?

##### Share on other sites
Quote:
 The application I am writing is the basis of a multi-computer multi-threaded rendering farm. The culling code is re-used for every refraction rendering pass, every reflection rendering pass, and every normal rendering pass. To set up a test case scenario to show how much juice the frustum culling code is taking I will (arbitrarily) create a 3D scene of a single house. This house has water running in the sink, 5 candles burning, and lets say 1 mirror, and 1 window. We will render 1 minute of video at 25 FPS.The flames of each candle is composed of about ~5000 particles. Each particle has a unique light source attached to it, and affects the lighting of objects around it. It also affects the shadow projections of the objects around it. Thats 5x5000 light sources, and 5x5000 textured quads. For each of the particles the scene must be translated to its location, and the scene re-rendered for the shadow pass of the particles light source. Each time the scene is rendered, the culling code is called. Thats approximately 5x5000 calls to eh frustum culling code.The water in the sink has to refract the scene, and reflect the scene. It must re-render all the geometry for each pass. This multiplies the frustum calls by 3 (original pass, reflection pass, and refraction pass). That is approximately 3x5x5000 calls to the frustum code.The mirror only reflects the scene, and hence multiplies the frustum calls by 2. That is approximately 2x2x5x5000 calls to the frustum code.The window both refracts the scene and reflects the scene, and multiplies the number of calls by 3. That is approximately 3x2x2x5x5000 calls to the frustum code.That is a total of 300,000 calls to the frustum code in a single frame. Running at 25 FPS for 60 seconds, it is a grand total of 450,000,000 calls to the frustum code.
So, you're saying the frustum code is called a lot? (j/k :)

I didn't spot anything, but here are some things you might double-check:

1. Did you already fix the loop that was only testing against the bottom frustum plane? (Just checking...)

2. There are two forms of the frustum extraction algorithm you're using: one for D3D-style projection matrices, and one for OpenGL-style projection matrices (they differ in that D3D uses a distance of 0 for the near plane of the canonical view volume, while OpenGL uses a distance of -1). You might check to make sure you're using the right form of the algorithm, just in case.

I'm still not clear on how you're handling the matrices exactly (for example, right now you have a matrix push-pop in your code that doesn't actually do anything), so I can't really comment on that part of the code.

Lastly, have you tried attaching the frustum to a 'test' object of some sort and rendering it so that you can see if it's correct? That might help you nail down the source of the problem (if the frustum is obviously wrong, for example, that will point towards the frustum extraction or matrix transform code rather than the culling code).

##### Share on other sites
As I have now idea whats wrong, I would suggest you start by culling against one of the planes at a time. Also, try to cull against a different camera than your actual openGL view camera, then you can render the extracted planes as huge squares and literally see whats going one.

As long as it doesn't work, you should not care about speed. As soon as you get it working, you can refactor the code to your preferred lightning fast equivalent.

##### Share on other sites
Quote:
 Original post by szecsYou should try to draw the frustum. This isn't easy, try to draw the normals of the side planes, then draw the front and back planes as Quads with different colors and backface culling enabled. So you can determine if the orientations are good.Or you could try (if you haven't yet) to comment all the statements in the isVector3dfInFrustum() function, so the points always pass, then uncomment the statements one by one, and just one at a time. Because if one of them is incorrect, the points will always fail.

These ideas are totally wrong?
Or haven't you read this comment?
Or maybe my English :D
It's maybe 5 minutes of work and will work.
If it's bullshit than Sorry!

##### Share on other sites
#1:
Expanding your calculateFrustumPlane() macro reveals your method to be exactly like mine (with one exception covered in #2). This is a problem, since my matrices are row-major and yours are column-major. Transpose your matrix before using this routine, or rewrite the routine to work with column-major matrices.

#2:
Plane distances are always stored negative. This reduces a lot of otherwise redundant negations in plane equations.
This is the difference between my routine and yours.

A snippet of mine:
		// Left clipping plane.		pLeftPlane.n.x = _mMatrix._14 + _mMatrix._11;		pLeftPlane.n.y = _mMatrix._24 + _mMatrix._21;		pLeftPlane.n.z = _mMatrix._34 + _mMatrix._31;		pLeftPlane.dist = -(_mMatrix._44 + _mMatrix._41);		// Right clipping plane.		pRightPlane.n.x = _mMatrix._14 - _mMatrix._11;		pRightPlane.n.y = _mMatrix._24 - _mMatrix._21;		pRightPlane.n.z = _mMatrix._34 - _mMatrix._31;		pRightPlane.dist = -(_mMatrix._44 - _mMatrix._41);

And the associated way to compare points:
	// Determine on which side of the plane is given point is.	CPlane3::PLANE_INTERSECT LSM_CALL CIntersection::ClassifyPoint( const CPlane3 &_pPlane, const CVector3 &_vPoint ) {		FXREAL fDist = _pPlane.n.Dot( _vPoint ) - _pPlane.dist;		if ( fDist > FX_PLANE_THICKNESS ) { return CPlane3::PI_FRONT; }		if ( fDist < -FX_PLANE_THICKNESS ) { return CPlane3::PI_BACK; }		return CPlane3::PI_COPLANAR;	}

#3:
Extending off the above, you can see that it is insufficient to simply return true or false; there are 3 possible cases, and for numerical robustness each must be correctly handled.

#4:
You have already stressed how performance-demanding your routine needs to be. Fixing your plane (and vector) normalization yields the following:
    f32 mag = plane->a * plane->a + plane->b * plane->b + plane->c * plane->c;    if(mag)    {        mag = 1.0f / sqrt( mag );        plane->a *= mag;        plane->b *= mag;        plane->c *= mag;        plane->d *= mag;    }

Never divide multiple numbers by the same denominator. Get the reciprocal via one divide and then multiply your values by that number.

Storing plane distances as negatives is another optimization, and one assumed by many textbooks (which means the formulas they give will not work if your plane is not negated).

#5:
As already mentioned, your new version of isVector3dfInFrustum() uses only the BOTTOM plane.
Surely this is not the code you are using now, but I am covering every ground here.

L. Spiro

##### Share on other sites
Thank you YogurtEmperor, your post was very helpful. I had forgoten that division is slower than multiplication. I have re-written my frustum code as follows:
#define calculateFrustumPlane(a, b, c)     p->d[0] =  clip.m[a + 0 * 4] b clip.m[c + 0 * 4];     p->d[1] =  clip.m[a + 1 * 4] b clip.m[c + 1 * 4];     p->d[2] =  clip.m[a + 2 * 4] b clip.m[c + 2 * 4];     p->d[3] =  -(clip.m[a + 3 * 4] b clip.m[c + 3 * 4]);     normalizePlane(p);FASTCALL void updateFrustum(){    static struct Matrix4x4 proj, modl, clip;    static struct Plane * p;    glMatrixMode(GL_MODELVIEW);    glPushMatrix();    glGetFloatv(GL_PROJECTION_MATRIX, &proj.m[0]);    glGetFloatv(GL_MODELVIEW_MATRIX, &modl.m[0]);    glPopMatrix();    proj = getTransposedMatrix4x4(proj);    modl = getTransposedMatrix4x4(modl);    clip = multiplyMatrix4x4(proj, modl);    p = &frustumPlane[RIGHT];    calculateFrustumPlane(3, -, 0);    p = &frustumPlane[LEFT];    calculateFrustumPlane(3, +, 0);    p = &frustumPlane[BOTTOM];    calculateFrustumPlane(3, +, 1);    p = &frustumPlane[TOP];    calculateFrustumPlane(3, -, 1);    p = &frustumPlane[BACK];    calculateFrustumPlane(3, -, 2);    p = &frustumPlane[FRONT];    calculateFrustumPlane(3, +, 2);}// because I am only doing point based culling (no bbox, or bsphere) if a point is on a frustum plane it would not be seen anyways, so just return false.FASTCALL bool isVector3dfInFrustum(struct vector3df d){    static u8 i;    for(i = 0; i < 6; i++)        if(frustumPlane[i].d[0] * d.x + frustumPlane[i].d[1] * d.y + frustumPlane[i].d[2] * d.z - frustumPlane[i].d[3] <= 0)            return false;    return true;}FASTCALL struct Matrix4x4 getTransposedMatrix4x4(struct Matrix4x4 a){    struct Matrix4x4 b;    b.m[0]  = a.m[0];    b.m[1]  = a.m[4];    b.m[2]  = a.m[8];    b.m[3]  = a.m[12];    b.m[4]  = a.m[1];    b.m[5]  = a.m[5];    b.m[6]  = a.m[9];    b.m[7]  = a.m[13];    b.m[8]  = a.m[2];    b.m[9]  = a.m[6];    b.m[10] = a.m[10];    b.m[11] = a.m[14];    b.m[12] = a.m[3];    b.m[13] = a.m[7];    b.m[14] = a.m[11];    b.m[15] = a.m[15];    return b;}

It is now clipping some things, but not others. Moving the camera down the X-axis culls points in the distance down the Z-axis, rather than on the X-axis.

##### Share on other sites
You should swap the order of the operands in multiplyMatrix4x4() and transpose the clip matrix again, or modify the multiplyMatrix4x4()
function by indexing it like I did it in my first reply as YogurtEmperor told about matrix indexing.
So you don't have to transpose before or after the multiplication.

And I think you should invert the modelview matrix before the operations:

glMatrixMode(GL_MODELVIEW);f32 inv_modl[16];    glPushMatrix(); //these are totally useless here    glGetFloatv(GL_PROJECTION_MATRIX, &proj.m[0]);    glGetFloatv(GL_MODELVIEW_MATRIX, &modl.m[0]);    glPopMatrix(); //these are totally useless hereinvert(&modl.m[0], inv_modl);    //inv_modl = getInvertMatrix4x4(modl);    clip = multiplyMatrix4x4(proj, inv_modl);//the modified func

.....

I had the same problem as I mentioned before, and that was the solution.

Invertion code
/*	| a1 a2 |	| b1 b2 | calculate the determinent of a 2x2 matrix*/double det2x2(const double a1, const double a2,			const double b1, const double b2) {	return a1*b2 - b1*a2;}/*	| a1 a2 a3 |	| b1 b2 b3 |	| c1 c2 c3 | calculate the determinent of a 3x3 matrix*/double det3x3(const double a1, const double a2, const double a3,			  const double b1, const double b2, const double b3,			  const double c1, const double c2, const double c3) {	return a1*det2x2(b2,b3,c2,c3) - b1*det2x2(a2,a3,c2,c3) +			c1*det2x2(a2,a3,b2,b3);}void invert(float *output, float *i) {	double a11 =  det3x3(i[5],i[6],i[7],i[9],i[10],i[11],i[13],i[14],i[15]);	double a21 = -det3x3(i[1],i[2],i[3],i[9],i[10],i[11],i[13],i[14],i[15]);	double a31 =  det3x3(i[1],i[2],i[3],i[5],i[6],i[7],i[13],i[14],i[15]);	double a41 = -det3x3(i[1],i[2],i[3],i[5],i[6],i[7],i[9],i[10],i[11]);	double a12 = -det3x3(i[4],i[6],i[7],i[8],i[10],i[11],i[12],i[14],i[15]);	double a22 =  det3x3(i[0],i[2],i[3],i[8],i[10],i[11],i[12],i[14],i[15]);	double a32 = -det3x3(i[0],i[2],i[3],i[4],i[6],i[7],i[12],i[14],i[15]);	double a42 =  det3x3(i[0],i[2],i[3],i[4],i[6],i[7],i[8],i[10],i[11]);	double a13 =  det3x3(i[4],i[5],i[7],i[8],i[9],i[11],i[12],i[13],i[15]);	double a23 = -det3x3(i[0],i[1],i[3],i[8],i[9],i[11],i[12],i[13],i[15]);	double a33 =  det3x3(i[0],i[1],i[3],i[4],i[5],i[7],i[12],i[13],i[15]);	double a43 = -det3x3(i[0],i[1],i[3],i[4],i[5],i[7],i[8],i[9],i[11]);	double a14 = -det3x3(i[4],i[5],i[6],i[8],i[9],i[10],i[12],i[13],i[14]);	double a24 =  det3x3(i[0],i[1],i[2],i[8],i[9],i[10],i[12],i[13],i[14]);	double a34 = -det3x3(i[0],i[1],i[2],i[4],i[5],i[6],i[12],i[13],i[14]);	double a44 =  det3x3(i[0],i[1],i[2],i[4],i[5],i[6],i[8],i[9],i[10]);	double det = (i[0]*a11) + (i[4]*a21) + (i[8]*a31) + (i[12]*a41);	double oodet = 1/det;	output[ 0] = a11*oodet;	output[ 1] = a21*oodet;	output[ 2] = a31*oodet;	output[ 3] = a41*oodet;	output[ 4] = a12*oodet;	output[ 5] = a22*oodet;	output[ 6] = a32*oodet;	output[ 7] = a42*oodet;	output[ 8] = a13*oodet;	output[ 9] = a23*oodet;	output[10] = a33*oodet;	output[11] = a43*oodet;	output[12] = a14*oodet;	output[13] = a24*oodet;	output[14] = a34*oodet;	output[15] = a44*oodet;}

and another thing: you should pass the matrices to the functions with pointers, not the whole matrices because the CPU has to copy those matrices. It's easy to modify, a few minutes work.

I hope that helps you.

##### Share on other sites
Thank you for your help. I have re-written my code as recommended, but now nothing is drawn.

Here is the updated version:
#define calculateFrustumPlane(a, b, c)     p->d[0] =  clip.m[a + 0 * 4] b clip.m[c + 0 * 4];    p->d[1] =  clip.m[a + 1 * 4] b clip.m[c + 1 * 4];    p->d[2] =  clip.m[a + 2 * 4] b clip.m[c + 2 * 4];    p->d[3] =  -(clip.m[a + 3 * 4] b clip.m[c + 3 * 4]);    normalizePlane(p);FASTCALL void updateFrustum(){    static struct Matrix4x4 proj, modl, clip;    static struct Plane * p;    glGetFloatv(GL_PROJECTION_MATRIX, &proj.m[0]);    glGetFloatv(GL_MODELVIEW_MATRIX, &modl.m[0]);    modl = getInvertedMatrix4x4(modl);    clip = multiplyMatrix4x4(proj, modl);    p = &frustumPlane[RIGHT];    calculateFrustumPlane(3, -, 0);    p = &frustumPlane[LEFT];    calculateFrustumPlane(3, +, 0);    p = &frustumPlane[BOTTOM];    calculateFrustumPlane(3, +, 1);    p = &frustumPlane[TOP];    calculateFrustumPlane(3, -, 1);    p = &frustumPlane[BACK];    calculateFrustumPlane(3, -, 2);    p = &frustumPlane[FRONT];    calculateFrustumPlane(3, +, 2);}// make opengl do he matrix multiplicationFASTCALL struct Matrix4x4 multiplyMatrix4x4(struct Matrix4x4 a, struct Matrix4x4 b){    struct Matrix4x4 c;	glPushMatrix();	glLoadMatrixf(&b.m[0]);	glMultMatrixf(&a.m[0]);	glGetFloatv(GL_MODELVIEW_MATRIX, &c.m[0]);	glPopMatrix();	return c;}/** thanks to szecs frome GameDev.net **/FASTCALL f32 det2x2(f32 a1, f32 a2, f32 b1, f32 b2){	return a1 * b2 - b1 * a2;}/** thanks to szecs frome GameDev.net **/FASTCALL f32 det3x3(f32 a1, f32 a2, f32 a3, f32 b1, f32 b2, f32 b3, f32 c1, f32 c2, f32 c3){	return a1 * det2x2(b2, b3, c2, c3) - b1 * det2x2(a2, a3, c2, c3) + c1 * det2x2(a2, a3, b2, b3);}/** thanks to szecs frome GameDev.net **/FASTCALL struct Matrix4x4 getInvertedMatrix4x4(struct Matrix4x4 matrix){    struct Matrix4x4 ret;	f32 a11 =  det3x3(matrix.m[5], matrix.m[6], matrix.m[7], matrix.m[9], matrix.m[10], matrix.m[11],  matrix.m[13], matrix.m[14], matrix.m[15]);	f32 a21 = -det3x3(matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[9], matrix.m[10], matrix.m[11],  matrix.m[13], matrix.m[14], matrix.m[15]);	f32 a31 =  det3x3(matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[5], matrix.m[6],  matrix.m[7],   matrix.m[13], matrix.m[14], matrix.m[15]);	f32 a41 = -det3x3(matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[5], matrix.m[6],  matrix.m[7],   matrix.m[9],  matrix.m[10], matrix.m[11]);	f32 a12 = -det3x3(matrix.m[4], matrix.m[6], matrix.m[7], matrix.m[8], matrix.m[10], matrix.m[11], matrix.m[12],  matrix.m[14], matrix.m[15]);	f32 a22 =  det3x3(matrix.m[0], matrix.m[2], matrix.m[3], matrix.m[8], matrix.m[10], matrix.m[11], matrix.m[12],  matrix.m[14], matrix.m[15]);	f32 a32 = -det3x3(matrix.m[0], matrix.m[2], matrix.m[3], matrix.m[4], matrix.m[6],  matrix.m[7],  matrix.m[12],  matrix.m[14], matrix.m[15]);	f32 a42 =  det3x3(matrix.m[0], matrix.m[2], matrix.m[3], matrix.m[4], matrix.m[6],  matrix.m[7],  matrix.m[8],   matrix.m[10], matrix.m[11]);	f32 a13 =  det3x3(matrix.m[4], matrix.m[5], matrix.m[7], matrix.m[8], matrix.m[9], matrix.m[11],  matrix.m[12],  matrix.m[13], matrix.m[15]);	f32 a23 = -det3x3(matrix.m[0], matrix.m[1], matrix.m[3], matrix.m[8], matrix.m[9], matrix.m[11],  matrix.m[12],  matrix.m[13], matrix.m[15]);	f32 a33 =  det3x3(matrix.m[0], matrix.m[1], matrix.m[3], matrix.m[4], matrix.m[5], matrix.m[7],   matrix.m[12],  matrix.m[13], matrix.m[15]);	f32 a43 = -det3x3(matrix.m[0], matrix.m[1], matrix.m[3], matrix.m[4], matrix.m[5], matrix.m[7],   matrix.m[8],   matrix.m[9],  matrix.m[11]);	f32 a14 = -det3x3(matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[8], matrix.m[9], matrix.m[10],  matrix.m[12],  matrix.m[13], matrix.m[14]);	f32 a24 =  det3x3(matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[8], matrix.m[9], matrix.m[10],  matrix.m[12],  matrix.m[13], matrix.m[14]);	f32 a34 = -det3x3(matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[4], matrix.m[5], matrix.m[6],   matrix.m[12],  matrix.m[13], matrix.m[14]);	f32 a44 =  det3x3(matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[4], matrix.m[5], matrix.m[6],   matrix.m[8],   matrix.m[9],  matrix.m[10]);	f32 det = (matrix.m[0] * a11) + (matrix.m[4] * a21) + (matrix.m[8] * a31) + (matrix.m[12] * a41);	f32 oodet = 1.0f / det;	ret.m[0]  = a11 * oodet;	ret.m[1]  = a21 * oodet;	ret.m[2]  = a31 * oodet;	ret.m[3]  = a41 * oodet;	ret.m[4]  = a12 * oodet;	ret.m[5]  = a22 * oodet;	ret.m[6]  = a32 * oodet;	ret.m[7]  = a42 * oodet;	ret.m[8]  = a13 * oodet;	ret.m[9]  = a23 * oodet;	ret.m[10] = a33 * oodet;	ret.m[11] = a43 * oodet;	ret.m[12] = a14 * oodet;	ret.m[13] = a24 * oodet;	ret.m[14] = a34 * oodet;	ret.m[15] = a44 * oodet;	return ret;}OpenGL should be multiplying the matrices correctly, and I am inverting the model view matrix as instructed.Any ideas why its not working?

##### Share on other sites
Try this, if it isn't working, I won't reply any more:

static struct Matrix4x4 proj, modl, clip;    static struct Plane * p;    glGetFloatv(GL_PROJECTION_MATRIX, &proj.m[0]);    glGetFloatv(GL_MODELVIEW_MATRIX, &modl.m[0]);    clip = multiplyMatrix4x4(proj, modl);    clip = getInvertedMatrix4x4(clip);....

And try to use own multiplication code with correct indexing (as mentioned).

##### Share on other sites
With using your matrix multiplication code and inverting the clip matrix **everything** (including off-screen objects) is now rendered.

    clip = multiplyMatrix4x4(proj, modl);    clip = getInvertedMatrix4x4(clip);

/** thanks to szecs at GameDev.net **/FASTCALL struct Matrix4x4 multiplyMatrix4x4(struct Matrix4x4 a, struct Matrix4x4 b){    struct Matrix4x4 c;    c.m[0]  = a.m[0] * b.m[0]  + a.m[4] * b.m[1]  + a.m[8]  * b.m[2]  + a.m[12] * b.m[3];    c.m[1]  = a.m[1] * b.m[0]  + a.m[5] * b.m[1]  + a.m[9]  * b.m[2]  + a.m[13] * b.m[3];    c.m[2]  = a.m[2] * b.m[0]  + a.m[6] * b.m[1]  + a.m[10] * b.m[2]  + a.m[14] * b.m[3];    c.m[3]  = a.m[3] * b.m[0]  + a.m[7] * b.m[1]  + a.m[11] * b.m[2]  + a.m[15] * b.m[3];    c.m[4]  = a.m[0] * b.m[4]  + a.m[4] * b.m[5]  + a.m[8]  * b.m[6]  + a.m[12] * b.m[7];    c.m[5]  = a.m[1] * b.m[4]  + a.m[5] * b.m[5]  + a.m[9]  * b.m[6]  + a.m[13] * b.m[7];    c.m[6]  = a.m[2] * b.m[4]  + a.m[6] * b.m[5]  + a.m[10] * b.m[6]  + a.m[14] * b.m[7];    c.m[7]  = a.m[3] * b.m[4]  + a.m[7] * b.m[5]  + a.m[11] * b.m[6]  + a.m[15] * b.m[7];    c.m[8]  = a.m[0] * b.m[8]  + a.m[4] * b.m[9]  + a.m[8]  * b.m[10] + a.m[12] * b.m[11];    c.m[9]  = a.m[1] * b.m[8]  + a.m[5] * b.m[9]  + a.m[9]  * b.m[10] + a.m[13] * b.m[11];    c.m[10] = a.m[2] * b.m[8]  + a.m[6] * b.m[9]  + a.m[10] * b.m[10] + a.m[14] * b.m[11];    c.m[11] = a.m[3] * b.m[8]  + a.m[7] * b.m[9]  + a.m[11] * b.m[10] + a.m[15] * b.m[11];    c.m[12] = a.m[0] * b.m[12] + a.m[4] * b.m[13] + a.m[8]  * b.m[14] + a.m[12] * b.m[15];    c.m[13] = a.m[1] * b.m[12] + a.m[5] * b.m[13] + a.m[9]  * b.m[14] + a.m[13] * b.m[15];    c.m[14] = a.m[2] * b.m[12] + a.m[6] * b.m[13] + a.m[10] * b.m[14] + a.m[14] * b.m[15];    c.m[15] = a.m[3] * b.m[12] + a.m[7] * b.m[13] + a.m[11] * b.m[14] + a.m[15] * b.m[15];}

*sigh*. Any ideas?

##### Share on other sites
Turns out the matrix multiplication code is the problem, still working to fix it however.

The clip matrix is being returned as the following values:
{{1.#QNAN0, 1.#QNAN0, 1.#QNAN0, 1.#QNAN0} {1.#QNAN0, 1.#QNAN0, 1.#QNAN0, 1.#QNAN0} {1.#QNAN0, 1.#QNAN0, 1.#QNAN0, 1.#QNAN0} {1.#QNAN0, 1.#QNAN0, 1.#QNAN0, 1.#QNAN0}}

I have since re-written the matrix multiplication code:
FASTCALL struct Matrix4x4 multiplyMatrix4x4(struct Matrix4x4 a, struct Matrix4x4 b){    struct Matrix4x4 c;    s32 i, j, k;    for (i = 0; i < 4; i++)        for (j = 0; j < 4; j++)            for (k = 0; k < 4; k++)                c.m[i * 4 + j] += a.m[i * 4 + k] * b.m[k * 4 + j];    return c;}

This new multiplyMatrix4x4() function does not give weird values.

Now the inverted clip matrix is being returned as the following values:
{{0.000000, -1.#IND00, 0.000000, 0.000000} {0.000000, -1.#IND00, 0.000000, 0.000000} {0.000000, 0.000000, 0.000000, 0.000000} {-1.#IND00, -1.#IND00, 0.000000, -1.#IND00}}

Any ideas?

##### Share on other sites
Just a quick comment on your matrix multiplication code: you're not zeroing out c before you perform the multiplication, which means that the result may or may not be correct. (This may not be causing you any problems currently - for example, it may be that the memory just happens to be zeroed already for whatever reason - but it's something that should be fixed nonetheless.)

##### Share on other sites
I don't know. I thought functions cannot return arrays, just single values or pointers.
So he uses arrays that's really just pointers, that had been deallocated after returning from the functions. But it worked in some parts of his code for some reason, so I don't know.
Should use output params as pointers in the param. list. (void functions of course)

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628275
• Total Posts
2981740
• ### Similar Content

• By mellinoe
Hi all,
First time poster here, although I've been reading posts here for quite a while. This place has been invaluable for learning graphics programming -- thanks for a great resource!
Right now, I'm working on a graphics abstraction layer for .NET which supports D3D11, Vulkan, and OpenGL at the moment. I have implemented most of my planned features already, and things are working well. Some remaining features that I am planning are Compute Shaders, and some flavor of read-write shader resources. At the moment, my shaders can just get simple read-only access to a uniform (or constant) buffer, a texture, or a sampler. Unfortunately, I'm having a tough time grasping the distinctions between all of the different kinds of read-write resources that are available. In D3D alone, there seem to be 5 or 6 different kinds of resources with similar but different characteristics. On top of that, I get the impression that some of them are more or less "obsoleted" by the newer kinds, and don't have much of a place in modern code. There seem to be a few pivots:
The data source/destination (buffer or texture) Read-write or read-only Structured or unstructured (?) Ordered vs unordered (?) These are just my observations based on a lot of MSDN and OpenGL doc reading. For my library, I'm not interested in exposing every possibility to the user -- just trying to find a good "middle-ground" that can be represented cleanly across API's which is good enough for common scenarios.
Can anyone give a sort of "overview" of the different options, and perhaps compare/contrast the concepts between Direct3D, OpenGL, and Vulkan? I'd also be very interested in hearing how other folks have abstracted these concepts in their libraries.
• By aejt
I recently started getting into graphics programming (2nd try, first try was many years ago) and I'm working on a 3d rendering engine which I hope to be able to make a 3D game with sooner or later. I have plenty of C++ experience, but not a lot when it comes to graphics, and while it's definitely going much better this time, I'm having trouble figuring out how assets are usually handled by engines.
I'm not having trouble with handling the GPU resources, but more so with how the resources should be defined and used in the system (materials, models, etc).
This is my plan now, I've implemented most of it except for the XML parts and factories and those are the ones I'm not sure of at all:
I have these classes:
For GPU resources:
Geometry: holds and manages everything needed to render a geometry: VAO, VBO, EBO. Texture: holds and manages a texture which is loaded into the GPU. Shader: holds and manages a shader which is loaded into the GPU. For assets relying on GPU resources:
Material: holds a shader resource, multiple texture resources, as well as uniform settings. Mesh: holds a geometry and a material. Model: holds multiple meshes, possibly in a tree structure to more easily support skinning later on? For handling GPU resources:
ResourceCache<T>: T can be any resource loaded into the GPU. It owns these resources and only hands out handles to them on request (currently string identifiers are used when requesting handles, but all resources are stored in a vector and each handle only contains resource's index in that vector) Resource<T>: The handles given out from ResourceCache. The handles are reference counted and to get the underlying resource you simply deference like with pointers (*handle).
And my plan is to define everything into these XML documents to abstract away files:
Resources.xml for ref-counted GPU resources (geometry, shaders, textures) Resources are assigned names/ids and resource files, and possibly some attributes (what vertex attributes does this geometry have? what vertex attributes does this shader expect? what uniforms does this shader use? and so on) Are reference counted using ResourceCache<T> Assets.xml for assets using the GPU resources (materials, meshes, models) Assets are not reference counted, but they hold handles to ref-counted resources. References the resources defined in Resources.xml by names/ids. The XMLs are loaded into some structure in memory which is then used for loading the resources/assets using factory classes:
Factory classes for resources:
For example, a texture factory could contain the texture definitions from the XML containing data about textures in the game, as well as a cache containing all loaded textures. This means it has mappings from each name/id to a file and when asked to load a texture with a name/id, it can look up its path and use a "BinaryLoader" to either load the file and create the resource directly, or asynchronously load the file's data into a queue which then can be read from later to create the resources synchronously in the GL context. These factories only return handles.
Factory classes for assets:
Much like for resources, these classes contain the definitions for the assets they can load. For example, with the definition the MaterialFactory will know which shader, textures and possibly uniform a certain material has, and with the help of TextureFactory and ShaderFactory, it can retrieve handles to the resources it needs (Shader + Textures), setup itself from XML data (uniform values), and return a created instance of requested material. These factories return actual instances, not handles (but the instances contain handles).

Is this a good or commonly used approach? Is this going to bite me in the ass later on? Are there other more preferable approaches? Is this outside of the scope of a 3d renderer and should be on the engine side? I'd love to receive and kind of advice or suggestions!
Thanks!
• By nedondev
I 'm learning how to create game by using opengl with c/c++ coding, so here is my fist game. In video description also have game contain in Dropbox. May be I will make it better in future.
Thanks.

• So I've recently started learning some GLSL and now I'm toying with a POM shader. I'm trying to optimize it and notice that it starts having issues at high texture sizes, especially with self-shadowing.
Now I know POM is expensive either way, but would pulling the heightmap out of the normalmap alpha channel and in it's own 8bit texture make doing all those dozens of texture fetches more cheap? Or is everything in the cache aligned to 32bit anyway? I haven't implemented texture compression yet, I think that would help? But regardless, should there be a performance boost from decoupling the heightmap? I could also keep it in a lower resolution than the normalmap if that would improve performance.
Any help is much appreciated, please keep in mind I'm somewhat of a newbie. Thanks!

• Hi,
I'm trying to learn OpenGL through a website and have proceeded until this page of it. The output is a simple triangle. The problem is the complexity.
I have read that page several times and tried to analyse the code but I haven't understood the code properly and completely yet. This is the code:

I don't know what parts are necessary for that output. And also, what the correct order of instructions for such an output or programs is, generally. That start point is too complex for a beginner of OpenGL like me and I don't know how to make the issue solved. What are your ideas please? What is the way to figure both the code and the whole program out correctly please?
I wish I'd read a reference that would teach me OpenGL through a step-by-step method.

• 10
• 11
• 17
• 10
• 9