2

I am having some issues with the way in which I do my frustum culling. The current way does resolve in culling but there is a really odd effect. When I get too close to my main parent object, I am using a scenegraph to render everything, the objects starts flickering really fast. This is gone when I move away. I have tried a lot of things but have no ideas anymore. Do you guys have any thoughts. Any help is greatly appreciated.

I first create a boundingbox consisting of eight points around my models. These are correct as far as i am aware after a lot of testing.

This is my way of calculating the points of the frustum planes. THe camera position is the position in world space and the orientation is the direction it is looking at. Furhtermore the cameraUp and cameraRight are calculated every time the camera is rotated.

    Vector3 pos = Camera.staticPosition;
    Vector3 view = Camera.staticOrientation;
    Vector3 upVector3 = Camera.cameraUp;
    Vector3 rightVector3 = Camera.cameraRight;
    float toRadians = (float)Math.PI / 180.0f;
    float nearDis = .1f;
    float farDistance = 1000f;
    float fov = Game.FOV;
    float aspectRatio = 1.3f;

    //Get with and height of near and far plane
    float tanDiv = 2 * (float) Math.Tan(fov*toRadians / 2);
    float heightNear = tanDiv * nearDis;
    float widthNear = heightNear * aspectRatio;

    float heightFar = tanDiv * farDistance;
    float widthFar = heightFar * aspectRatio;

    // get the centre points of the planes so they can be used to calculate the edge points
    Vector3 centreNear = pos + view * nearDis;
    Vector3 centreFar = pos + view * farDistance;

    // get the halfht values of the width and hegiht to make sure you can get the points
    float hNearHalf = heightNear / 2;
    float wNearHalf = widthNear / 2;
    float hFarHalf = heightFar / 2;
    float wFarHalf = widthFar / 2;

    Vector3 nearTopLeft = centreNear + (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
    Vector3 nearTopRight = centreNear + (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
    Vector3 nearBottomLeft = centreNear - (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
    Vector3 nearBottomRight = centreNear - (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);

    Vector3 farTopLeft = centreFar + (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
    Vector3 farTopRight = centreFar + (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
    Vector3 farBotomLeft = centreFar - (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
    Vector3 farBottomRight = centreFar - (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);

I store my frustum points in an array. First thhe nearplane points, then the farplane, topplane, bottomplane, leftplane and lastly the rightplane. Then i loop through all the six planes and 8 points of the boundinbox if the point is on the right side of the plane increment the value of that key in the dictionary.

    Vector3[] frustumPoints = new Vector3[18]
    {
        nearTopLeft, nearTopRight, nearBottomLeft, farTopLeft, farTopRight, farBotomLeft, nearTopLeft, farTopLeft,
        nearTopRight, nearBottomLeft, farBotomLeft, nearBottomRight, nearTopLeft, nearBottomLeft, farTopLeft,
        nearTopRight, nearBottomRight, farTopRight
    };
    Dictionary<Vector3, int> count = new Dictionary<Vector3, int>(8);
    for (int value = 0; value < 8; value++)
    {
        count.Add(cubePositions[value], 0);
    }

    for (int x = 0; x < 18; x += 3)
    {
        Vector3 normal = NormalPlane(frustumPoints[x], frustumPoints[x + 1], frustumPoints[x + 2]);

        for (int y = 0; y < 8; y++)
        {
            Vector3 pointPlane = frustumPoints[x] - cubePositions[y];
            float dot = Vector3.Dot(pointPlane, normal);


            if (dot <= 0 && x % 6 == 0)
            {
                count[cubePositions[y]]++;
            }
            else if (dot >= 0 && x % 3 == 0)
            {
                count[cubePositions[y]]++;
            }

        }
    }

This is my method to get the normals of the plane

   Vector3 NormalPlane(Vector3 pointOne, Vector3 pointTwo, Vector3 pointThree)
{
    Vector3 normal;
    Vector3 edgeOne = pointTwo - pointOne; // calculate vector from point one to point two
    Vector3 edgeTwo = pointThree - pointOne; // calculate vector from point one to point three

    normal = Vector3.Normalize(Vector3.Cross(edgeOne, edgeTwo)); // calculate the cross product of the two given vectors. Then normalize it so you have normal of plane

    return normal; // return the normal 
}

If for one of these points on the cube the count is six, the points is within all planes and thus the frustum and I draw the object. If none of the points is equal to 6 the objects don't get drawn.

Problem is i have no idea where I am making a mistake so do you guys have any ideas?

Thanks in advance,

Jeromer

Jeromer
  • 49
  • 8

1 Answers1

3

If for one of these points on the cube the count is six, the points is within all planes and thus the frustum and I draw the object. If none of the points is equal to 6 the objects don't get drawn.

Your logic here seems to be

  • "if there is no vertex of the cube lying inside the frustum, the cube is not visible."

However. This is just wrong. Even if all 8 vertices of the cube lie outside the frustum, the cube still can intersect the frustum, as demonstrated in this 2D sketch:

                  *----------*
                  |          |
+-----------------+--+       |
 \                | /        |
  \               |/         |
   \              /          |
    \            /|          |
     \          / *----------*
      \        /
       \      /
        +----+

Hence you cull stuff which is potentially visible.

The usual logic for frustum culling is to cull the box only if all of its vertices are rejected by the same plane. (This will result in some odd cases where the box is completely outside and not culled, but these situations are quite unlikely and usually not a big deal to worry about.)

derhass
  • 43,833
  • 2
  • 57
  • 78
  • Thanks for answer. I'll try and implement what you told me. And you are right this is indeed something I had not thought of. Just need to figure out how I am going to change my method for this error that I have made. Thanks for pointing it out! – Jeromer Jun 25 '17 at 17:55
  • Oke that fixed some things. I am now calculating the min and max values of all the corners and seeing if the max is bigger than the max value of the frustum. If that is the case I cull. Problem is that when my parent gets culled the children also get culled. – Jeromer Jun 25 '17 at 19:27
  • If you do hierarchical culling, you also need hierarchical bounding volumes. – derhass Jun 25 '17 at 19:30
  • How do you mean hierarchical bounding volumes. Is it not sufficient to use the transform of its parent to decide the positions of points of the boundingbox or am I misinterpreting you? The rendering should also be bottom to top to clarify any confusion there. Thanks for the help! – Jeromer Jun 25 '17 at 19:43
  • This was indeed one of the main problems. Had some smaller ones as well. But this indeed caused some issues. – Jeromer Jun 30 '17 at 11:00