4.15 How to use multiple ConstantBufferViews to render translated shapes in Direct3D12?

In this example we create one instance of Direct3D12RootSignature having the number of descriptors for ConstantBufferViews, and four instances of Direct3D12ConstantBufferView corresponding to the four shapes(Box, Sphere, Torus, Cylinder) in the following way.
  // Create a rootSignature specified by the parameters:
  //    NUMBER_OF_CONSTANT_BUFFER_VIEW and NUMBER_OF_SHADER_RESOURCE_VIEW
  rootSignature            = new Direct3D12RootSignature(*device,
                                      NUMBER_OF_CONSTANT_BUFFER_VIEW,
                                      NUMBER_OF_SHADER_RESOURCE_VIEW);

  // Create a commonDescriptorHeap of size of
  //    UMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW
  commonDescriptorHeap     = new Direct3D12CommonDescriptorHeap(*device, 
                            NUMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW);

  // Create NUMBER_OF_CONSTANT_BUFFER_VIEW constantBufferViews. 
  for (UINT i = 0; i < NUMBER_OF_CONSTANT_BUFFER_VIEW; i++) {
    constantBufferView[i]  = new Direct3D12TransformLightConstantBufferView(*device,
                                                  commonDescriptorHeap->getCPUHandle(CBV_HANDLE + i));
  }

Direct3D12Object
Direct3D12DeviceChild
Direct3D12Pageable
Direct3D12DescriptorHeap
Direct3D12View
Direct3D12ConstantBufferView
Direct3D12RootSignature
 
The following Direct3D12LightedShapesWithMultipleConstantBufferViews is a simple sample program to render four colored and lighted shapes(Box, Sphere, Torus, Cylinder) in the translated positions on WorldViewProjection. Although this is certainly an elementary sample to use multiple ConstantBufferViews, this may be helpful when you would like to place the shapes in your preferred positions in Direct3D12.



/*
 * Direct3D12LightedShapesWithMultipleConstantBufferViews.cpp 
 * Copyright (c) 2016 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */

// 2016/12/15

#define COMMONCONTROLS_V6
#define WIN10

#include <sol/direct3d12/DirectX3D12MainView.h>
#include <sol/direct3d12/DirectX3D12View.h>
#include <sol/direct3d12/DirectXMatrix.h>
#include <sol/direct3d12/Direct3D12CommandAllocator.h>
#include <sol/direct3d12/Direct3D12RenderTargetView.h>
#include <sol/direct3d12/Direct3D12DepthStencilView.h>
#include <sol/direct3d12/Direct3D12CommonDescriptorHeap.h>
#include <sol/direct3d12/Direct3D12TransformLightConstantBufferView.h>
#include <sol/direct3d12/Direct3D12RootSignature.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>
#include <sol/direct3d12/Direct3D12PipelineState.h>
#include <sol/direct3d12/D3D12RasterizerDesc.h>
#include <sol/direct3d12/D3D12BlendDesc.h>
#include <sol/direct3d12/D3D12GraphicsPipelineStateDesc.h>
#include <sol/direct3d12/D3D12ResourceBarrier.h>
#include <sol/direct3d12/D3D12TransformLight.h>
#include <sol/direct3d12/Direct3D12Synchronizer.h>

#include <sol/direct3d12/Direct3DX12Box.h>
#include <sol/direct3d12/Direct3DX12Cylinder.h>
#include <sol/direct3d12/Direct3DX12Sphere.h>
#include <sol/direct3d12/Direct3DX12Torus.h>

#include <sol/direct3d12/DirectXTransformLight.h>

#include "resource.h"

namespace SOL {
  
class MainView :public DirectX3D12MainView {      
private:
  static const UINT  NUMBER_OF_CONSTANT_BUFFER_VIEW = 4; //The number of shapes.
  static const UINT  NUMBER_OF_SHADER_RESOURCE_VIEW = 1; //Unused;

  static const int                SHAPES = 4;  //Sphere, Torus, Cylinder and Cube.

  /////////////////////////////////////////////////////////////////
  //Inner class 
  class SimpleView :public DirectX3D12View {
  private:
    
    SmartPtr<Direct3D12CommandAllocator>     commandAllocator;
    SmartPtr<Direct3D12RenderTargetView>     renderTargetView;
    SmartPtr<Direct3D12DepthStencilView>     depthStencilView;
    SmartPtr<Direct3D12RootSignature>        rootSignature;
    SmartPtr<Direct3D12CommonDescriptorHeap> commonDescriptorHeap;
    SmartPtr<Direct3D12GraphicsCommandList>  graphicsCommandList;
    SmartPtr<Direct3D12PipelineState>        pipelineState;
    SmartPtr<Direct3D12Synchronizer>         synchronizer;
    SmartPtr<Direct3DX12Shape>               shapes[SHAPES];
    SmartPtr<Direct3D12TransformLightConstantBufferView>   constantBufferView[SHAPES];
      
