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.