1
\$\begingroup\$

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.

at zero a little forward too much 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;
    }
\$\endgroup\$
1
  • \$\begingroup\$ Can you describe in more detail what specifically goes wrong when doing this in C#/OpenTK that you did not observe in C++/glm? \$\endgroup\$
    – DMGregory
    Mar 14, 2019 at 15:04

1 Answer 1

2
\$\begingroup\$

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

Green lines are frustum in world space. enter image description here

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

                Matrix4 clipToWorld = cameraMatrixInverse * projectionMatrixInverse;

                UpdateFrustumPoints(clipToWorld);
                UpdateFrustumPlanes();
            }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .