4.14 How to render multiple textured rectangles in Direct3D12?
We have updated the following two classes:
1. Direct3DX12TexturedRectange
to create a Direct3DX12Rectangle specified by D3D12Rectangle structure .
2. Direct3D12RootSignature
to create an ID3D12RootSignature with the specified number of descriptors of ConstantantBufferViews and
ShaderResourceViews .
Direct3D12Object
Direct3DX12Shape
Direct3DX12TexturedRectangle
Direct3D12DeviceChild
Direct3D12RootSignature
The following Direct3D12MultiPNGTexturedRectangles is a simple sample program to render
four PNG textured rectangles which can be rotated by the left and right keys.
/*
* Direct3D12MultiPNGTexturedRectangles.cpp
* Copyright (c) 2016 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*/
// 2016/12/15
// This is a simple example to render multiple textured rectangles
//with multiple shaderResourceViews.
#define COMMONCONTROLS_V6
#define WIN10
#include <sol/COMInitializer.h>
#include <sol/WCharModuleFileName.h>
#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/Direct3D12TransformConstantBufferView.h>
#include <sol/direct3d12/Direct3D12TextureRootSignature.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>
#include <sol/direct3d12/Direct3D12Fence.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/D3D12Transform.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>
#include <sol/direct3d12/Direct3D12Synchronizer.h>
#include <sol/direct3d12/Direct3D12Texture2D.h>
#include <sol/direct3d12/Direct3DX12TexturedRectangle.h>
#include <sol/direct3d12/Direct3D12ShaderResourceView.h>
#include <sol/direct3d12/Direct3D12Sampler.h>
#include <sol/direct3d12/Direct3DX12ColoredRectangle.h>
#include <sol/direct3d12/DirectXTransform.h>
#include <sol/direct3d12/Direct3D12Subresources.h>
#include <sol/wic/WICBitmapFileReader.h>
#include <sol/direct3d12/D3D12SubresourceData.h>
#include <sol/direct3d12/D3D12Rectangle.h>
#include "resource.h"
namespace SOL {
class MainView :public DirectX3D12MainView {
private:
static const UINT NUMBER_OF_CONSTANT_BUFFER_VIEW = 1;
static const UINT NUMBER_OF_SHADER_RESOURCE_VIEW = 4; //The number of rectangles;
//Inner class starts.
class SimpleView :public DirectX3D12View {
private:
SmartPtr<Direct3D12CommandAllocator> commandAllocator;
SmartPtr<Direct3D12RenderTargetView> renderTargetView;
SmartPtr<Direct3D12DepthStencilView> depthStencilView;
SmartPtr<Direct3D12RootSignature> rootSignature;
SmartPtr<Direct3D12CommonDescriptorHeap> commonDescriptorHeap;
SmartPtr<Direct3D12TransformConstantBufferView> constantBufferView;
SmartPtr<Direct3D12ShaderResourceView> shaderResourceView[NUMBER_OF_SHADER_RESOURCE_VIEW];
SmartPtr<Direct3D12GraphicsCommandList> graphicsCommandList;
SmartPtr<Direct3D12PipelineState> pipelineState;
SmartPtr<Direct3D12Synchronizer> synchronizer;
SmartPtr<Direct3DX12TexturedRectangle> texturedRectangle[NUMBER_OF_SHADER_RESOURCE_VIEW];
SmartPtr<Direct3D12Subresources> subresources[NUMBER_OF_SHADER_RESOURCE_VIEW];
SmartPtr<Direct3D12Texture2D> texture2D[NUMBER_OF_SHADER_RESOURCE_VIEW];
UINT frameIndex;
DirectXTransform worldViewProjection;
float angle;
StringT<TCHAR> directory;
private:
virtual void createPipelineState(ID3D12Device* device)
{
//Create a graphicPipelineStateDes.
D3D12GraphicsPipelineStateDesc graphicsPipelineStateDesc(*rootSignature);
UINT count = 0;
const D3D12_INPUT_ELEMENT_DESC* inputElements = texturedRectangle[0]->getInputElementDesc(count);
D3D12RasterizerDesc rasterDesc(
D3D12_FILL_MODE_SOLID,
D3D12_CULL_MODE_NONE,
false);
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 setDirectXTransform()
{
int width = 0;
int height = 0;
getClientSize(width, height);
try {
XMVECTOR eye = XMVectorSet( 0.0f, 0.0f, -4.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 );
worldViewProjection.world = DirectXMatrix::rotationY( angle );
worldViewProjection.view = DirectXMatrix::lookAtLH(eye, at, up);
worldViewProjection.projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.4f, width / (FLOAT)height, 0.01f, 100.0f );
if (constantBufferView != nullptr) {
constantBufferView->update(worldViewProjection);
}
} 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()
{
if (graphicsCommandList == nullptr) {
throw IException("graphicsCommandList is NULL.")
}
graphicsCommandList->setOMRenderTargets(0, nullptr, FALSE, nullptr);
renderTargetView = NULL;
depthStencilView = NULL;
}
void readImageFile(int width, int height, D3D12SubresourceData& subresource,
const wchar_t* filename)
{
WCharModuleFileName moduleFileName;
const wchar_t* dir = moduleFileName.getDir();
wchar_t path[MAX_PATH];
swprintf_s(path, CountOf(path), L"%s\\..\\image\\%s", dir, filename);
WICImagingFactory factory;
WICBitmapFileReader reader(factory, (const wchar_t*)path);
reader.read(width, height, subresource);
}
public:
virtual void initialize()
{
int width = 0;
int height = 0;
validateClientSize(width, height);
Direct3D12Device* device = getD3D12Device();
DirectXGISwapChain3* swapChain = getSwapChain3();
Direct3D12CommandQueue* commandQueue = getCommandQueue();
try {
commandAllocator = new Direct3D12CommandAllocator(*device);
graphicsCommandList = new Direct3D12GraphicsCommandList(*device, *commandAllocator);
//Create a rootSignature specified by the arguments
// 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);
synchronizer = new Direct3D12Synchronizer(*device, *commandQueue);
createViews(*device, *swapChain, width, height);
//Create a commonDescriptorHeap of the size of
// NUMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW.
commonDescriptorHeap = new Direct3D12CommonDescriptorHeap(*device,
NUMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW);
constantBufferView = new Direct3D12TransformConstantBufferView(*device,
commonDescriptorHeap->getCPUHandle(CBV_HANDLE));
const wchar_t* filenames[NUMBER_OF_SHADER_RESOURCE_VIEW] = {
L"flower1.png",
L"flower2.png",
L"flower3.png",
L"flower4.png",
};
const D3D12Rectangle rectangles[NUMBER_OF_SHADER_RESOURCE_VIEW] = {
{-0.8f, 0.7f, -0.8f, 0.6f, 0.4f},
{ 0.8f, 0.7f, -0.8f, 0.6f, 0.4f},
{ 0.8f, -0.7f, 0.8f, 0.6f, 0.4f},
{-0.8f, -0.7f, 0.8f, 0.6f, 0.4f},
};
for (size_t i = 0; i < NUMBER_OF_SHADER_RESOURCE_VIEW; i++) {
texturedRectangle[i] = new Direct3DX12TexturedRectangle(*device, rectangles[i]);
D3D12SubresourceData imageResource;
readImageFile((UINT&)width, (UINT&)height, imageResource, filenames[i]);
texture2D[i] = new Direct3D12Texture2D(*device, width, height);
subresources[i] = new Direct3D12Subresources(*device, *texture2D[i]);
subresources[i] -> update(*graphicsCommandList,
*commandAllocator,
*commandQueue,
imageResource,
synchronizer);
shaderResourceView[i] = new Direct3D12ShaderResourceView(*device,
commonDescriptorHeap->getCPUHandle(SRV_HANDLE + i),
*texture2D[i]);
}
createPipelineState(*device);
setDirectXTransform();
} 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 ||
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;
}
try {
Direct3D12Device* device = getD3D12Device();
DirectXGISwapChain3* swapChain = getSwapChain3();
Direct3D12CommandQueue* commandQueue = getCommandQueue();
worldViewProjection.world = DirectXMatrix::rotationY( angle );
constantBufferView->update(worldViewProjection);
commandAllocator -> reset();
graphicsCommandList->reset(*commandAllocator, nullptr);
frameIndex = swapChain -> getCurrentBackBufferIndex();
D3D12ResourceBarrier barrier(renderTargetView->getResource(frameIndex));
barrier.startRendering();
graphicsCommandList->resourceBarrier(1, barrier);
graphicsCommandList->setDescriptorHeap(*commonDescriptorHeap);
graphicsCommandList->setGraphicsRootSignature(*rootSignature);
graphicsCommandList->setPipelineState(*pipelineState);
graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE,
commonDescriptorHeap->getGPUHandle(CBV_HANDLE)); //ConstantBufferView
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, D3D12_CLEAR_FLAG_DEPTH);
graphicsCommandList->setOMRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
for (size_t i = 0; i<NUMBER_OF_SHADER_RESOURCE_VIEW; i++) {
graphicsCommandList->setGraphicsRootDescriptorTable(SRV_HANDLE,
commonDescriptorHeap->getGPUHandle(SRV_HANDLE + i));
texturedRectangle[i] -> drawIndexedInstanced(graphicsCommandList);
}
barrier.endRendering();
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);
}
}
void render()
{
angle += 0.02f;
display();
}
void incrementAngle()
{
angle += 0.1f;
display();
}
void decrementAngle()
{
angle -= 0.1f;
display();
}
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);
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);
}
}
virtual void keyDown(Event& event)
{
WPARAM wparam = event.getWParam();
switch(wparam) {
case VK_LEFT:
view -> decrementAngle();
break;
case VK_RIGHT:
view -> incrementAngle();
break;
}
}
};
}
//////////////////////////////////////////////
//
void Main(int argc, TCHAR** argv)
{
TCHAR directory[MAX_PATH];
appDirectory(argv[0], directory, CountOf(directory));
const TCHAR* appClass = appName(argv[0]);
try {
//For DXGI components.
COMInitializer initializer( COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
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.