Monday, November 20, 2017

directx11 - How best to handle ID3D11InputLayout in rendering code?


I'm looking for an elegant way to handle input layouts in my directx11 code.


The problem I have that I have an Effect class and a Element class. The effect class encapsulates shaders and similar settings, and the Element class contains something that can be drawn (3d model, lanscape etc)


My drawing code sets the device shaders etc using the effect specified and then calls the draw function of the Element to draw the actual geometry contained in it.


The problem is this - I need to create an D3D11InputLayout somewhere. This really belongs in the Element class as it's no business of the rest of the system how that element chooses to represent it's vertex layout. But in order to create the object the API requires the vertex shader bytecode for the vertex shader that will be used to draw the object. In directx9 it was easy, there was no dependency so my element could contain it's own input layout structures and set them without the effect being involved.


But the Element shouldn't really have to know anything about the effect that it's being drawn with, that's just render settings, and the Element is there to provide geometry.



So I don't really know where to store and how to select the InputLayout for each draw call. I mean, I've made something work but it seems very ugly.


This makes me thing I've either missed something obvious, or else my design of having all the render settings in an Effect, the Geometry in an Element, and a 3rd party that draws it all is just flawed.


Just wondering how anyone else handles their input layouts in directx11 in a elegant way?



Answer



The way I handle this is that I have a VertexFormat.h file in which I have a bunch of input layouts of different types (VertexPositionNormal, VertexNormalUV...) wrapped in structs for easy creation/destruction. It works pretty well even though it's ugly IMO. It's very easy to add a new vertex format to the file if you have a shader that uses a layout that is not currently supported. Then I have a VertexFormatManager that creates/destroys those layouts when I need them. So when I need to create one, I feed the shader byte code and a vertexformat ID to the manager and it creates it for me and stores it in a pool so that you only ever have one of each layout. Then you need to create your geometry. To do this, I have a Create method on my geometry class that takes an ID for a vertex format. In the create function it queries the vertex format manager with the given ID. The manager returns an integer that serves as a bitfield with a flag set for every type of element the input layout contains. So I could have something like this:


int bitfield = VertexFormatManager::QueryFormat( formatID );
if (bitfield & VertexFormat::NORMAL)
{
// do somethings
}

if (bitfield & VertexFormat::UV)
{
// do somethings
}
...

Each input layout element is created into a separate ID3D11Buffer. That allows me to build a mesh given any type of vertex format. Say you want to render a cube with a texture, it needs vertex positions and uv coords. You feed it the VertexPositionUV (as an example) format ID, and the query return a bitfield contain set bits for the POSITION and UV flags. That create two ID3D11Buffers: one for the positions, one for the uv coords. Then you attach both of these to the pipeline before drawing. The advantage of doing this is that if you want to do something like shadow maps, you can render a mesh with only its vertex position buffer set.


I'm not sure much of this is very clear, I'm at work and I'll try and do a proper write up later tonight. In the mean time, I asked this question a while ago and got this answer . It's good, but I find that the way I'm doing it now makes more sense, especially in the case of DX11.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...