Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8583113
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 11, 20262026-06-11T21:27:27+00:00 2026-06-11T21:27:27+00:00

I am currently trying to implement frustum culling (again) for my world. My world

  • 0

I am currently trying to implement frustum culling (again) for my world. My world consists of chunks with the size 16x256x16 (x, y, z):

Frustum frustum = Frustum(engine.proj * engine.view);

foreach(chunkc, chunk; chunks) {
    vec3i w_chunkc = vec3i(chunkc.x*16, chunkc.y*256, chunkc.z*16);

    AABB aabb = AABB(vec3(w_chunkc), vec3(w_chunkc.x+16, w_chunkc.y+256, w_chunkc.z+16));
    if(aabb in frustum) {
        bind(engine, chunk);

        glDrawArrays(GL_TRIANGLES, 0, cast(uint)chunk.vbo_vcount);
    }
}

chunkc holds the coordinates of the whole chunk e.g. [0, 0, -2]. So to get the chunks bounding box, I have to multiply these coordinates by the size of each chunk to get the minimal position of the AABB and add the size to each component to get the max. position of the AABB. Then I check this AABB against the frustum.

Frustum implementation:

struct Frustum {
    enum {
        LEFT, /// Used to access the planes array.
        RIGHT, /// ditto
        BOTTOM, /// ditto
        TOP, /// ditto
        NEAR, /// ditto
        FAR /// ditto
    }

    Plane[6] planes; /// Holds all 6 planes of the frustum.

    @safe pure nothrow:

    @property ref Plane left() { return planes[LEFT]; }
    @property ref Plane right() { return planes[RIGHT]; }
    @property ref Plane bottom() { return planes[BOTTOM]; }
    @property ref Plane top() { return planes[TOP]; }
    @property ref Plane near() { return planes[NEAR]; }
    @property ref Plane far() { return planes[FAR]; }

    /// Constructs the frustum from a model-view-projection matrix.
    /// Params:
    /// mvp = a model-view-projection matrix
    this(mat4 mvp) {
        planes = [
            // left
            Plane(mvp[0][3] + mvp[0][0], // note: matrices are row-major
                mvp[1][3] + mvp[1][0],
                mvp[2][3] + mvp[2][0],
                mvp[3][3] + mvp[3][0]),

            // right
            Plane(mvp[0][3] - mvp[0][0],
                mvp[1][3] - mvp[1][0],
                mvp[2][3] - mvp[2][0],
                mvp[3][3] - mvp[3][0]),

            // bottom
            Plane(mvp[0][3] + mvp[0][1],
                mvp[1][3] + mvp[1][1],
                mvp[2][3] + mvp[2][1],
                mvp[3][3] + mvp[3][1]),
            // top
            Plane(mvp[0][3] - mvp[0][1],
                mvp[1][3] - mvp[1][1],
                mvp[2][3] - mvp[2][1],
                mvp[3][3] - mvp[3][1]),
            // near
            Plane(mvp[0][3] + mvp[0][2],
                mvp[1][3] + mvp[1][2],
                mvp[2][3] + mvp[2][2],
                mvp[3][3] + mvp[3][2]),
            // far
            Plane(mvp[0][3] - mvp[0][2],
                mvp[1][3] - mvp[1][2],
                mvp[2][3] - mvp[2][2],
                mvp[3][3] - mvp[3][2])
        ];

        normalize();
    }

    /// Constructs the frustum from 6 planes.
    /// Params:
    /// planes = the 6 frustum planes in the order: left, right, bottom, top, near, far.
    this(Plane[6] planes) {
        this.planes = planes;
        normalize();
    }

    private void normalize() {
        foreach(ref e; planes) {
            e.normalize();
        }
    }

    /// Checks if the $(I aabb) intersects with the frustum.
    /// Returns OUTSIDE (= 0), INSIDE (= 1) or INTERSECT (= 2).
    int intersects(AABB aabb) {
        vec3 hextent = aabb.half_extent;
        vec3 center = aabb.center;

        int result = INSIDE;
        foreach(plane; planes) {
            float d = dot(center, plane.normal);
            float r = dot(hextent, abs(plane.normal));

            if(d + r < -plane.d) {
                // outside
                return OUTSIDE;
            }
            if(d - r < -plane.d) {
            result = INTERSECT;
            }
        }

        return result;
    }

    /// Returns true if the $(I aabb) intersects with the frustum or is inside it.
    bool opBinaryRight(string s : "in")(AABB aabb) {
        return intersects(aabb) > 0;
    }
}

And the AABB implementation:

struct AABBT(type) {
        alias type at; /// Holds the internal type of the AABB.
        alias Vector!(at, 3) vec3; /// Convenience alias to the corresponding vector type.

        vec3 min = vec3(0.0f, 0.0f, 0.0f); /// The minimum of the AABB (e.g. vec3(0, 0, 0)).
        vec3 max = vec3(0.0f, 0.0f, 0.0f); /// The maximum of the AABB (e.g. vec3(1, 1, 1)).

        @safe pure nothrow:

        /// Constructs the AABB.
        /// Params:
        /// min = minimum of the AABB
        /// max = maximum of the AABB
        this(vec3 min, vec3 max) {
            this.min = min;
            this.max = max;
        }

