Skip to main content
GameDev.net gamedev.net
🔒 Locked

DX11 Instancing - Only render certain instances

Started by Veiled Glitch Mar 20, 2013 at 11:43 PM 1 replies 3.5k views
Original Post
Veiled Glitch
Veiled Glitch

Hi guys!

So, imagine you have a scene with 1000 trees and your rendering it with instancing, quite a lot, and you wan't to implement a lod system. Now your lod system is actually done, but now how do you change the buffers for that tree (the one too far away).

Illustration (real):
2uqd6px.png

Now as you see I have quite a lot of trees there, but now I only wan't some of those trees from my instanced buffer to be rendered. As I understand you have to update the buffer, but wouldn't that be quite heavy, or do I have to split up the instanced buffer into chunks, and update those? Right below I'm gonna show you how I handle my rendering.

Rendering:


UberBuffer._instance = true;
UberShader.SendObjectBuffer(ObjectBuffer, devcon);
UberShader.SendUberBuffer(UberBuffer, devcon);
InstancedMesh->SendInstancedData(ObjectBuffer, Camera, Bufferphase, devcon); // doesn't really matter for now, but if you wan't it, say it :)

bool changed = false;

for (int lod = -1; lod < InstancedMesh->Lods.GetCount(); lod++) // we start from -1 as some meshes don't have lods, so we actually trick it!
{
	if (changed)
	{
		InstancedMesh->SendBuffers(devcon, dev, Camera, ObjectBuffer, Bufferphase);
		changed = false;
	}

	if (lod > -1) // is this a lod?
	{
		for (int instance = 0; instance < InstancedMesh->instanceCount; instance++)
		{
			if (sqrtf(D3DXVec3Dot(&*Camera->GetPostion(), &InstancedMesh->instances[instance].pos)) >= InstancedMesh->Lods.GetComputedADistance(lod)) // distance...
			{
				InstancedMesh->Lods.GetComputedLod(lod)->SendVIBuffers(devcon, dev, Bufferphase); // new vertex buffer
				changed = true;

				// DO SOME STUFF HERE
			}
		}
	}

	UberShader.SendConstantBuffers(devcon);
	UberShader.Render(devcon, Bufferphase, true, InstancedMesh->instanceCount); // Render Instanced, one line of code: devcon->DrawInstanced(Bufferphase.IndexCount, instanceCount, 0, 0);

	for (int inSM = 0; inSM < (InstancedMesh->SubMeshes.size()); inSM++) // Sub meshes, doesn't really matter so much for now, I'll take care of those.
	{
		InstancedMesh->SendSubBuffers(devcon, dev, Camera, ObjectBuffer, Bufferphase, inSM);
		UberShader.Render(devcon, Bufferphase, true, InstancedMesh->instanceCount);
	}
} 

Now for each Lod i check all the instances for the distance, and if the distance is larger, then apply the different vertex buffer. But somehow I only need to apply this vertex buffer to the instances affected by it!

Now how is this possible? blink.png

Jason Z
Jason Z

I would try to just use two different vertex buffers, and you can stick with a single instance buffer. The trick is to reshuffle your instance data to have all of the high LOD instances in a continuous block, while the lower LOD instances should be in a separate block (you could just as easily implement this with two instance buffers I guess...). This takes two draw calls, but that isn't a big deal.

This would require modifying the data in the buffers, but it would only be necessary once in a while when the view is significantly moved. If you store your instances in an intelligent order (like in a quadtree fashion) then moving the data around should be minimally intrusive and will let you quickly get through the update.

Jason Zink :: DirectX MVP   Direct3D 11 engine on CodePlex: Hieroglyph 3 Direct3D Books: 
Veiled Glitch
Veiled Glitch

Alright got it working, thanks for pointing the way!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.