I'm using glDrawArraysInstanced to draw multiple instances of a tree at different positions to generate a forest.
Is there a way to draw selected instances? For example: I got 100 trees with different attributes. Due to culling I only want to draw instance 3, 65, 89 and 95.
Being able to draw a single instance would already be enough.
There are several approaches you could take:
Use a separate buffer for your per-instance attribute(s), and fill it in each frame with the instances which pass your visibility test. This has the advantage of being very simple. Unless you have many thousands of trees, you shouldn't be generating significant bus traffic uploading this to GPU memory each frame. You can also use a hierarchical space division scheme (e.g. quadtree) to frustum-cull more efficiently. The main disadvantage is that you can only do frustum culling easily. Occlusion culling would require much more work.
Daniel Rakos describes a technique - Instance culling using geometry shaders - for using a geometry shader and transform feedback to generate a buffer containing the per-instance data only for visible instances.
As he notes towards the end of the article, it was written for a version of OpenGL which didn't have glVertexAttributeDivisor
, so you can ignore the suggestion to use uniform or texture buffer objects to store the per-instance data.
Although the technique as described only does frustum culling, I think you could do some additional visibility tests if you have the terrain already rendered into a depth texture. You could calculate the world position of the top of the tree and test its z-value against the value already in the buffer. If the top of the tree is occluded, then the rest of the tree will be also (you may need to use a point somewhere above the tree-top to account for tree and terrain shape, and also account somehow for the situation where the top of the tree is off-screen, but the rest of might not be).
I'm not sure how practical this is to use with a large number of trees. You would have to create a query object for each tree instance and issue a draw call with the simple stand-in geometry for each tree between calls to glBeginQuery
and glEndQuery
. You would then issue a draw call for the real geometry of each tree between calls to glBeginConditionalRender
and glEndConditionalRender
.
Note that although this results in a lot of draw calls (you would no longer be using glDrawArraysInstanced
), that need not be too expensive as you do not need to change much state between calls - just set the transform uniforms.
As an aside, you would probably be better off using indexed vertex data and glDrawElementsInstanced
instead of glDrawArraysInstanced
.