        /// Constructs the AABB around N points (all points will be part of the AABB).
        static AABBT from_points(vec3[] points) {
            AABBT res;

            foreach(v; points) {
                res.expand(v);
            }

            return res;
        }

        /// Expands the AABB by another AABB.
        void expand(AABBT b) {
            if (min.x > b.min.x) min.x = b.min.x;
            if (min.y > b.min.y) min.y = b.min.y;
            if (min.z > b.min.z) min.z = b.min.z;
            if (max.x < b.max.x) max.x = b.max.x;
            if (max.y < b.max.y) max.y = b.max.y;
            if (max.z < b.max.z) max.z = b.max.z;
        }

        /// Expands the AABB, so that $(I v) is part of the AABB.
        void expand(vec3 v) {
            if (v.x > max.x) max.x = v.x;
            if (v.y > max.y) max.y = v.y;
            if (v.z > max.z) max.z = v.z;
            if (v.x < min.x) min.x = v.x;
            if (v.y < min.y) min.y = v.y;
            if (v.z < min.z) min.z = v.z;
        }


        /// Returns true if the AABBs intersect.
        /// This also returns true if one AABB lies inside another.
        bool intersects(AABBT box) const {
            return (min.x < box.max.x && max.x > box.min.x) &&
                (min.y < box.max.y && max.y > box.min.y) &&
                (min.z < box.max.z && max.z > box.min.z);
        }

        /// Returns the extent of the AABB (also sometimes called size).
        @property vec3 extent() const {
            return max - min;
        }

        /// Returns the half extent.
        @property vec3 half_extent() const {
            return 0.5 * (max - min);
        }

        /// Returns the area of the AABB.
        @property at area() const {
            vec3 e = extent;
            return 2.0 * (e.x * e.y + e.x * e.z + e.y * e.z);
        }

        /// Returns the center of the AABB.
        @property vec3 center() const {
            return 0.5 * (max + min);
        }

        /// Returns all vertices of the AABB, basically one vec3 per corner.
        @property vec3[] vertices() const {
            return [
                vec3(min.x, min.y, min.z),
                vec3(min.x, min.y, max.z),
                vec3(min.x, max.y, min.z),
                vec3(min.x, max.y, max.z),
                vec3(max.x, min.y, min.z),
                vec3(max.x, min.y, max.z),
                vec3(max.x, max.y, min.z),
                vec3(max.x, max.y, max.z),
            ];
        }

        bool opEquals(AABBT other) const {
            return other.min == min && other.max == max;
        }
    }

    alias AABBT!(float) AABB;

So far in theory, unfortunatly I get completly wrong results, in certain dirctions (z- and x+) the whole world disappears and in all other directions nothing is culled.

I hope anyone of you has an idea why this doesn’t work.

EDIT (different method of checking AABB agains Frustum):

bool intersects2(AABB aabb) {
    foreach(plane; planes) {
        if(plane.a * aabb.min.x + plane.b * aabb.min.y + plane.c * aabb.min.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.max.x + plane.b * aabb.min.y + plane.c * aabb.min.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.min.x + plane.b * aabb.max.y + plane.c * aabb.min.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.max.x + plane.b * aabb.max.y + plane.c * aabb.min.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.min.x + plane.b * aabb.min.y + plane.c * aabb.max.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.max.x + plane.b * aabb.min.y + plane.c * aabb.max.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.min.x + plane.b * aabb.max.y + plane.c * aabb.max.z + plane.d > 0 )
            continue;
        if(plane.a * aabb.max.x + plane.b * aabb.max.y + plane.c * aabb.max.z + plane.d > 0 )
            continue;
        return false;
    }
    return true;
}

Edit 2 (Example input):

Here is a MVP:

[[1.18424,0,0.31849,-331.577],
[0.111198,1.51016,-0.413468,-88.5585],
[0.251117,-0.274135,-0.933724,214.897],
[0.249864,-0.272768,-0.929067,215.82]]

And a possible failing AABB:
min: (14*16, 0, 13*16)
max: (14*16+16, 256, 13*16+16)

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-11T21:27:28+00:00Added an answer on June 11, 2026 at 9:27 pm

    Ok, I have the answer now … a really stuipid thing, I didn’t think of.

    I did what “Peter Alexander” suggested and tried to debug everything … I ended up finding out that the frustum-planes are completly wrong (left and right planes normals were pointing at the same direction) so I messed with my code and other example codes and found out, the the matrix wasn’t transposed (I store it as row-major, opengl as column.major), so a simple: mvp.transpose() in the Frustum-Ctor fixes my frustum.

    Thanks for your help.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm currently trying to implement a Table View on my iPhone app that grabs
I'm currently trying to implement a editable details view using a grouped UITableView. I'd
I am currently trying to implement a grid view in the iPhone SDK, whereby
I am trying to implement frustum culling in my OpenGL 2d game. The only
I am currently trying to implement a graph on a website from a raw
I am currently trying to implement Conway's Game of Life in a Code, and
I'm currently trying to implement some kind of search system in a program of
I am currently trying to implement a PNG encoder in C++ based on libpng
I'm currently trying to implement a socket server that enables the clients to send
I'm currently trying to implement a simple Add-In for InfoPath 2010 Filler/Editor mode, which

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.