    UINT                           frameIndex;
    DirectXTransformLight          lightedConstantBuffer;
    float                          angle;
    StringT<TCHAR>                 directory;

  private:
        
    virtual void createPipelineState(ID3D12Device* device)
    {
      //Create a graphicPipelineStateDes.
      D3D12GraphicsPipelineStateDesc graphicsPipelineStateDesc(*rootSignature);

      UINT count = 0;
      static const D3D12_INPUT_ELEMENT_DESC* inputElements = D3D12InputElements::getPosNormalDesc(count); 
          
      D3D12RasterizerDesc  rasterDesc(
        D3D12_FILL_MODE_SOLID, 
        D3D12_CULL_MODE_NONE, 
        true);

      D3D12BlendDesc       blendDesc;
            
      graphicsPipelineStateDesc.setInputLayput(inputElements, count);
      
      graphicsPipelineStateDesc.setRasterizerState(rasterDesc);
      graphicsPipelineStateDesc.setBlendState(blendDesc);
      
      StringT<TCHAR> vsshaderFile = getShaderFilePath(directory, _T("VertexShader.cso"));
      StringT<TCHAR> psshaderFile = getShaderFilePath(directory, _T("PixelShader.cso"));

      graphicsPipelineStateDesc.setVertexShader(vsshaderFile);
      graphicsPipelineStateDesc.setPixelShader(psshaderFile);

      pipelineState = new Direct3D12PipelineState(device, graphicsPipelineStateDesc);
    }
    
    void setDirectXTransformLight(int i) //i: shape index
    {
      int width = 0;
      int height = 0;
      getClientSize(width, height);

      try {         
        XMFLOAT3 pos[SHAPES] = {
            XMFLOAT3(-1.5f,  1.5f,   1.0f),
            XMFLOAT3( 1.5f,  1.5f,   1.0f),
            XMFLOAT3(-1.5f, -1.5f,   0.0f),
            XMFLOAT3( 1.5f, -1.5f,  -1.0f)  
        };
        DirectXMatrix world =  DirectXMatrix::rotationY( angle );
        DirectXMatrix m = DirectXMatrix::translation(pos[i].x, pos[i].y, pos[i].z);
        world += m;
                      
        XMVECTOR eye = XMVectorSet(  0.0f,  2.0f, -8.0f,  0.0f );
        XMVECTOR at  = XMVectorSet(  0.0f,  0.0f,  0.0f,  0.0f );
        XMVECTOR up  = XMVectorSet(  0.0f,  1.0f,  0.0f,  0.0f );

        lightedConstantBuffer.world      = world;

        lightedConstantBuffer.view       = DirectXMatrix::lookAtLH(eye, at, up);
        lightedConstantBuffer.projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.3f, 
             width / (FLOAT)height, 0.01f, 100.0f );
        lightedConstantBuffer.lightDirection = XMFLOAT4( -0.8f, 0.8f, 0.3f, 1.0f );
        XMFLOAT4 colors[SHAPES] = {
          XMFLOAT4(  0.0f, 0.0f, 1.0f, 1.0f ),
          XMFLOAT4(  1.0f, 0.0f, 0.0f, 1.0f ),
          XMFLOAT4(  0.0f, 1.0f, 0.0f, 1.0f ),
          XMFLOAT4(  0.4f, 0.4f, 0.4f, 1.0f )
        };
        lightedConstantBuffer.lightColor     = colors[i]; //XMFLOAT4(  0.0f, 0.8f, 0.0f, 1.0f );
        
         constantBufferView[i] ->update(lightedConstantBuffer);

      } catch (Exception& ex) {
        caught(ex);      
      }
    }
    
    //Create a renderTargetView and a depthStencilView.
    void createViews(ID3D12Device* device, IDXGISwapChain3* swapChain,
                  int width, int height)
    {
      renderTargetView = new Direct3D12RenderTargetView(device, swapChain);
      depthStencilView = new Direct3D12DepthStencilView(device,  width, height);
    }
    
    //Delete a renderTargetView and a depthStencilView.
    void deleteViews()
    {
      graphicsCommandList->setOMRenderTargets(0, nullptr, FALSE, nullptr);
    
      renderTargetView = NULL;
      depthStencilView = NULL;
    }
   
