Advertisement
Guest User

Untitled

a guest
Mar 12th, 2012
434
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.70 KB | None | 0 0
  1. 1- We defined a vertex format that represents a vertex that has position, normal and texture information. This struct layout is the same for each different vertex format. So adding new ones is simple. The only thing that changes is the m_inputLayout member and the m_formatID (this ID is unique).
  2.  
  3. Header file:
  4. struct VertexPositionNormalUV
  5. {
  6.     ...
  7.     static HRESULT          create( ID3D11Device *device, ID3DBlob *shaderBytecode );
  8.     static void         destroy();
  9.     static ID3D11InputLayout    *getInputLayout();
  10.  
  11.     static D3D11_INPUT_ELEMENT_DESC const *getLayoutDesc();
  12.     static UINT getNumInputElements();
  13.     static UINT getFormatID();
  14.  
  15.     // since we only need one of each format, we make is static. There is no need to create the same    //vertex multiple time even if it's being used in different places, rendering passes or anything else.
  16.     static D3D11_INPUT_ELEMENT_DESC m_layout[];
  17.     static UINT         m_nElements;
  18.     static ID3D11InputLayout    *m_inputLayout;
  19.     static UINT         m_formatID;
  20. };
  21.  
  22. Source file:
  23. ID3D11InputLayout *VertexPositionNormalUV::m_inputLayout = 0;
  24. UINT VertexPositionNormalUV::m_nElements = 3;
  25.  
  26. // since each buffer with use a different vertex buffer slot, we need to specify them here when creating the input layout
  27. // this step is different, depending on the type of vertex.
  28. D3D11_INPUT_ELEMENT_DESC VertexPositionNormalUV::m_layout[] =
  29. {
  30.     {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
  31.     {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
  32.     {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 2, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
  33. };
  34.  
  35.  
  36. 2- In order to create the vertex, I go through a "manager" that keeps track of the formats I've create. If I call the create method for a format that has previously been created, it does nothing. Notice the "vertexFormatID" parameter. This is the one that was defined in the struct in step 1. The manager uses this ID to know which vertex format to build, and call the "create" method from the struct in step 1.
  37. Obviously the shader bytecode needs to match the vertex format, you can't work around that.
  38. createVertexFormat( ID3D11Device *device, ID3DBlob *byteCodeInputSignature, UINT vertexFormatID );
  39.  
  40.  
  41. 3- In this step, you can start creating the actual mesh that will be rendered. All meshes could derive a base class in order to have the same public interface. As an example, here is what a cube mesh creation could look like:
  42. HRESULT Cube::create( ID3D11Device *device, UINT vertexFormatID )
  43. {
  44.     // again, the vertexFormatID here is the same as in step 1. The manager uses it internally for the queries.
  45.     // query the number of elements the input layout the vertex has. This is also the number of buffers the mesh will have.
  46.     UINT nElements = VertexFormatManager::getNumInputElements(vertexFormatID);
  47.  
  48.     // query the elements from the input layout belonging to vertex format identified by the vertexFormatID
  49.     D3D11_INPUT_ELEMENT_DESC const *desc = VertexFormatManager::getInputElementDesc(vertexFormatID);
  50.  
  51.     for each (element in desc)
  52.     {
  53.         if (element & VERTEX_POSITION)
  54.         {
  55.             // create positions buffer
  56.         }
  57.         else if (element & VERTEX_UV)
  58.         {
  59.             // create uv coords buffer
  60.         }
  61.         ...
  62.     }
  63. }
  64.  
  65. At this point you end up with same number of buffers as elements in the input layout you are using. In this case it would be 3 buffers: one containing the positions of the vertices, one for the normals and one for the uv coords.
  66.  
  67. 4- To render the mesh you need set the bind the buffers to the pipeline. The m_buffers member knows how many buffers we have from the create function.
  68. context->IASetVertexBuffers(0, numBuffers, m_buffers, m_strides, m_offsets);
  69.  
  70. The whole thing may seem a little overkill but it's pretty flexible, and enables you to render any shape of mesh with any given shader without having to hard code the vertex format inside the mesh class. Most of this code would takes place at initialization time so it shouldn't be a performance bottleneck. On top of that, it's now also possible to select what buffers you want to bind to the pipeline before drawing.
  71. As an example, when rendering shadow maps, you only need the positions of the vertices. You don't need to render the texture of the mesh or anything like that. So you could easily have a method that would let you choose what buffers you are using.
  72.  
  73. void    Cube::setBufferFlags( UINT flags )
  74. {
  75.     if (flags & VERTEX_POSITION)
  76.         // use position buffer
  77.     if (flags & VERTEX_NORMAL)
  78.         // use normals buffer
  79.     ...
  80. }
  81.  
  82. This function would modify the array of buffers you pass to the IASetVertexBuffers function. That way, in the shadow maps example, you would only be sending vertex position information to the GPU as no other info is needed when rendering a mesh to a shadow map.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement