1
\$\begingroup\$

I started implementing instanced rendering in my 3D engine, but I quickly stumbled upon some issues that I'm not sure whats the best practice to work around.

When I setup my scene, I capture the amount of instances for every mesh and I write the transformation matrices first into a dynamic list and finally into an "instance buffer" (UBO) which is sent to the shaders and indexed by gl_InstanceID to fetch the correct transform. This is working perfectly.

So when I apply frustum culling per instance, what I do now is that once I found out that an instance should be culled, I remove this transformation matrix from the dynamic list and therefore I keep the transformation matrices of just the active instances which end up getting drawn from the glDrawElementsInstanced.

Obviously inserting and removing elements from this dynamic list is expensive and I want to get rid of it. So I was thinking that I'll implement a fixed length list this time consisting of per-instance structs to hold instance data something like this:

struct InstanceData {
    float worldMatrix[16];
    bool isOccluded;
    /* and more */
};

However this leads to another problem. In this case, since the draw call will render a fixed amount of instances all the time, regardless if they are visible or not, I'll have to discard the vertices in the shader, and I don't think that this is optimal either.

I've thought of other ways as well, such as sorting the instances based on their occlusion status on every frame, but then I'll have to pay the price for the sorting.

Is there any common practice to deal with instanced data? I fear that I should experiment with all the options and find what suits me best x.x

Thanks in advance

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Just have your VertexBuffer (for the insances) a fixed length (maximum allowed instances).

You also have a local buffer (array) of the same sice and an index variable. Each frame you set the index to zero and go over all of your objects. If it is in Frustum, add it to the local buffer (means: set the buffer at the current index with relevant data) and increment the index variable.

when done, you just put that data into your vertexbuffer from 0 to index and when drawing you send that buffer with a maxindex of your index. (there should be an overload when you set the data)

That way you don't need to recreate your VertexBuffer but just update it's contents (the same is true for your local buffer).

unfortunately, I can't provide any OpenGL Code so just talking about the theory how I woudld do it with DX, where there are overloads in SetData and DrawIndexedInstances, to just set/render a range of the buffer.

\$\endgroup\$
2
  • \$\begingroup\$ i get your point, but its also one of the cases that I briefly tried to describe, in this case you also suggest that I'll have to update the same data over and over again. so the question is: is it worth to do this update on every frame or minimize the number of updates and discard data in the shader? \$\endgroup\$
    – Greg
    Dec 8, 2019 at 12:48
  • \$\begingroup\$ that mainly depends on how much geometry you actually have in the scene. Occlusion Culling may not be necessary at all. You could even start out without it and if you feel you hit a bottleneck, you can add it later. for example, I have a particle renderer, which works with one giant vertex "ringbuffer" where I do no occlusion calling at all, because it would be to expensive. On the other hand if you've already space partioned your data somehow, a naiv occlusion culling may be a good idea. \$\endgroup\$
    – reiti.net
    Dec 8, 2019 at 21:22

You must log in to answer this question.

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