    void createShapes(ID3D12Device* device)
    {
      try {
        int i = 0;
        //1 Create a box.
        {
          float fWidth   = 0.8f; 
          float fHeight  = 0.8f; 
          float fDepth   = 0.8f;
          shapes[i++] = new Direct3DX12Box(device,
              fWidth, fHeight, fDepth);
        }
        
        //2 Create a torus.
        {
          float fInnerRadius = 0.2f;
          float fOuterRadius = 0.6f;
          UINT uSides  = 30;
          UINT uRings  = 30; 
          shapes[i++] = new Direct3DX12Torus(device,
                    fInnerRadius, fOuterRadius, uSides,
                                uRings);
        }
        
        //3 Create a sphere.
        {
          float fRadius = 0.6f;
          UINT  uSlices = 20;
          UINT  uStacks = 20;      
          shapes[i++] = new Direct3DX12Sphere(device,
            fRadius, uSlices, uStacks);
        }
 
        //4 Create a cylinder.
        {
          float fRadius1  = 0.3f;
          float fRadius2  = 0.5f;
          float fLength   = 1.0f; 
          UINT uSlices    = 20;
          UINT uStacks    = 20;
          shapes[i] = new Direct3DX12Cylinder(device,
            fRadius1, fRadius2, fLength, uSlices, uStacks);
        }
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
  public:
    virtual void initialize()
    {
      int width  = 0;
      int height = 0;
      validateClientSize(width, height);
      Direct3D12Device*       device    = getD3D12Device();
      DirectXGISwapChain3*    swapChain = getSwapChain3();
      Direct3D12CommandQueue* commandQueue = getCommandQueue();
      
      try {
        //1 Create a commandAllocator.
        commandAllocator         = new Direct3D12CommandAllocator(*device);

        //2 Creaate a commadList.
        graphicsCommandList      = new Direct3D12GraphicsCommandList(*device, *commandAllocator);

        //3 Create a rootSignature specified by the parameters:
        //    NUMBER_OF_CONSTANT_BUFFER_VIEW and NUMBER_OF_SHADER_RESOURCE_VIEW
        rootSignature            = new Direct3D12RootSignature(*device,
                                      NUMBER_OF_CONSTANT_BUFFER_VIEW,
                                      NUMBER_OF_SHADER_RESOURCE_VIEW);

        //4 Create a commonDescriptorHeap of size of
        //    UMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW
        commonDescriptorHeap     = new Direct3D12CommonDescriptorHeap(*device, 
                            NUMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW);

        //5 Create NUMBER_OF_CONSTANT_BUFFER_VIEW constantBufferViews. 
        for (UINT i = 0; i < NUMBER_OF_CONSTANT_BUFFER_VIEW; i++) {
          constantBufferView[i]  = new Direct3D12TransformLightConstantBufferView(*device,
                                                  commonDescriptorHeap->getCPUHandle(CBV_HANDLE + i));
        }
        //6 Create a synchronizer.
        synchronizer             = new Direct3D12Synchronizer(*device, *commandQueue);

        //7 Create views.
        createViews(*device, *swapChain, width, height);
        
        //8 Create shapes
        createShapes(*device);
        
        //9 Create a pipelineState.
        createPipelineState(*device);
        
      } catch (Exception& ex) {
        caught(ex);
      }
    }

    bool ready()
    {
      Direct3D12Device*    device = getD3D12Device();
      DirectXGISwapChain3* swapChain = getSwapChain3();
      Direct3D12CommandQueue* commandQueue = getCommandQueue();
      
      if (
        device                    == nullptr ||
        commandQueue              == nullptr ||

        swapChain                 == nullptr ||
        commandAllocator          == nullptr ||
        renderTargetView          == nullptr ||
        depthStencilView          == nullptr ||

        rootSignature             == nullptr ||
        commonDescriptorHeap      == nullptr ||
        constantBufferView        == nullptr ||
        graphicsCommandList       == nullptr ||
        pipelineState             == nullptr ||
        synchronizer              == nullptr ) {

        return false;
      }
      return true;
    }
    
    virtual void display()
    {
      int width  = 0;
      int height = 0;
      validateClientSize(width, height);
      if ( !ready() ) {
        return;
      }     
      Direct3D12Device*       device       = getD3D12Device();
      DirectXGISwapChain3*    swapChain    = getSwapChain3();
      Direct3D12CommandQueue* commandQueue = getCommandQueue();

      try {
        commandAllocator->reset();

        graphicsCommandList->reset(*commandAllocator, nullptr);

        frameIndex = swapChain->getCurrentBackBufferIndex();

        D3D12ResourceBarrier barrier(renderTargetView->getResource(frameIndex));

        barrier.startTransition();

        graphicsCommandList->resourceBarrier(1, barrier);

        graphicsCommandList->setGraphicsRootSignature(*rootSignature);
 
        graphicsCommandList->setDescriptorHeap(*commonDescriptorHeap);

        graphicsCommandList->setPipelineState(*pipelineState);
        
        graphicsCommandList->setRSViewport(width, height);

        graphicsCommandList->setRSScissorRect(width, height);

        D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = renderTargetView->getHandle(frameIndex);

        graphicsCommandList->clearRenderTargetView(rtvHandle, XMColor(0.0f, 0.0f, 0.0f, 1.0f));

        D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = *depthStencilView;

        graphicsCommandList->clearDepthStencilView(dsvHandle);

        graphicsCommandList->setOMRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);

        for (int i = 0; i<SHAPES; i++) {
          //Update transformation matrix and light variables for each shape 
          setDirectXTransformLight(i); 
          //Set each constantBufferView adddres for each shape to the commandList.
          graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE,
              commonDescriptorHeap->getGPUHandle(CBV_HANDLE + i));
          //Draw each shape.
          shapes[i]->drawIndexedInstanced(graphicsCommandList);
        }
        
        barrier.endTransition();

        graphicsCommandList->resourceBarrier(1, barrier);

        graphicsCommandList->close();

        commandQueue->executeCommandList( *graphicsCommandList);
        
        swapChain->present(1, 0);
        
        synchronizer->waitForCompletion();

      } catch (Exception& ex) {
        caught(ex);
      }
    }
        
