# OpenGL frustum extraction

I'm trying to extract frustum planes from the camera.

The algorithm is simple:

1. create clip to world space matrix (inversed projection * inversed view)
2. multiply clip point by clip to world matrix
3. divide xyz by w

This worked fine with glm and c++, but in c# with openTK doesn't.

It might be something with row and column major matrices of openTK (matrix order is reversed).

Frustum is updated on start and when entity is moved.

Can anyone spot the mistake?

I am using entity component system just like in unity.

Monkey head entity has a second component that is using transform.getForward() and transform.Position to create camera/view matrix. Camera is facing forward with the monkey head. Images are of monkey head as it moves forward.

Here is the code:

class Frustum
{
/*frustum in world space
0                                               1
(1,1,1)-----------------------------------------(-1,1,1)
|                                               |
|           4                       5           |
|       (1,1,-1)----------------(-1,1,-1)       |
|           |                       |           |
|           |                       |           |
|           |                       |           |
|           |                       |           |
|           |                       |           |
|           |                       |           |
|       (1,-1,-1)----------------(-1,-1,-1)     |
|           7                       6           |
|                                               |
|                                               |
(1,-1,1)----------------------------------------(-1,-1,1)
3                                               2
*/

public Frustum()
{
worldPoints = new Vector3[8];
clipPoints = new Vector4[8];
planes = new Plane[6];

for (int i = 0; i < 6; ++i)
planes[i] = new Plane();

//frusum in clip space
clipPoints[0] = new Vector4(-1,1,1,1);
clipPoints[1] = new Vector4(1,1,1,1);
clipPoints[2] = new Vector4(1,-1,1,1);
clipPoints[3] = new Vector4(-1,-1,1,1);

clipPoints[4] = new Vector4(-1,1,-1,1);
clipPoints[5] = new Vector4(1,1,-1,1);
clipPoints[6] = new Vector4(1,-1,-1,1);
clipPoints[7] = new Vector4(-1,-1,-1,1);
}

public void Update(Matrix4 cameraMatrixInverted, Matrix4 projectionMatrixInverted)
{
Matrix4 clipToWorld = projectionMatrixInverted * cameraMatrixInverted;

UpdateFrustumPoints(clipToWorld);
UpdateFrustumPlanes();
}

private void UpdateFrustumPoints(Matrix4 clipToWorld)
{
for (int i = 0; i < 8; ++i)
{
Vector4 wp = clipToWorld * clipPoints[i];
wp.W = 1.0f / wp.W;
worldPoints[i] = wp.Xyz * wp.W;
}
}

private void UpdateFrustumPlanes()
{
Vector3 n;
Vector3 a, b;

//back      ok
a = worldPoints[6] - worldPoints[7];
b = worldPoints[4] - worldPoints[7];

n = Vector3.Cross(a,b).Normalized();
planes[0].normal = n;
planes[0].distance = Vector3.Dot(n, worldPoints[7]);

//up        ok
a = worldPoints[5] - worldPoints[4];
b = worldPoints[0] - worldPoints[4];

n = Vector3.Cross(a, b).Normalized();
planes[1].normal = n;
planes[1].distance = Vector3.Dot(n, worldPoints[4]);

//down      ok
a = worldPoints[2] - worldPoints[3];
b = worldPoints[7] - worldPoints[3];

n = Vector3.Cross(a, b).Normalized();
planes[2].normal = n;
planes[2].distance = Vector3.Dot(n, worldPoints[3]);

//left      ok
a = worldPoints[7] - worldPoints[3];
b = worldPoints[0] - worldPoints[3];

n = Vector3.Cross(a, b).Normalized();
planes[3].normal = n;
planes[3].distance = Vector3.Dot(n, worldPoints[3]);

//right     ok
a = worldPoints[1] - worldPoints[2];
b = worldPoints[6] - worldPoints[2];

n = Vector3.Cross(a, b).Normalized();
planes[4].normal = n;
planes[4].distance = Vector3.Dot(n, worldPoints[2]);

//front     ok
n = -planes[0].normal;
planes[5].normal = n;
planes[5].distance = Vector3.Dot(n, worldPoints[3]);
}

public void DrawFrustum(Vector3 color)
{
var debug = DebugS.GetInstance();

debug.DrawLine(worldPoints[0], worldPoints[1], color);
debug.DrawLine(worldPoints[1], worldPoints[2], color);
debug.DrawLine(worldPoints[2], worldPoints[3], color);
debug.DrawLine(worldPoints[3], worldPoints[0], color);

debug.DrawLine(worldPoints[0], worldPoints[4], color);
debug.DrawLine(worldPoints[1], worldPoints[5], color);
debug.DrawLine(worldPoints[2], worldPoints[6], color);
debug.DrawLine(worldPoints[3], worldPoints[7], color);

debug.DrawLine(worldPoints[4], worldPoints[5], color);
debug.DrawLine(worldPoints[5], worldPoints[6], color);
debug.DrawLine(worldPoints[6], worldPoints[7], color);
debug.DrawLine(worldPoints[7], worldPoints[4], color);
}

private Vector3[] worldPoints;
private Vector4[] clipPoints;
private Plane[] planes;
}

• Can you describe in more detail what specifically goes wrong when doing this in C#/OpenTK that you did not observe in C++/glm? Commented Mar 14, 2019 at 15:04

In openTK you need to transpose matrices to make it work.

Green lines are frustum in world space.

public void Update(Matrix4 cameraMatrixInverse, Matrix4 projectionMatrixInverse)
{
cameraMatrixInverse.Transpose();
projectionMatrixInverse.Transpose();

Matrix4 clipToWorld = cameraMatrixInverse * projectionMatrixInverse;

UpdateFrustumPoints(clipToWorld);
UpdateFrustumPlanes();
}