DX11 - Instancing - The choice of method

Started by
5 comments, last by Key_46 10 years, 9 months ago

Hello guys!

As you know, Directx has a feature called 'Instancing', which is quite wonderful actually. But how to use it properly is an entirely different chapter. And that's why I'm here.

Imagine Crysis or some other game where high level of vegetation is needed, as grass, and you need to render that. What I would do, and what I actually do:

When creating the scene:

When Creating the scene:

  • Add all instances of grass
  • Split all instances into different patches
  • Create Instance Buffers

When Rendering the scene:

  • Do some range testing and frustum culling for all patches, and all valid are added to a list.
  • Render each individual element in the list

Now that method works fine for me when using static non destroyable or creatable objects, but imagine if one object has to be created? Do I recalculate the respective buffer for the bullets location.

Also in the Crysis Sandbox, or CryEngine 3 SDK, when placing/painting vegetation over the terrain, they appear lightning fast! If you have time, how does produceal vegetation work in a nutshell?

But what if we are simulating a space ship, IN SPACE! Where the space is almost unlimited, and then the player shoots, I can't have buffers for an unlimited space! (I could create buffers dynamically for where I am, but I'm not sure if that's efficient).

So, now, I ask you, what, if it exists, is the most efficient way of handeling instances of an object?

Thank You, again...

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

Advertisement

Do I recalculate the respective buffer for the bullets location.
i don't quite follow, how'd you get from instancing vegetation to drawing bullets?
some cry3 specific thing i assume.
generally speaking, you'll have a model in buffers (vertex and index), and transforms for each instance in another buffer.
for modifiable vegetation, simply recalculate part or all of the transform buffer when required. you may also be able to do some indexing trick to only draw a range of instances in the transform buffer, and include/exclude vegetation that way.
although i'm not that well versed in dx11, i think you could also pass in flags in a constant buffer that could be used to determine which instances to draw.
it my also be possible to use some reserved value for a variable in the instance buffer that indicates "don't draw this instance".
it also may be possible to pass in some sort of "instance buffer" as well as the "transform buffer". the instance buffer would have a flag for each instance or perhaps work with indexes. not sure how many input buffers of what type you can use in dx11.
in the long run, recalculating the transform buffer, passing constant buffers, reserved values, an instance buffer (if supported), and drawing index ranges are all just different ways of telling directx which plants to draw.
me personally, i'd probably just recalculate the transform buffer as needed. i do a similar thing in my current title. vegetation is modifiable. terrain is drawn in chunks which are generated as needed from the various data structures that describe whats in the world. Any immobile object created in the world (a hut, landmark, storage pit, temporary shelter, or bedding) means the plants there should not be drawn. so whenever an immobile world object is created or destroyed, its "chunk" gets regenerated to add or remove the plants as needed.
when i generate a chunk, i basically do my own instancing to create the ground mesh for each ground texture tile. the "model" is a simple quad. a "pattern map" says which quads in the chunk's ground mesh use a given tile texture. for each quad that uses a given texture, the "model" is transformed to the correct x,z location in the chunk, procedurally height mapped in y, and added to a VB and IB. there's a VB and IB for each ground tile texture in the chunk. when its time to draw, i just set the ground texture and draw the VB for that texture, as the VB is already "pre-instanced" so to speak.
i still don't get the part about bullets and buffers though...

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

With the bullets, i mean this:

(Just an example)

Imagine thousands of spaceships, shooting lasers (or something) all the time, I would imagine that I would instance all bullets, wouldn't I? In that case I don't really see how I would split up each bullet up into a chunk, as they could go anywhere...

But Thanks!

FastCall22: "I want to make the distinction that my laptop is a whore-box that connects to different network"

Blog about... stuff (GDNet, WordPress): www.gamedev.net/blog/1882-the-cuboid-zone/, cuboidzone.wordpress.com/

In general you take a single geometry object (i.e. a vertex buffer and possibly an index buffer) and replicate it as needed. Where and how many to replicate is determined by the instance buffer. Here you will put the world matrix (for example) of each bullet in the world. In your shader you will multiply your model's vertices with the particular instance's world matrix to determine where in the world that particular instance is. It's like you were using the geometry you wanted to instance as a stamp, then the instance buffer would contain the locations where you need to stamp :) (and other properties, like the colour for example)

If the number of instances changes, one approach is to recompute all of it and re-bind it. If your geometry is mostly static, then another approach is to a create a "large enough" buffer. You can bind it even though it could not be full. When the need arises, you simply add more entries to the buffer, without having to recreate the other ones. This also sets some sort of limit for your rendering engine as it's like saying that you can render up to X instances.

In the specific case of spaceships though, I think you'd need to update them each frame. BUT! If you go for the hard science approach, then you don't need to worry about any of this at all, beam weapons are supposed to travel at the speed of light so .. problem solved!

--Avengers UTD Chronicles - My game development blog

Procedural generation of vegetation typically means that you don't have to know / create all the instances before you need them. That is, when the vegetation block is close enough you can calculate what kind of foliage / vegetation should occupy the area.

That means that you'll need to update your buffers dynamically. You should however split the problem a bit. Instancing and how to handle vegetation are two separate problems.

Instancing just enables you to draw multiple meshes with same / similar parameters in one draw call. How you update / organize your data is a different matter.

I'm copying my instance data every frame from main memory to a generic float4 buffer object. Typically this means something like 1-3 megabytes of data per frame depending on the amount of instances and data required by one instance. The data transfer isn't a bottleneck if implemented correctly. This kind of arrangement allows me to cull objects pretty well (foliage and such in bigger blocks) and have exactly one draw call per mesh.

Cheers!

note that if your vegetation doesn't change often, you can use static VB's and IB's. if it changes every frame or you recalculate every frame, then you'll want to go dynamic. so you can probably use static for vegetation, and dynamic for bullets. you'll have a VB and IB for your bullet or grass clump. then you'll have an instance buffer of world transforms for each instance you want to draw. the whole idea is to reduce the number of times you bind the instance buffer to a minimum. think of it this way: binding is bad. different binds have different costs: textures are highest (?). then VB's, then IB's, then constant buffers. apparently the hit for constant buffers isn't that bad. can't recall if binding dynamic vs static buffers is more costly (i think so). all this info is available in the docs.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

With the bullets, i mean this:

(Just an example)

Imagine thousands of spaceships, shooting lasers (or something) all the time, I would imagine that I would instance all bullets, wouldn't I? In that case I don't really see how I would split up each bullet up into a chunk, as they could go anywhere...

But Thanks!

You are dealing with the problem of what objects worth drawing, One solution is keeping a buffer large enough only to draw the bullets near the camera and dynamically insert / remove the elements. You can specify the number of instances inside the buffer.

This topic is closed to new replies.

Advertisement