Custom Culling

Hello monkeys,

as the title suggests, still working on my voxelengine, I’m currently trying to implement some custom culling.
searching through the net I found this approach that I’m following
https://tomcc.github.io/2014/08/31/visibility-1.html
It works quite well so far and although I still have to play around with some parameters since my terrain looks somewhat different from the acticles game, using wireframe mode I already find some chunks beeing culled.

The way I hook the custom culling in, is by taking the players position and viewDirection on the jmeMain Thread, pass it to a thread to do the algorithm from the article and get a future for it. once the computation is done take the result set of chunks and set their shouldDraw flag mentioned below accordingly. also unset visible chunks from last check and then repeat by kicking off the thread to do the algorithm again. that works like a charm.
the thing is, I “had to” extend Node in a way like

public class VoxelNode extends Node {

    private static final Vector3f SIZE = PerformanceVariables.get().CHUNK_SIZE.toVector3f().multLocal(PerformanceVariables.get().BLOCK_SIZE);
    private static final Vector3f EXTEND = SIZE.mult(0.5f);

    private boolean shouldDraw = false;

    public VoxelNode(String name) {
        super(name);
        setRequiresUpdates(false);
        this.cullHint = CullHint.Dynamic;
    }

    public void setPosition(int x, int y, int z) {
        TempVars tmp = TempVars.get();
        tmp.vect1.x = x * SIZE.x + EXTEND.x;
        tmp.vect1.y = y * SIZE.y + EXTEND.y;
        tmp.vect1.z = z * SIZE.z + EXTEND.z;
        setLocalTranslation(x * SIZE.x, y * SIZE.y, z * SIZE.z);
        this.worldBound = new BoundingBox(tmp.vect1, EXTEND.x, EXTEND.y, EXTEND.z);
        tmp.release();
    }

    public void setShouldDraw(boolean draw) {
        shouldDraw = draw;
    }

    @Override
    public boolean checkCulling(Camera cam) {
        //hook custom culling into checkCulling before frustum culling since its cheaper at that point
        if (!shouldDraw) {
            return false;
        }
        //if custom culling failed, do frustum culling
        return super.checkCulling(cam);
    }

    @Override
    protected void updateWorldBound() {
        refreshFlags &= ~RF_BOUND;
    }

}

Notes about that implementation:

  • I manually set the culling mode because all voxelnodes are direct children of the root node which is most probably never culled and even if it is, the custom culling would have set these chunks to not draw already and it wouldn’t need the built in culling anyways
  • I set it to not requireUpdates since Node sets this flag to true for extending classes for some downwards compatibility that i dont need (at least for now, maybe i need to add some functional stuff to the nodes but I would then try the adding controls approach for that)
  • I use setPosition(chunkPos) method to calculate localTranslation and worldBounds and override updateWorldBound() method to only reset the flag. that is because I can just assume the BoundingVolume would be the full chunk, won’t hurt if its actually little bit smaller
  • I use setShouldDraw(draw) method to set the flag, that I later check in the overridden checkCulling(cam) method to see if I can skip built in frustum culling

So now to my questions:

  1. Since the wiki and some threads here point out that extending node is usually mixing model and view and can be done with controls the first question is: is this at all a valid approach or am I going completly wrong with what I’m doing? i just dont think there is a way to hook a control into a node in a way that alternates the culling similar to how I do it
  2. additionally to setting the worldBounds that I do in the VoxelNode class, i also manually set the meshes boundingVolume before I add it to its VoxelNode. Is that needed or is the meshes boundingVolume never reached since I override the Node the way I do and prevent it from recalculating its boundingVolume (I hope I completly prevent it from recalculatnig)?
    I’m talking about the rending aspect only, I guess dependant on how I implement physics i might eventually need the meshes boundingVolume
  3. last but not least and a little aside from the actual topic but still related:
    how would I go about setting the order the drawcalls are sent to the GPU each frame? the article mentions that there might be benefits from it in that the algorithm already orders the results front to back and thus some GPU hidden surface optimizations give greater benefits

Once more, thanks in advance and many greetings from the shire,
Samwise

You could do this without overriding Node.

Use the cull hint instead of your flag.

Set the bounding volume of the mesh then you won’t have to do it in your extended class.

Otherwise what position is doing could be done externally.

As always: thanks for the quick response :smiley:
But doesn’t that mean the node would recalculate its boundingVolume once I reset its children after some block changes? i just though i could make it like super rock solid never changing
Or can this basically be ignored as long as I set the children meshes boundingVolume (referred to question 2)?

World bound is only recalculated if the child geometry recalculates their bounds… which you have to force to happen. (or if the geometry moves but if you’re doing that then something is wrong with your approach).

So unless you call updateModelBound() on the Geometry, no matter what you do to the mesh, world bound will not be recalculated… but especially if the mesh bounds never changes.