    virtual void resize(int width, int height)
    {
      Direct3D12Device*   device = getD3D12Device();
      DirectXGISwapChain3* swapChain = getSwapChain3();
      if (device           == NULL || 
         swapChain        == NULL) { 
        return ;
      }        
      try {
        deleteViews();
        
        swapChain->resizeBuffers(width, height);

        createViews(*device, *swapChain, width, height);
        
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
  public:
    //Constructor
    SimpleView(DirectX3D12MainView* parent, const TCHAR* name, Args& args)
    :DirectX3D12View(parent, name, args),
    angle (0.6f),
    frameIndex(0),
    directory(_T(""))
    {
      directory = (const TCHAR*)args.get(XmNapplicationDirectory);
      postResizeRequest();
    }
    
    ~SimpleView()
    {
    }
  };
  // Inner class ends.
  
private:
  SmartPtr<SimpleView> view;

public:
  /**
   * Constructor
   */
  MainView(Application& applet, const TCHAR* name, Args& args)
  :DirectX3D12MainView(applet, name,
                 args.set(XmNstyle, (ulong)WS_CLIPCHILDREN|WS_CLIPSIBLINGS) ),
  view(NULL)
  {
    const TCHAR* directory = (const TCHAR*)args.get(XmNapplicationDirectory);
    // 1 Restore the replacement of MainView 
    restorePlacement();

    // 2 Create a view of SimpleView.
    Args ar;
    int width  = 0;
    int height = 0;
    getClientSize(width, height);

    ar.set(XmNwidth, width);
    ar.set(XmNheight,height);
    ar.set(XmNapplicationDirectory, (const TCHAR*)directory);

    ar.set(XmNstyle, WS_BORDER|WS_CHILD|WS_VISIBLE);
    view = new SimpleView(this, _T(""), ar);

    // 3 Post a resize request to this MainView.
    postResizeRequest();
  }

public:
  ~MainView()
  {
  }

  void resize(int width, int height)
  {
    if (view != nullptr) {
      view -> reshape(0, 0, width, height);      
    }
  } 
};
}


//////////////////////////////////////////////
//
void  Main(int argc, TCHAR** argv)
{
  TCHAR directory[MAX_PATH];
  appDirectory(argv[0], directory, CountOf(directory));

  const TCHAR* appClass = appName(argv[0]); 
  try {    
    Application applet(appClass, argc, argv);

    Args args;
    args.set(XmNwidth,  480);
    args.set(XmNheight, 480);
    args.set(XmNapplicationDirectory, directory);

    MainView mainView(applet, appClass, args);
    mainView.realize();

    applet.run();
  } catch (Exception& ex) {
    caught(ex);
  }
}

Last modified: 14 Dec 2016

Copyright (c) 2016 Antillia.com ALL RIGHTS RESERVED.