A doubt with my frustum plane generation algorithm

Hi, I have a doubt with my frustum plane generation algorithm.

I don’t understand the math involved in the extraction of the planes from a given matrix, the algorithm is copied from a tutorial web site.

The algorithm recieve a matrix which is the multiplication of the “ViewMatrix” by the “ProjectionMatrix” of the camera.

As the “ViewMatrix” I’m passing the transform matrix of the camera node, which stores the position and rotation of it, before pass it I flip the Look and Left components of the matrix because in OpenGL the camera points in negative Z, after this I finally calculate the inverse matrix and this is my “ViewMatrix”.

I use the generated planes to do a early frustum culling to the primitives before send it to the renderer.

The doubt come with te usage of the ‘ViewMatrix’ to extract the planes, becasue I test the planes against the AABB of my meshes in “WorldSpace”, and it seems works fine.

But, how it is possible? I suposse that the planes are in “ViewSpace” and the AABB of the meshes are in “WorldSpace”.

Here you can see the code of the plane extraction algorithm:

class FrustumSide
{
    public:

        GLfloat mDist;
        
        Vec3 mNormal;

        FrustumSide()
        {
        }

        FrustumSide( GLfloat dist, Vec3 normal )
        {
            this->Set( dist, normal );
        }
        
        [...]
};

void Frustum::Init( Mat4 viewProj )
{
    uint_fast32_t i;
    FrustumSide sides[6];

    // this function generates the frustum sides pointing to inside, so we need negate it
    
    sides[0].Set( viewProj[15] - viewProj[12], -Vec3( viewProj[3] - viewProj[0], viewProj[7] - viewProj[4], viewProj[11] - viewProj[8] ) );

    sides[1].Set( viewProj[15] + viewProj[12], -Vec3( viewProj[3] + viewProj[0], viewProj[7] + viewProj[4], viewProj[11] + viewProj[8] ) );

    sides[2].Set( viewProj[15] + viewProj[13], -Vec3( viewProj[3] + viewProj[1], viewProj[7] + viewProj[5], viewProj[11] + viewProj[9] ) );

    sides[3].Set( viewProj[15] - viewProj[13], -Vec3( viewProj[3] - viewProj[1], viewProj[7] - viewProj[5], viewProj[11] - viewProj[9] ) );

    sides[4].Set( viewProj[15] - viewProj[14], -Vec3( viewProj[3] - viewProj[2], viewProj[7] - viewProj[6], viewProj[11] - viewProj[10] ) );

    sides[5].Set( viewProj[15] + viewProj[14], -Vec3( viewProj[3] + viewProj[2], viewProj[7] + viewProj[6], viewProj[11] + viewProj[10] ) );


    for ( i = 0; i < 6; i++ )
    {
        sides[i].Normalize();

        this->SetSide( i, sides[i] );
    }
}

The view matrix transforms from world space to eye space. The projection matrix transforms from eye space to clip space. The combination of projection and view matrices transforms from world space to clip space. The inverse of that matrix transforms from clip space to world space.

The frustum planes are x=w, x=-w, y=w, y=-w, z=w, z=-w, in clip space.

So you transform world-space [xw,yw,zw,ww] to clip space [xc,yc,zc,wc] then set xc=±wc <=> xc∓wc=0.

xc = Mx · [xw yw zw ww]T
wc = Mw · [xw yw zw ww]T

where Mx, My etc are the rows of the matrix.

xc∓wc = Mx · [xw yw zw ww]T ∓ Mw · [xw yw zw ww]T
= (Mx ∓ Mw) · [xw yw zw ww]T

So the coefficients of the world-space plane equations are obtained by adding or subtracting the x/y/z rows and the w row.