OpenGL Instanced Rendering with Level of Detail Problem:
I'm trying to draw a scene with a lot (about 10000) of similar objects (in my case bushes, but could be anything). For each bush I have three meshes with a different number of triangles and I want to use one of these meshes depending on the distance to the camera.

First approach:
I can select the correct mesh on the CPU, update the model matrix after every bush and then draw the VBO with the correct mesh. The problem is that I need to update the model matrix 10000 times per frame ... you can guess what this means performance wise.

Second Approach:
Again select the correct mesh on the CPU, but this time use instanced rendering to draw all bushes with lowest lod in one draw call, then the bushes with middle lod and then the bushes with high lod. I have stored the bush positions already on the GPU. But my problem here is that I still need to send an array as uniform variable which contains the information which mesh has to be drawn at which position. With this approach i run into the limit of uniform variables.

Question:
What I would like to do is to calculate the distance from the bush to the camera on the GPU (no problem for example in the vertex shader). And then draw only the VBO with the correct level of detail depending on the outcome. Therefore my question is if there is any possibility to select which VBO to draw on the GPU (I don't see any possibility to do this, since in the Vertex and Fragment shader I am a already to far down the pipeline)? Or do you have another idea that I could try?

Best, Albert
IMO, a variation of your second approach is going to be the simplest, and could be quite fast.

Have you profiled anything yet? A CPU should chew through 10000 matrix multiplications extremely quickly. If you wanted to get even more performance, you could SIMD / thread the update. That said, the slowest part is probably going to be the bandwidth of sending 10000 matrices over the PCIE bus. 

But, again, this is all supposition. Try it out, and profile.



I was thinking something like this:

(I apologize for the DX functions. I'm not super familiar with the corresponding OpenGL functions. That said, OpenGL should be quite similar)

// Variable definitions

vector&lt;matrix&gt; lod0;
vector&lt;matrix&gt; lod1;
vector&lt;matrix&gt; lod2;

ID3D11Buffer lod0VertexBuffer;
uint lod0VertexCount;

ID3D11Buffer lod1VertexBuffer;
uint lod1VertexCount;

ID3D11Buffer lod2VertexBuffer;
uint lod2VertexCount;

ID3D11Buffer instanceBuffer;

/// ..................


/// Per frame...
lod0.clear();
lod1.clear();
lod2.clear();

for (uint i = 0; i &lt; bushes.size(); ++i) {
    float distance = distance(bushes[i].pos, camera.origin);
    if (distance &lt; 50.0f) {
        lod0.push_back(bushes[i].matrix);
    } else if (distance &lt; 100.0f) {
        lod1.push_back(bushes[i].matrix);
    } else {
        lod2.push_back(bushes[i].matrix);
    }
}

D3D11_MAPPED_SUBRESOURCE mappedResource;
ID3D11Buffer vertexBuffers[] = {
    lod0VertexBuffer,
    instanceBuffer
};

// Update lod0 matrices
context-&gt;Map(instanceBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &amp;mappedResource);
memcpy(mappedResource.pData, &amp;lod0[0], sizeof(matrix) * lod0.size());
context-&gt;Unmap(instanceBuffer, 0);

// Draw lod0
context-&gt;IASetVertexBuffers(0, 2, vertexBuffers, nullptr, nullptr);
context-&gt;DrawInstanced(lod0VertexCount, lod0.size(), 0, 0);


// Update lod1 matrices
context-&gt;Map(instanceBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &amp;mappedResource);
memcpy(mappedResource.pData, &amp;lod1[0], sizeof(matrix) * lod1.size());
context-&gt;Unmap(instanceBuffer, 0);

// Draw lod1
vertexBuffers[0] = lod1VertexBuffer;
context-&gt;IASetVertexBuffers(0, 2, vertexBuffers, nullptr, nullptr);
context-&gt;DrawInstanced(lod1VertexCount, lod1.size(), 0, 0);


// Update lod2 matrices
context-&gt;Map(instanceBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &amp;mappedResource);
memcpy(mappedResource.pData, &amp;lod2[0], sizeof(matrix) * lod1.size());
context-&gt;Unmap(instanceBuffer, 0);

// Draw lod2
vertexBuffers[0] = lod2VertexBuffer;
context-&gt;IASetVertexBuffers(0, 2, vertexBuffers, nullptr, nullptr);
context-&gt;DrawInstanced(lod1VertexCount, lod2.size(), 0, 0);


If this ends up being too slow, you could try to do this calculation in a compute shader, then draw the result using an indirect draw call. See AZDO.