I'm trying to extract frustum planes from the camera.
The algorithm is simple:
- create clip to world space matrix (inversed projection * inversed view)
- multiply clip point by clip to world matrix
- 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;
}