1. 개발 현황
인스턴싱을 활용하여 효율적인 렌더링 환경 구축
DX12의 DrawIndexedInstanced 함수 내 StartInstanceLocation 활용에 오류가 있어, constant buffer를 활용하여 Start Location을 전달하는 방법으로 동작 구현
2. 상세 개발 내용
// Defaults for number of lights.
#ifndef NUM_DIR_LIGHTS
#define NUM_DIR_LIGHTS 3
#endif
#ifndef NUM_POINT_LIGHTS
#define NUM_POINT_LIGHTS 0
#endif
#ifndef NUM_SPOT_LIGHTS
#define NUM_SPOT_LIGHTS 0
#endif
#define MaxLights 16
#include "LightingUtil.hlsli"
struct InstanceData
{
float4x4 World;
float4x4 TexTransform;
float4x4 WorldInvTranspose; // Geometery Shader 동작 간 법선 벡터 변환 시 직교 성질 유지를 위함
uint MaterialIndex;
float2 DisplacementMapTexelSize;
float GridSpatialStep;
float bPerObjectPad1;
};
struct MaterialData
{
float4 DiffuseAlbedo;
float3 FresnelR0;
float Roughness;
float4x4 MatTransform;
uint DiffuseMapIndex;
uint MatPad0;
uint MatPad1;
uint MatPad2;
};
#ifdef TEX_SIZE
Texture2D gDiffuseMap[TEX_SIZE] : register(t0, space0);
#else
Texture2D gDiffuseMap[16] : register(t0, space0);
#endif
#ifdef TEX_ARRAY_SIZE
Texture2DArray gTreeMapArray[TEX_ARRAY_SIZE] : register(t0, space1);
#else
Texture2DArray gTreeMapArray[2] : register(t0, space1);
#endif
// Put in space1, so the texture array does not overlap with these resources.
// The texture array will occupy registers t0, t1, ..., t3 in space0.
StructuredBuffer<InstanceData> gInstanceData : register(t0, space2);
StructuredBuffer<MaterialData> gMaterialData : register(t1, space2);
Texture2D gDisplacementMap : register(t2, space2);
SamplerState gsamPointWrap : register(s0);
SamplerState gsamPointClamp : register(s1);
SamplerState gsamLinearWrap : register(s2);
SamplerState gsamLinearClamp : register(s3);
SamplerState gsamAnisotropicWrap : register(s4);
SamplerState gsamAnisotropicClamp : register(s5);
// Constant data that varies per material.
cbuffer cbPass : register(b0)
{
float4x4 gView;
float4x4 gInvView;
float4x4 gProj;
float4x4 gInvProj;
float4x4 gViewProj;
float4x4 gInvViewProj;
float3 gEyePosW;
float cbPerPassPad1;
float2 gRenderTargetSize;
float2 gInvRenderTargetSize;
float gNearZ;
float gFarZ;
float gTotalTime;
float gDeltaTime;
float4 gAmbientLight;
// Allow application to change fog parameters once per frame.
// For example, we may only use fog for certain times of day.
float4 gFogColor;
float gFogStart;
float gFogRange;
float2 cbPerObjectPad2;
// Indices [0, NUM_DIR_LIGHTS) are directional lights;
// indices [NUM_DIR_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHTS) are point lights;
// indices [NUM_DIR_LIGHTS+NUM_POINT_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHT+NUM_SPOT_LIGHTS)
// are spot lights for a maximum of MaxLights per object.
Light gLights[MaxLights];
};
cbuffer cbInstance : register(b1)
{
uint gBaseInstanceIndex;
}
void MyApp::BuildRootSignature()
{
// Create root CBVs.
D3D12_DESCRIPTOR_RANGE TexTable // register t0[16] (Space0)
{
/* D3D12_DESCRIPTOR_RANGE_TYPE RangeType */.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
/* UINT NumDescriptors */.NumDescriptors = (UINT)TEXTURE_FILENAMES.size() + SRV_USER_SIZE,
/* UINT BaseShaderRegister */.BaseShaderRegister = 0,
/* UINT RegisterSpace */.RegisterSpace = 0,
/* UINT OffsetInDescriptorsFromTableStart */.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
};
D3D12_DESCRIPTOR_RANGE TexArrayTable // register t0[0] (Space1)
{
/* D3D12_DESCRIPTOR_RANGE_TYPE RangeType */.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
/* UINT NumDescriptors */.NumDescriptors = (UINT)TEXTURE_ARRAY_FILENAMES.size(),
/* UINT BaseShaderRegister */.BaseShaderRegister = 0,
/* UINT RegisterSpace */.RegisterSpace = 1,
/* UINT OffsetInDescriptorsFromTableStart */.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
};
D3D12_DESCRIPTOR_RANGE DisplacementMapTable // register t2 (Space2)
{
/* D3D12_DESCRIPTOR_RANGE_TYPE RangeType */.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
/* UINT NumDescriptors */.NumDescriptors = 1,
/* UINT BaseShaderRegister */.BaseShaderRegister = 2,
/* UINT RegisterSpace */.RegisterSpace = 2,
/* UINT OffsetInDescriptorsFromTableStart */.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
};
// Root parameter can be a table, root descriptor or root constants.
CD3DX12_ROOT_PARAMETER slotRootParameter[7];
/*D3D12_SHADER_VISIBILITY
{
D3D12_SHADER_VISIBILITY_ALL = 0,
D3D12_SHADER_VISIBILITY_VERTEX = 1,
D3D12_SHADER_VISIBILITY_HULL = 2,
D3D12_SHADER_VISIBILITY_DOMAIN = 3,
D3D12_SHADER_VISIBILITY_GEOMETRY = 4,
D3D12_SHADER_VISIBILITY_PIXEL = 5,
D3D12_SHADER_VISIBILITY_AMPLIFICATION = 6,
D3D12_SHADER_VISIBILITY_MESH = 7
} D3D12_SHADER_VISIBILITY;*/
// Perfomance TIP: Order from most frequent to least frequent.
slotRootParameter[0].InitAsConstantBufferView(1); // register b1 (gBaseInstanceIndex)
slotRootParameter[1].InitAsShaderResourceView(0, 2); // InstanceData t0 (Space2)
slotRootParameter[2].InitAsShaderResourceView(1, 2); // MaterialData t1 (Space2)
slotRootParameter[3].InitAsConstantBufferView(0); // register b0
slotRootParameter[4].InitAsDescriptorTable(1, &TexTable, D3D12_SHADER_VISIBILITY_PIXEL);
slotRootParameter[5].InitAsDescriptorTable(1, &TexArrayTable, D3D12_SHADER_VISIBILITY_PIXEL);
slotRootParameter[6].InitAsDescriptorTable(1, &DisplacementMapTable, D3D12_SHADER_VISIBILITY_ALL);
auto staticSamplers = D3DUtil::GetStaticSamplers();
// A root signature is an array of root parameters.
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(7, slotRootParameter, (UINT)staticSamplers.size(), staticSamplers.data(), D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
// create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
Microsoft::WRL::ComPtr<ID3DBlob> serializedRootSig = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> errorBlob = nullptr;
HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
if (errorBlob != nullptr)
::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
ThrowIfFailed(hr);
ThrowIfFailed(mDevice->CreateRootSignature(0, serializedRootSig->GetBufferPointer(), serializedRootSig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.GetAddressOf())));
}
for (size_t i = 0; i < mAllRitems.size(); ++i)
{
auto& ri = mAllRitems[i];
if (!(ri->LayerFlag & (1 << (int)flag)))
continue;
if (flag == RenderLayer::Normal
|| flag == RenderLayer::NormalWireframe
|| flag == RenderLayer::TreeSprites
|| flag == RenderLayer::TreeSpritesWireframe)
ri->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
else if (flag == RenderLayer::Tessellation
|| flag == RenderLayer::TessellationWireframe)
ri->PrimitiveType = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
else
ri->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
D3D12_VERTEX_BUFFER_VIEW vbv = ri->Geo->VertexBufferView();
D3D12_INDEX_BUFFER_VIEW ibv = ri->Geo->IndexBufferView();
mCommandList->IASetVertexBuffers(0, 1, &vbv);
mCommandList->IASetIndexBuffer(&ibv);
mCommandList->IASetPrimitiveTopology(ri->PrimitiveType);
std::cout << ri->StartInstanceLocation << std::endl;
D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = currInstanceCB->GetGPUVirtualAddress() + i * objCBByteSize;
mCommandList->SetGraphicsRootConstantBufferView(0, objCBAddress);
mCommandList->DrawIndexedInstanced(ri->IndexCount, ri->InstanceCount, ri->StartIndexLocation, ri->BaseVertexLocation, ri->StartInstanceLocation);
// mCommandList->DrawIndexedInstanced(ri->IndexCount, ri->InstanceCount, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
}
3. TODO
컬링을 적용하여 더 효율적인 렌더링 환경 구축
4. 참고자료
https://www.gamedev.net/forums/topic/662594-startinstancelocation-and-sv-instanceid/
https://github.com/microsoft/DirectXShaderCompiler/issues/2946
[SPIR-V] SV_InstanceID behavior different than in DX12 · Issue #2946 · microsoft/DirectXShaderCompiler
When using SV_InstanceID, the SPIR-V codegen emits gl_InstanceIndex, which is not correct. The DX12 InstanceID always counts from 0, even if the StartInstanceLocation parameter is non-zero. gl_Inst...
github.com
728x90
반응형
'---------개인공부-------- > |DirectX (C++)|' 카테고리의 다른 글
[DirectX12] Geometry Shader 응용 (0) | 2025.01.25 |
---|---|
[DirectX12] Imgui Render Target 출력 (0) | 2025.01.22 |
[DirectX] Imgui Texture Image 출력 (0) | 2025.01.21 |
[DirectX] 3D 엔진 개발 현황 (0) | 2025.01.20 |