Windows 10+ ยท Direct3D 12 (FL 11.0+) ยท C++17 ยท Visual Studio + Win10 SDK
ํ๊ตญ์ด | English
Data-Oriented Design์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌํํ DirectX 12 ์ปค์คํ ๋ ๋๋ง ์์ง์ด๋ค. Scene/Component ๋ฐ์ดํฐ๋ฅผ ๋ ๋๋ง ์ ์ฉ Frame Snapshot๊ณผ Draw Item Cache๋ก ๋ณํํ๊ณ , Renderer๋ ์๋ณธ Scene์ด ์๋ ์บ์๋ ๋ถ๋ณ(immutable) ํ๋ ์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Forward / Deferred path๋ฅผ ์คํํ๋ค. Transform์ SoA ๊ตฌ์กฐ์ dirty index๋ก ๊ฐฑ์ ๋น์ฉ์ ์ค์์ผ๋ฉฐ, RenderObject ๋ณ๊ฒฝ์ Draw Item Cache์ ๋ฐ์ํ๋ค.
์นด๋ฉ๋ผ๋ณ Frustum Culling์ผ๋ก visible draw item์ ๊ตฌ์ฑํ๊ณ , Deferred path๋ Shadow, Depth Pre-Pass, G-Buffer, SSAO, Lighting, Forward Overlay Pass๋ก ๋ถ๋ฆฌํ๋ค. DirectX 12 ๋ฆฌ์์ค, descriptor, command queue, render target, root signature๋ ์์ฒด ๋ ๋๋ง API๋ก ๋ํํ์ผ๋ฉฐ, shader reflection๊ณผ RenderDB๋ฅผ ํตํด material, mesh, transform, light ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๋ค.
โฃ Authoring ยท mutable
JScene
ยท Entity / Component pools
ยท dirty transform / camera / light
โ events
โผ
โฃ Render Frontend ยท CPU
JRenderServer::SyncScene
(consume events ยท update draw item cache ยท build snapshot)
โ
โโโโถ JRenderSnapshotBuilder (์นด๋ฉ๋ผ viewยทprojection, dirty transform โ world, light snapshot)
โโโโถ JCameraRenderQueueBuilder (frustum 6-plane cull, visible opaque / transparent ์ธ๋ฑ์ค)
โ
โผ
โโ JFrameDesc (immutable) โโ
โ
โผ
โฃ Render Backend ยท GPU
JRenderDB material / mesh / camera / transform / light GPU mirror
โ
โผ
JRenderer::Render(JFrameDesc)
ยท Forward : SceneColorPass
ยท Deferred : Shadow โ Depth โ GBuffer โ SSAO โ Lighting โ ForwardOverlay
๋ ๋๋ง ๋ฐ์ดํฐ ํ๋ฆ์ JScene โ Snapshot โ RenderDB โ Renderer ์ ๋จ์ผ ๋ฐฉํฅ ๊ตฌ์กฐ๋ก ์ค๊ณํ๋ค. Scene์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์๋ณธ ์ํ๋ง ๊ด๋ฆฌํ๊ณ , Renderer๋ ํ๋ ์๋ง๋ค ํ์ ๋ JFrameDesc ์ RenderDB ๋ง ์ฐธ์กฐํ๋๋ก ๋ถ๋ฆฌํ๋ค.
์ด๋ ๊ฒ ๋ถ๋ฆฌํ๋ฉด Scene ๋ณ๊ฒฝ ์ถ์ ์ด ๋จ์ํด์ง๊ณ , ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ง ๊ฐฑ์ ํ ์ ์๋ค. ๋ํ RenderPass๊ฐ ๊ฐ๋ณํ๋ Scene์ ์ง์ ์์กดํ์ง ์์ ๋๋ฒ๊น ๊ฒฝ๊ณ๊ฐ ๋ช ํํ๊ณ , Sorting Queue ์์ฑ์ด๋ Snapshot ๋น๋ ๊ฐ์ ๋จ๊ณ์ ๋ณ๋ ฌํ์ ์ต์ ํ๊ฐ ์ฌ์์ ธ ์ถํ ์ ์ฉํ Multi Thread Rendering ๊ตฌ์กฐ์ ์ ํฉํ๊ฒ ์ค๊ณํ์๋ค.
Data-Oriented Design์ ํต์ฌ์ ๋ฐ์ดํฐ ์ ๊ทผ ํจํด์ ๊ธฐ์ค์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๋ฐฐ์น๋ฅผ ์ค๊ณํด Cache Hit๋ฅผ ๋์ด๊ณ , ๋ถํ์ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ค์ด๋ ๊ฒ์ด๋ค. ๊ฐ์ฒด ๋จ์์ ์ถ์ํ๋ณด๋ค ๋งค ํ๋ ์ ๋ฐ๋ณต๋๋ ์ฒ๋ฆฌ ํ๋ฆ์ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฆฌํ์ผ๋ฉฐ, ๊ฐ์ ๊ณ์ฐ์ ํ์ํ ๋ฐ์ดํฐ๋ค์ ์ฐ์๋ ๊ตฌ์กฐ๋ก ๋ฌถ์ด ์์ฐจ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋๋ก ๊ตฌ์ฑํ๋ค.
๋ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋งค ํ๋ ์ ๋ค์ ์ฒ๋ฆฌํ์ง ์๊ณ , ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ์ ๋ ๋๋ง์ ์ค์ ๋ก ํ์ํ Hot Data๋ง ์ ๋ณํด Snapshot๊ณผ Draw Item Cache๋ก ๋ณํํ๋ค. ์ด๋ฅผ ํตํด Scene์ ๋ฐ์ดํฐ์ Renderer์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฆฌํ๊ณ , ๋ ๋๋ง ํ์ดํ๋ผ์ธ์์๋ Cache ์นํ์ ์ธ ๋ฐ์ดํฐ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๊ฒ ํ๋ค.
๋ํ์ ์ผ๋ก JTransformPool ์ translation / rotation / scale์ ๊ฐ๊ฐ ๋ณ๋์ std::vector ๋ก ๋ณด๊ดํ๋ SoA(Structure of Arrays) ๊ตฌ์กฐ์ด๋ฉฐ, ๋ณ๊ฒฝ๋ ์ธ๋ฑ์ค๋ง dirty ring์ ๋์ ํด ๊ทธ ํ๋ ์์ ๋ฐ๋ transform๋ง world matrix๋ก ๋ณํํ๋ค.
// JTransformPool โ SoA + dirty index ring
std::vector<JVec3> _translations;
std::vector<JVec3> _rotations;
std::vector<JVec3> _scales;
std::vector<uint8> _dirtyFlags; // ์ค๋ณต push ๋ฐฉ์ง
std::vector<uint32> _dirtyIndices; // ์ด ํ๋ ์์ ๋ณ๊ฒฝ๋ ์ธ๋ฑ์ค๋ง ๋์ Scene์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ฒด ๋จ์๋ก ํฉ์ด ๋์ง ์๊ณ ๊ฐ์ ์ข ๋ฅ๋ผ๋ฆฌ Pool์ ๋ชจ์ ์ง์ ์์ ํ๋ค. ํต์ฌ์ ์ธ๋ถ(Sceneยท์์คํ )๊ฐ ์ปดํฌ๋ํธ์ ์ฃผ์๋ฅผ ๋ค์ง ์๊ณ ๊ฐ๋ฒผ์ด ํธ๋ค๋ก๋ง ๊ฐ๋ฆฌํค๋ฉฐ, ์ค์ ์ ๊ทผ์ ๋งค๋ฒ ํ์ ๊ฑฐ์น๋ค๋ ์ ์ด๋ค.
struct JEntityHandle { uint32 index; uint32 generation; };
template <typename TData>
struct JPoolSlot { uint32 generation; bool active; TData data; };
template <typename TData>
class JEntityPool {
std::vector<JPoolSlot<TData>> _slots;
std::vector<uint32> _freeIndices;
};์ด๋ ๊ฒ ํฌ์ธํฐ ๋์ ํธ๋ค์ ์ฐ๋ ๊ฒ์ด Pool ๊ตฌ์กฐ์ ๊ถ๊ทน์ ์ธ ์ด์ ๋ค. ์ปดํฌ๋ํธ๋ฅผ ํฌ์ธํฐ๋ก ์ง์ ๋ค๊ณ ์์๋ค๋ฉด, ํ์ด ๋ด๋ถ ๋ฐฐ์ด์ ํค์ฐ๊ฑฐ๋(std::vector ์ฌํ ๋น) ์ฌ๋กฏ์ ์ฌ๋ฐฐ์นํ๋ ์๊ฐ ๊ทธ ์ฃผ์๋ค์ด ์ ๋ถ ๋ฌดํจ๊ฐ ๋์ด ๋ฉ๋ชจ๋ฆฌ ๋ฐฐ์น๋ฅผ ์ฌ์ค์ ๋ฐ๊ฟ ์ ์๋ค. ํธ๋ค์ ์ ๊ทผ ์์ ์ ํ์์ ์์น๋ฅผ ๋ค์ ์ฐพ์ผ๋ฏ๋ก ๋ฐ์ดํฐ๊ฐ ์ด๋๋ก ์ฎ๊ฒจ๊ฐ๋ ์ธ๋ถ ์ฐธ์กฐ๊ฐ ๊นจ์ง์ง ์๋๋ค. ์ฆ ์๋ฌด๋ ์ฃผ์๋ฅผ ๋ค๊ณ ์์ง ์๊ธฐ์ ํ์ด ๋ฐ์ดํฐ ๋ฐฐ์น๋ฅผ ์์ ๋กญ๊ฒ ํต์ ํ ์ ์๊ณ , ๊ฐ์ ์ข
๋ฅ์ ๋ฐ์ดํฐ๋ฅผ ์ฐ์ยทSoA๋ก ๋ชจ์ Cache Hit์จ์ ๋์ด๋ ์ต์ ํ(์์ ๋ณธ JTransformPool์ SoA ๋ถ๋ฆฌ)๊ฐ ๋ฐ๋ก ์ด ์์์ ๊ฐ๋ฅํด์ง๋ค. ํธ๋ค์ ํจ๊ป ๋ด๊ธด generation์ ์ญ์ ํ ์ฌ์ฌ์ฉ๋ ์ฌ๋กฏ์ ๊ตฌ๋ถํด, ์ฌ๋ผ์ง ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๋ฆฌํค๋ ์ ํธ๋ค์ ์์ฐ์ค๋ฝ๊ฒ ๊ฑธ๋ฌ ์ฃผ๋ ์์ ์ฅ์น ์ญํ ์ ํ๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ๊ฐ์ฒด ๊ฐ ํฌ์ธํฐ๋ฅผ ๋ฐ๋ผ๊ฐ๋ ๋ถ๊ท์นํ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ์ด ์ฌ๋ผ์ง๊ณ , Transform ๊ฐฑ์ ์ด๋ RenderObject ์ํ์ฒ๋ผ ๋งค ํ๋ ์ ๋ฐ๋ณต๋๋ ์์ ์ด ์ฐ์๋ ๋ฐฐ์ด์ ์์ฐจ ์ ๊ทผํ๋ ํํ๊ฐ ๋๋ค. ๊ฐ ์ปดํฌ๋ํธ ํ์ Entity index๋ฅผ ๊ทธ๋๋ก ์ปดํฌ๋ํธ ์ฌ๋กฏ ์ธ๋ฑ์ค๋ก ์ฌ์ฉํ๋ฏ๋ก, ํ ์ํฐํฐ๋น ๊ฐ์ ์ข ๋ฅ์ ์ปดํฌ๋ํธ๋ ํ๋๋ง ๊ฐ์ง ์ ์๊ณ lookup์ ํด์ ์์ด ์ธ๋ฑ์ฑ๋ง์ผ๋ก ๋๋๋ค.
Entity Index 0 1 2 3 4
EntityPool active active free active active
RenderObject mesh/ mesh/ mesh/
Pool material material material
TransformPool SoA SoA SoA SoA
Snapshot์ DOD ๊ด์ ์์ Scene ๋ฐ์ดํฐ๋ฅผ ๋ ๋๋ง์ด ๊ฐ๋ฅํ ํํ๋ก ์ฌ๋ฐฐ์นํ๋ ๋จ๊ณ์ด๋ค. Scene์ Entity์ Component๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ข์ ๊ตฌ์กฐ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๊ดํ์ง๋ง, Renderer๋ ๋งค ํ๋ ์ ๊ณ์ฐ๋ world matrix, viewProjection, light parameter, visible draw item ๋ชฉ๋ก์ฒ๋ผ ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ ๋ฐ์ดํฐ๋ง ํ์ํ๋ค.
๋ฐ๋ผ์ Snapshot ๋จ๊ณ์์ CPU-side Component ๋ฐ์ดํฐ๋ฅผ ๋ ๋๋ง์ ํ์ํ ํํ๋ก ๋ณํํ๊ณ , Renderer๊ฐ ์๋ณธ Scene์ ๋ค์ ํ์ํ์ง ์๋๋ก ํ๋ค. ์ด๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด์ ์์ ๊ด๊ณ๊ฐ ์๋๋ผ ์ค์ ์ฌ์ฉ ํ๋ฆ ๊ธฐ์ค์ผ๋ก ์ฌ๊ตฌ์ฑํ์ฌ ๋ถํ์ํ ์ ๊ทผ๊ณผ ๊ณ์ฐ์ ์ค์ด๋ DOD ์ค๊ณ์ด๋ค.
RenderObject์ ๋ณ๊ฒฝ์ ๋งค ํ๋ ์ ์ ์ฒด๋ฅผ ์ฌ๊ตฌ์ถํ์ง ์๊ณ JDrawItemCache ์ ์ฆ๋ถ ๋ฐ์ํ๋ค. Scene ์ด๋ฒคํธ๋ฅผ ๋ฐ์ Added ๋ draw item์ append, Modified ๋ ๊ธฐ์กด range๋ฅผ in-place patch, Removed ์ผ ๋๋ง rebuild ํ๋ค.
DirectX 12์ explicitํ ์ ์ด๊ถ์ ์ ์งํ๋, ์์ RenderPass๊ฐ Command Allocator, Descriptor Heap, Resource Upload, Root Binding์ ์ง์ ์ธ๋ถ์ ์ผ๋ก ๋ค๋ฃจ์ง ์๋๋ก ๋ ๋๋ง Abstraction Layer๋ฅผ ๊ตฌ์ฑํ๋ค.
JRenderContext๋ GPU ๋ฆฌ์์ค ์์ฑ์ ๋ด๋นํ๋ค. CreateVertexBuffer, CreateIndexBuffer, CreateConstantBuffer, CreateTextureFromFile, CreateShader, CreatePipeline, CreateRootSignature ๊ฐ์ ํจ์๋ฅผ ์ ๊ณตํ์ฌ DX12 Resource ์์ฑ ๊ณผ์ ์ ์์ง API ํธ์ถ๋ก ๋จ์ํํ๋ค.
JVertexBuffer* vb = renderContext->CreateVertexBuffer(vertices, vertexCount);
JIndexBuffer* ib = renderContext->CreateIndexBuffer(indices);
JTexture* texture = renderContext->CreateTextureFromFile(path);
JPipeline* pipe = renderContext->CreatePipeline(shader);๋ด๋ถ์์๋ Default Heap ์์ฑ, Upload Buffer ๋ณต์ฌ, Resource Barrier ์ ํ, Descriptor ์์ฑ ๊ฐ์ DX12 ์ ์ฐจ๋ฅผ ์ฒ๋ฆฌํ๋ค. ๋ฐ๋ผ์ ์ฌ์ฉํ๋ ์ชฝ์์๋ GPU Resource๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๋ณต์กํ ์ฝ๋๋ฅผ ๋งค๋ฒ ์์ฑํ์ง ์์๋ ๋๋ค.
JCommandQueue๋ ๋ ๋๋ง ๋ช
๋ น ๊ธฐ๋ก์ ๋จ์ํํ๋ค. RenderBegin, BeginRenderPass, BeginDepthPass, SetPipeline, SetGraphicResources, BindVertexBuffer, DrawIndexed, EndRenderPass, RenderEnd ๊ฐ์ ํจ์๋ฅผ ์ ๊ณตํ์ฌ RenderPass๊ฐ ํ์ํ ๋ช
๋ น๋ง ์์๋๋ก ํธ์ถํ ์ ์๊ฒ ํ๋ค.
commandQueue->BeginRenderPass(renderTarget, clearColor, 1);
commandQueue->SetPipeline(materialResource->pipeline);
commandQueue->SetGraphicResources(&graphicResource);
commandQueue->BindVertexBuffer(meshResource);
commandQueue->DrawIndexed(indexCount, 1, startIndex, 0, 0);
commandQueue->EndRenderPass();๋ํ RenderTarget์ ์ํ ์ ํ, Frame Resource๋ณ Upload Buffer(16 MB ์์ ๋ฒํผ ์
๋ก๋ ๋ง), Descriptor Heap, Fence ๋๊ธฐํ๋ JCommandQueue ๋ด๋ถ์์ ๊ด๋ฆฌํ๋ค. ๊ฐ์ ๋จธํฐ๋ฆฌ์ผ์ด ํ ํ๋ ์ ์์์ ์ฌ๋ฌ ๋ฒ ๊ทธ๋ ค์ง ๋๋ฅผ ์ํด (shader, texture set) ํค๋ก GPU descriptor table์ ์บ์ํ๋ค. ์ด๋ฅผ ํตํด RenderPass๋ "์ด๋ค Target์ ์ด๋ค Resource๋ฅผ ๋ฐ์ธ๋ฉํ๊ณ ์ด๋ค Draw Call์ ์คํํ ๊ฒ์ธ๊ฐ"์๋ง ์ง์คํ ์ ์๋ค.
Shader Compile ์ดํ D3DReflect ๋ก cBuffer, Texture, Sampler Binding ์ ๋ณด๋ฅผ ์์งํ๋ค. ์ด metadata๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Root Signature์ Graphic Resource Binding์ ๊ตฌ์ฑํ์ฌ, C++ ์ฝ๋๊ฐ shader register index๋ฅผ ์ง์ ๋ฐ๋ณต ๊ด๋ฆฌํ์ง ์๋๋ก ํ๋ค.
CompileShader()
โ D3DReflect(VS / PS)
โ collect BoundResources (CBUFFER / TEXTURE / SAMPLER)
โ build binding table
โ create root signature
cBuffer๋ root CBV๋ก, Texture๋ descriptor table๋ก ๋ฌถ์ด๊ณ , Sampler๋ static sampler๋ก root signature์ ๋ฐํ๋ค. ๋ฐ๋ผ์ ์ฌ๋กฏ ์ธ๋ฑ์ค๋ฅผ ์ฝ๋๋ก ์ง์ ํ์ง ์๊ณ ์ ฐ์ด๋์ ๋์ผํ ์ด๋ฆ๋ง ๋ง์ถ๋ฉด ๋ฐ์ธ๋ฉ์ด ์ฐ๊ฒฐ๋๋ค.
JGraphicResource::SetConstantBuffer("PerObject", buffer);
JGraphicResource::SetTexture("AlbedoMap", texture);ํ๋ฐ ๋ ๋์๊ฐ ์ํ๋ฌ์ ์ข
๋ฅ๊น์ง ์ด๋ฆ ๊ท์ฝ์ผ๋ก ์ถ๋ก ํ๋ค โ ๋ฆฌ์์ค ์ด๋ฆ์ Shadow ๊ฐ ๋ค์ด๊ฐ๋ฉด ์์ง์ด reverse-Z์ฉ ๋น๊ต ์ํ๋ฌ(GREATER_EQUAL + border)๋ฅผ ์๋ ์์ฑํ๋ค. ์ ์
ฐ์ด๋๊ฐ ๊ทธ๋ฆผ์ ๋น๊ต ์ํ๋ง์ ์ฐ๋ ค๋ฉด ์ด๋ฆ๋ง ๋ง์ถ๋ฉด ๋๋ค.
Renderer๋ RenderPath::Forward / RenderPath::Deferred ๋ฅผ ๋ฐํ์์ ์ ํํ๋ค. Deferred path๋ ํ๋์ ๊ฑฐ๋ํ ์
ฐ์ด๋ ๋์ , ๊ฐ์ ์
๋ ฅ๊ณผ ์ถ๋ ฅ์ด ๋ช
ํํ 6๊ฐ์ ๋
๋ฆฝ ํจ์ค๋ก ๋ถ๋ฆฌํ๋ค.
JRenderer::Render(JFrameDesc)
โ
โโโถ JShadowPass directional light ๊ธฐ์ค cascade depth ์์ฑ (Texture2DArray)
โโโถ JDepthPass ์นด๋ฉ๋ผ ์์ reverse-Z depth pre-pass
โโโถ JGBufferPass Albedo / Normal / Material(MRT 3์ฅ) ๊ธฐ๋ก
โโโถ JSSAOPass depthยทnormal๋ก ํ๋ฉด ๊ณต๊ฐ ์ฐจํ ๊ณ์ฐ โ AO ํ๊ฒ (Lighting์ด ๋ธ๋ฌํด ์ฌ์ฉ)
โโโถ JLightingPass full-screen triangle๋ก G-Buffer ์ํ๋ง โ PBR ๋ผ์ดํ
+ IBL
โโโถ JForwardOverlayPass ๋ฐํฌ๋ช
ยท๋๋ฒ๊ทธยท๊ทธ๋ฆฌ๋ ๋ฑ forward ์ค๋ฒ๋ ์ด
์ฌ๊ธฐ์ ์ค์ํ ์ค๊ณ ๊ฒฐ์ ์, ๋ชจ๋ ํจ์ค๊ฐ mutable Scene์ ์ ํ ๋ชจ๋ฅธ๋ค๋ ์ ์ด๋ค. ํจ์ค์ ์
๋ ฅ์ immutable JFrameDesc ์ JRenderDB(GPU ๋ฆฌ์์ค mirror)๋ฟ์ด๋ผ, ๊ฐ ํจ์ค๋ ๊ฐ์ ์
๋ ฅ์ ๋ํด ํญ์ ๊ฐ์ ์ถ๋ ฅ์ ๋ด๋ ์์ ํจ์์ ๊ฐ๊น๋ค. ๊ทธ ๋๋ถ์ ํจ์ค ๋จ์ ํ
์คํธ, ๊ฐ์ ํ๋ ์์ ๋ฐ๋ณต ์ฌ์(๋ฆฌํ๋ ์ดยทํค๋๋ฆฌ์ค), snapshotยทculling ๋จ๊ณ์ ๋ณ๋ ฌํ๊ฐ ๊ตฌ์กฐ์ ์ผ๋ก ๊ฐ๋ฅํด์ง๋ค.
๋ํ ๊ฐ ํจ์ค๊ฐ ์๊ธฐ ์
ฐ์ด๋ยทํ์ดํ๋ผ์ธ์ lazyํ๊ฒ ์์ฑ(ensureResources)ํ๊ณ , depthยทshadowยทgbuffer๊ฐ ๋์ผํ draw item ๋ชฉ๋ก(opaqueDrawItemIndices = frustum culling ๊ฒฐ๊ณผ)์ ๊ณต์ ํ๋ฏ๋ก, ํจ์ค๋ฅผ ์ถ๊ฐํ๋ ๋น์ฉ์ด "ํด๋์ค ํ๋ ์ถ๊ฐ" ์์ค์ผ๋ก ๋ฎ๋ค.
๋ณธ๊ฒฉ์ ์ธ G-Buffer ๊ธฐ๋ก ์ ์, ๋ถํฌ๋ช ์ค๋ธ์ ํธ์ ๊น์ด๋ง ๋จผ์ ํ ๋ฒ ๊ทธ๋ฆฐ๋ค. depth pre-pass๋ก ์ต์ข ๊น์ด๋ฅผ ํ์ ํด ๋๋ฉด ์ดํ G-Buffer / Lighting ํจ์ค์์ ๊ฐ๋ ค์ง๋ ํฝ์ ์ ํฝ์ ์ ฐ์ด๋ ๋น์ฉ์ ์ ๊ฐํ ์ ์๋ค.
์ด ๊ณผ์ ์์ Reverse-Z๋ฅผ ์์ง ์ ์ญ์ ๋จ์ผ ๊ท์ฝ์ผ๋ก ํต์ผํ ๊ฒ์ด ํน์ง์ด๋ค. ๊น์ด ๋น๊ต ํจ์๋ฅผ GREATER, depth clear ๊ฐ์ 0(near = 1, far = 0)์ผ๋ก ๋ง์ท๊ณ , ์ด ๊ท์ฝ์ depth pre-pass๋ฟ ์๋๋ผ G-Buffer, shadow ortho ํฌ์, ๋น๊ต ์ํ๋ฌ, "์๋ฌด๊ฒ๋ ์ ๊ทธ๋ ค์ง ํฝ์
ํ์ "๊น์ง ์ ๋ถ ๋์ผํ๊ฒ ์ ์ฉ๋๋ค. depth๋ฅผ ๋ค๋ฃจ๋ ์ฝ๋ ์ด๋์๋ "0 = far, ๋น๊ต๋ GREATER"๊ฐ ์ผ๊ด๋๊ฒ ์ฑ๋ฆฝํ๋ฏ๋ก, ํจ์ค๋ฅผ ๋๋ ค๋ ๊น์ด ์ฒ๋ฆฌ์์ ์ค์๊ฐ ๋ผ์ด๋ค ์ฌ์ง๊ฐ ์ ๋ค. ๋ถ๊ฐ์ ์ผ๋ก ๋ถ๋์์์ depth ๋ถํฌ๊ฐ ์๊ฑฐ๋ฆฌ์์ ์ด์ดํด์ ธ z-fighting๋ ์ค์ด๋ ๋ค.
depth pre-pass์ shadow pass๋ ๊ฒฐ๊ตญ ๊น์ด๋ง ํ์ํ๋ฏ๋ก ๋์ผํ depth_prepass.hlsl ์
ฐ์ด๋๋ฅผ ๊ณต์ ํ๋ค. ํจ์ค๊ฐ ๋์์ง๋ง ์
ฐ์ด๋ ์ฝ๋๋ ํ ๋ฒ๋ง ์ ์ง๋๋ค.
// JDepthPass / JShadowPass ๋ชจ๋ ๊ฐ์ ์
ฐ์ด๋๋ฅผ ์ฌ์ฌ์ฉ
_shader = renderContext->CreateShader(get_Engine_Shader_Path() + "\\depth_prepass.hlsl");
_pipeline = renderContext->CreatePipeline(
_shader, /*alphaBlend*/ false, /*vertexInput*/ true, ...,
/*depthWrite*/ D3D12_DEPTH_WRITE_MASK_ALL,
/*depthFunc*/ D3D12_COMPARISON_FUNC_GREATER); // reverse-Zdirectional light์ ๊ด์ญ ๊ทธ๋ฆผ์๋ฅผ ์ํด 4๋จ Cascade Shadow Map์ ๊ตฌํํ๋ค. ๊น์ด๋ CASCADE_COUNT(4) ์ฌ๋ผ์ด์ค๋ฅผ ๊ฐ์ง Texture2DArray ํ ์ฅ์, cascade๋ณ DSV๋ก ๋๋ ๊ทธ๋ฆฐ๋ค.
์นด๋ฉ๋ผ์์ ๊ฐ๊น์ธ์๋ก ์ด์ดํ ํด์๋๊ฐ ํ์ํ๋ฏ๋ก, ์์ผ ๊ฑฐ๋ฆฌ๋ฅผ ๋น์ ํ ๋น์จ๋ก ๋๋๋ค.
// ๋์ ๋น์จ โ ๊ฐ๊น์ด cascade์ผ์๋ก ์ข์ ๊ตฌ๊ฐ์ ๋ฎ์
constexpr float CASCADE_SPLIT_RATIOS[4] = { 0.05f, 0.16f, 0.42f, 1.0f };์ด ๊ตฌํ์ ํน์ง์ near/far ํ๋ฉด ๊ฐ์ด๋ ๋ณ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ํ๋ ์ ๋ฐ์ดํฐ๋ก ๋๊ธฐ์ง ์๊ณ , ์นด๋ฉ๋ผ์ inverseViewProjection ํ๋๋ง์ผ๋ก ๋ชจ๋ ๋ถํ ์ ์ ๋ํ๋ค๋ ์ ์ด๋ค(self-contained). NDC ์ฝ๋๋ฅผ ์ญํฌ์ํด world-space ํ๋ฌ์คํ
์ฝ๋๋ฅผ ๊ตฌํ๊ณ , ๊ฐ cascade ๊ตฌ๊ฐ์ ์ฝ๋ ๋ณด๊ฐ์ผ๋ก ์๋ผ๋ธ๋ค.
// NDC ์ฝ๋ โ world-space ํ๋ฌ์คํ
์ฝ๋ (reverse-Z: z=1 near, z=0 far)
corners.nearCorners[i] = XMVector3TransformCoord({ndcX, ndcY, 1.0f, 0.0f}, inverseViewProjection);
corners.farCorners[i] = XMVector3TransformCoord({ndcX, ndcY, 0.0f, 0.0f}, inverseViewProjection);๊ฐ cascade ์ฌ๋ผ์ด์ค์ 8๊ฐ ์ฝ๋๋ฅผ ๊ฐ์ธ๋ bounding sphere๋ก ์ง๊ต ํฌ์ ๋ณผ๋ฅจ์ ์ก๋๋ค. sphere ๊ธฐ๋ฐ์ด๋ผ ์นด๋ฉ๋ผ๊ฐ ํ์ ํด๋ ๋ณผ๋ฅจ ํฌ๊ธฐ๊ฐ ๋ณํ์ง ์์ ๊ทธ๋ฆผ์ ๊ฐ์ฅ์๋ฆฌ์ ๊น๋นก์(shimmering)์ด ์ค์ด๋ ๋ค. ์ฌ๋ผ์ด์ค ๋ค์ชฝ(๋ผ์ดํธ ๋ฐฉํฅ)์ caster๊น์ง ๋ด๊ธฐ๋๋ก ์ฌ์ (casterMargin)๋ฅผ ๋ํ๋ฉฐ, ์ง๊ต ํฌ์๋ ์์ง ์ ์ญ reverse-Z์ ๋ง์ถฐ near/far๋ฅผ ์ค์ํ๋ค.
const XMMATRIX lightView = XMMatrixLookToLH(eye, lightDirection, up);
// reverse-Z(GREATER, clear 0)์ ๋ง์ถฐ near/far๋ฅผ ์ค์
const XMMATRIX lightProjection =
XMMatrixOrthographicOffCenterLH(-radius, radius, -radius, radius, /*zFar*/ zFar, /*zNear*/ 0.0f);๋ผ์ดํ
ํจ์ค์์๋ ํฝ์
์ ์นด๋ฉ๋ผ ๊ฑฐ๋ฆฌ๋ก cascade๋ฅผ ๊ณ ๋ฅธ ๋ค 2ร2 PCF๋ก ์ํ๋งํ๋ค. ๋น๊ต ์ํ๋ฌ๋ฅผ C++์์ ๋ง๋ค์ด ๋๊ธฐ๋ ๊ฒ ์๋๋ผ, ์์ ์ค๋ช
ํ ์ด๋ฆ ๊ท์ฝ(Shadow)์ ๋ฐ๋ผ ์
ฐ์ด๋ ๋ฆฌํ๋ ์
๋จ๊ณ์์ ์์ง์ด reverse-Z ๋น๊ต ์ํ๋ฌ๋ฅผ ์๋ ์์ฑํ๋ค. ๋งต ๋ฐ UV๋ border(0)์ ๋น๊ต๋ผ ref >= 0 โ ํญ์ lit์ผ๋ก ์ฒ๋ฆฌ๋๋ค.
Texture2DArray ShadowMap : register(t4);
SamplerComparisonState ShadowSampler : register(s0); // ์ด๋ฆ์ Shadow โ ๋น๊ต ์ํ๋ฌ ์๋ ์์ฑ
float referenceDepth = saturate(shadowPos.z + CascadeBiases[cascade]); // cascade๋ณ reverse-Z bias
shadow += ShadowMap.SampleCmpLevelZero(ShadowSampler, float3(uv, cascade), referenceDepth);depth bias๋ world ๋จ์๋ก ํ ๋ฒ๋ง ์ง์ ํ๊ณ , cascade๋ง๋ค ์์ ์ zFar๋ก ๋๋ reverse-Z depth ๋จ์๋ก ํ์ฐํ๋ค. ๋๋ถ์ ๊ฐ๊น์ด cascade์ ๋จผ cascade๊ฐ ์ผ๊ด๋ ๋๊ป์ bias๋ฅผ ๊ฐ๋๋ค.
| MRT | ํฌ๋งท | ๋ด์ฉ |
|---|---|---|
| Albedo | R8G8B8A8_UNORM |
base color (ร material baseColor) |
| Normal | R16G16B16A16_FLOAT |
world-space normal (0.5+0.5 ์ธ์ฝ๋ฉ) |
| Material | R8G8B8A8_UNORM |
R=Roughness, G=Metallic, B=Occlusion |
| Depth | D32_FLOAT |
reverse-Z depth (pre-pass์ ๊ณต์ ) |
๋จธํฐ๋ฆฌ์ผ ํ ์ค์ฒ๋ Bistro/glTF ์ปจ๋ฒค์ ์ ORM ํจํน(R=Occlusion, G=Roughness, B=Metalness) ์ ๊ทธ๋๋ก ์ฝ์ด ํ ๋ฒ์ ์ํ๋ก ์ธ ๊ฐ์ ์ป๋๋ค.
๋ ธ๋ฉ ๋งคํ์ ์ํด ๋ฒํ ์ค ํ์ ํธ๋ฅผ ๋ฐ๋ก ์ ์ฅยท์ํฌํธํ์ง ์๋๋ค. ๋์ G-Buffer ํจ์ค์์ ํ๋ฉด ๊ณต๊ฐ ๋ฏธ๋ถ(ddx/ddy)์ผ๋ก cotangent frame์ ์ฆ์ ๊ตฌ์ฑํด ๋ ธ๋ฉ ๋งต์ ์ ์ฉํ๋ค(Schรผler์ cotangent frame). ๋ฉ์ ํฌ๋งท์ tangent ์ฑ๋์ด ์์ด๋ ๋ ธ๋ฉ ๋งคํ์ด ๋์ํ๋ฏ๋ก FBX ์ํฌํธ ํ์ดํ๋ผ์ธ๊ณผ ์ ์ ๋ ์ด์์์ด ๊ทธ๋งํผ ๋จ์ํด์ง๋ค.
// ๋ฒํ
์ค ํ์ ํธ ์์ด TBN ๊ตฌ์ฑ. ddx/ddy๋ ๋์คํฐํ ์ค์๋ง ์ ํจํ๋ฏ๋ก G๋ฒํผ ํจ์ค์์ ๋
ธ๋ฉ์ ์์ฑํ๋ค.
float3 dp1 = ddx(worldPos); float3 dp2 = ddy(worldPos);
float2 duv1 = ddx(uv); float2 duv2 = ddy(uv);
float3 tangent = cross(dp2, normal) * duv1.x + cross(normal, dp1) * duv2.x;
float3 bitangent = cross(dp2, normal) * duv1.y + cross(normal, dp1) * duv2.y;BC5๋ก ์์ถ๋ ๋
ธ๋ฉ ๋งต์ RG๋ง ์ ์ฅํ๋ฏ๋ก Z๋ sqrt(1 - xยฒ - yยฒ)๋ก ๋ณต์ํ๋ค.
Lighting ํจ์ค๋ full-screen triangle ํ๋๋ก ํ๋ฉด์ ๋ฎ๊ณ , G-Buffer๋ฅผ Load๋ก ์ง์ ์ฝ์ด ํฝ์
๋ณ PBR์ ๊ณ์ฐํ๋ค.
- BRDF : GGX(๋ฒ์ ๋ถํฌ) + Smith(๊ธฐํ ๊ฐ์ ) + Schlick Fresnel ์ Cook-Torrance ๋ชจ๋ธ.
- ๋ผ์ดํธ :
w <= 0์ด๋ฉด directional(๊ฐ์ ์์),w > 0์ด๋ฉด point light๋ก inverse-square + range windowing(UE/Frostbite ์คํ์ผ) ๊ฐ์ ๋ฅผ ์ ์ฉํ๋ค. - ๊ทธ๋ฆผ์ : ๋ชจ๋ directional light๊ฐ ์ฒซ directional ๊ธฐ์ค cascade shadow๋ฅผ ๊ณต์ ํ๋ค.
- AO : occlusion(SSAO)์ ๊ฐ์ ๊ด(ambient)์๋ง ์ ์ฉํ๊ณ , ์ง์ ๊ด ์ฐจํ๋ shadow map์ด ๋ด๋นํ๋๋ก ์ญํ ์ ๋ถ๋ฆฌํ๋ค.
- ํค๋งคํ : ์ต์ข ์์ ACES filmic ๊ทผ์ฌ(Narkowicz 2015) ๋ก ํค๋งคํํ ๋ค ๊ฐ๋ง ๋ณด์ ํ๋ค. Reinhard๋ณด๋ค ๋๋นยท์ฑ๋ ๋ณด์กด์ด ์ข๋ค.
์ ์ญ reverse-Z ๊ท์ฝ ๋๋ถ์, "์๋ฌด๊ฒ๋ ๊ทธ๋ ค์ง์ง ์์ ํฝ์ (depth == 0 = far plane)"์ ๋จ ํ ๋ฒ์ ๋น๊ต๋ก ๊ฑธ๋ฌ ๋ผ์ดํ ์ ๊ฑด๋๋ด๋ค โ ๊น์ด ๊ท์ฝ์ ํต์ผํด ๋ ํจ๊ณผ๊ฐ ๋ผ์ดํ ๋จ๊ณ์์๋ ๊ทธ๋๋ก ์ด์ด์ง๋ค.
float depth = DepthBuffer.Load(int3(pixel, 0)).r;
if (depth <= 0.0f) return float4(albedo, alpha); // far plane = ๋ฏธ์์ฑ ํฝ์
...
color = ACESFilm(ambient + direct);
color = pow(saturate(color), 1.0 / 2.2);์ง์ ๊ด(CSM)๋ง์ผ๋ก๋ ๊ทธ๋ฆผ์ ์์ญ์ด ์๊น๋งฃ๊ฒ ๋จ์ด์ง๋ค. ๊ฐ์ ๊ด์ ์ฑ์ฐ๊ธฐ ์ํด ์ ์ ์ฌ์ ์ง์ ์บก์ฒํด ๊ตฝ๋ split-sum IBL๊ณผ ํ๋ฉด ๊ณต๊ฐ SSAO๋ฅผ ์ถ๊ฐํ๋ค. ์ธ๋ถ HDRI๋ฅผ ์ฐ์ง ์๊ณ ์ฌ ์์ฒด๋ฅผ ํ๊ฒฝ๋งต์ผ๋ก ์บก์ฒํ๋ฏ๋ก ๋ฐ์ฌยท๊ฐ์ ๊ด์ด ์ค์ ์ฅ๋ฉด๊ณผ ์ผ์นํ๋ค.
[๋ก๋ ํ 1ํ bake] [๋งค ํ๋ ์]
probe ์์น์์ ์ฌ 6๋ฉด โ HDR ํ๋ธ ์บก์ฒ
โ (irradiance / prefiltered / BRDF LUT ์์ฑ)
โผ LightingPass:
โโ irradiance ํ๋ธ (diffuse GI) โโ ambient = kDยทirradianceยทalbedo
โโ prefiltered ํ๋ธ (specular) โโโ์์ฃผ(์ํ๋ง)โโโถ + prefilteredยท(Fยทbrdf.x + brdf.y)
โโ BRDF LUT (Fํญ ์ ๋ถ) โโ (ร SSAO)
probe(์ฃผ ์นด๋ฉ๋ผ) ์์น์์ 6๋ฉด์ 90ยฐ FOVยทreverse-Z๋ก HDR ํ๋ธ(R16G16B16A16F)์ ๋ ๋ํ๋ค. ์ฌ๊ธฐ์ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ ์ค๊ณ๊ฐ ๊ทธ๋๋ก ์ด๋์ด ๋๋ค โ ๊ฐ์ ์ฌ์ ๋ฉด๋ง๋ค JFrameDesc๋ง ์๋ก ๊ตฌ์ฑ(probe ์นด๋ฉ๋ผ + ๋ฉด ๋ฐฉํฅ + ํ๋ธ face ํ๊ฒ)ํด ๋์ผํ deferred ๊ฒฝ๋ก๋ฅผ 6๋ฒ ๋๋ฆฌ๋ฉด ๋์ด๋ค. IBL ์์ค๋ linear์ฌ์ผ ํ๋ฏ๋ก ์บก์ฒ ๊ฒฝ๋ก์์๋ ํค๋งคํ/๊ฐ๋ง๋ฅผ ๊ฑด๋๋ฐ๊ณ linear HDR๋ก ๊ธฐ๋กํ๋ค.
์์ง์ compute ํ์ดํ๋ผ์ธ์ด ์์ด, ๋ชจ๋ ์ปจ๋ณผ๋ฃจ์ ์ ํ์คํฌ๋ฆฐ ํจ์ค๋ก ํ๋ธ ๋ฉด์ ์ง์ ๋ ๋ํด ์ฒ๋ฆฌํ๋ค.
- irradiance ํ๋ธ: ์บก์ฒ ํ๋ธ๋ฅผ ์ฝ์ฌ์ธ ๊ฐ์ค ์ ๋ถ โ ์ ์ฃผํ diffuse GI (์์ 32ยฒ ํ๋ธ๋ก ์ถฉ๋ถ)
- prefiltered ํ๋ธ: roughness๋ณ GGX importance sampling์ผ๋ก mip๋ง๋ค ํ๋ฆฌํํฐ โ roughness๊ฐ ํด์๋ก ํ๋ฆฐ ๋ฐ์ฌ
- BRDF LUT: split-sum์ Fํญ์
(NdotV, roughness)๋ก ์ ๋ถํ 2D LUT. ํ๊ฒฝ๊ณผ ๋ฌด๊ดํ๋ฏ๋ก ํ ๋ฒ๋ง ๊ตฝ๋๋ค.
float3 F = FresnelSchlickRoughness(NdotV, f0, roughness);
float3 kD = (1 - F) * (1 - metallic);
float3 diffuseIBL = IrradianceMap.Sample(s, N).rgb * albedo;
float3 prefiltered = PrefilteredEnv.SampleLevel(s, reflect(-V, N), roughness * MaxMip).rgb;
float2 brdf = BRDFLUT.Sample(sClamp, float2(NdotV, roughness)).rg;
float3 ambient = (kD * diffuseIBL + prefiltered * (F * brdf.x + brdf.y)) * ao;๊ฒฐ๊ณผ ํ๋ธ 3์ข ์ ๋ฐํ์ ๋ด๋ด ์์ฃผํ๊ณ ๋งค ํ๋ ์ ํ ์ค์ฒ ์ํ๋ง ํ๋ค โ ์ ์ ์ฌ์ด๋ผ bake๋ 1ํ๋ฉด ์ถฉ๋ถํ๊ณ ๋ฐํ์ ๋น์ฉ์ ๊ฑฐ์ 0์ด๋ค. ๋ ์ง์ค๋ฉํธ๋ฆฌ๊ฐ ์๋ ํฝ์ ์๋ ์ ์ฐจ์ ํ๋์ ๊ทธ๋ ค, skybox ๋ฐฐ๊ฒฝ์ด์ IBL ์๋ฐ๊ตฌ ๊ด์์ผ๋ก ๋์์ ํ์ฉํ๋ค.
์ฌ๊ธฐ์๋ ์์ง์ ์ด๋ฆ ๊ท์ฝ ๋ฐ์ธ๋ฉ์ด ์ด์ด์ง๋ค โ BRDF LUT์ฉ์ผ๋ก ์ด๋ฆ์
LUT๊ฐ ๋ค์ด๊ฐ๋ฉด clamp ์ํ๋ฌ๋ฅผ ์๋ ์์ฑํ๋ ๊ท์น์ ์ถ๊ฐํด(๊ฐ์ฅ์๋ฆฌ ๋์ ๋ฐฉ์ง), ์ ฐ์ด๋๋ ์ฌ๋กฏ/์ํ๋ฌ ์ค์ ์์ด ์ด๋ฆ๋ง ๋ง์ถ๋ฉด ๋๋ค.
์ด ์์ฐ์ "ORM" ํ
์ค์ฒ๊ฐ ์ฌ์ค Specular ๋งต์ด๋ผ baked occlusion(R ์ฑ๋)์ด 0์ ๊ฐ๊น์ ๊ณ , ๊ทธ๋๋ก ๊ณฑํ๋ฉด ๊ฐ์ ๊ด์ด ํต์งธ๋ก ์ฃฝ์ด ๊ทธ๋ฆผ์๊ฐ ์๊น๋งฃ๊ฒ ๋ณด์๋ค. baked AO์ ์์กดํ๋ ๋์ JSSAOPass๋ก depthยทnormal์์ ์ค์๊ฐ ์ฐจํ๋ฅผ ๊ณ์ฐํด ๊ฐ์ ๊ด์๋ง ๊ณฑํ๋๋ก ๋ฐ๊ฟจ๋ค.
- AO๋ฅผ ์ ์ฉ ํจ์ค์์ ๋จ์ผ ์ฑ๋ ํ๊ฒ์ ๋ ๋ํ๊ณ , ๋ผ์ดํ ์์ ๋ฐ์ค ๋ธ๋ฌ๋ก ์ฝ์ด ์๊ฐฑ์ด ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐํ๋ค.
- ์ํ ๋ฐ๊ฒฝ์ ์๋ ๊ณต๊ฐ ๊ธฐ์ค์ผ๋ก ์ก์ ํ๋ฉด ํฝ์ ๋ก ํ์ฐํ๋ค. ํ๋ฉด ๊ณ ์ ํฝ์ ๋ฐ๊ฒฝ์ ์๊ฑฐ๋ฆฌ์์ ์๋ footprint๊ฐ ๊ณผ๋ํ๊ฒ ์ปค์ ธ ๊น์ด๊ฐ ๋ค๋ฅธ ๋ฉด์ ๊ฐ๋ก์ง๋ฌ ์ผ๋ฃฉ์ด ์๊ธฐ๋๋ฐ, ์๋ ๊ธฐ์ค์ผ๋ก ๋๋ฉด ๊ฑฐ๋ฆฌ์ ๋ฌด๊ดํ๊ฒ ์ผ์ ํ ์ฐจํ๊ฐ ๋๋ค.
์ค๊ณ ํธ๋ ์ด๋์คํ: ๋จ์ผ probe๋ผ ์์น๋ณ ๋ฐ์ฌ ์์ฐจ(parallax)๋ ์๊ณ , 1-bounce ์ ์ ์บก์ฒ๋ค. ์ ์ ์ฌ ์ผ์ผ์ด์ค์์ ๋๋ฌ๋์ง ์์ผ๋ฉฐ, ๋ค์ค probeยท๋ฉํฐ๋ฐ์ด์ค ์ฌbake๋ก ํ์ฅ ๊ฐ๋ฅํ ๊ตฌ์กฐ๋ก ๋จ๊ฒจ ๋์๋ค.
์ถํ AI Agent๋ฅผ ์์ง์ ์ฐ๊ฒฐํ๋ ๊ฒ์ ๊ณ ๋ คํ์ฌ, ์์ง ์ํคํ
์ฒ๋ฅผ AI๊ฐ ์ดํดํ๊ณ ํ์ฅํ๊ธฐ ์ฌ์ด ํํ๋ก ์ค๊ณํ๋ค. Scene, Snapshot, RenderDB, Renderer, RenderPass์ ์ญํ ์ ๋ช
ํํ ๋ถ๋ฆฌํ๊ณ , ๋ฐ์ดํฐ ํ๋ฆ์ ๋จ๋ฐฉํฅ์ ๊ฐ๊น๊ฒ ๊ตฌ์ฑํ์ฌ ๊ฐ ๋จ๊ณ์ ์ฑ
์๊ณผ ์
๋ ฅ/์ถ๋ ฅ์ ์ถ์ ํ๊ธฐ ์ฝ๋๋ก ํ๋ค. ๋ํ ์ ์์ค DX12 API๋ฅผ JRenderContext, JCommandQueue, JGraphicResource ๊ฐ์ ์์ฒด API๋ก ๋ํํ์ฌ, AI๊ฐ ๊ธฐ๋ฅ์ ์ถ๊ฐยท์์ ํ ๋ ๋ณต์กํ DX12 ์ธ๋ถ ๊ตฌํ๋ณด๋ค ์์ง ๋ ๋ฒจ์ ๋ช
ํํ ์ธํฐํ์ด์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ์์
ํ ์ ์๋๋ก ํ๋ค.
Scene ์ ์ฅ ํฌ๋งท ์ญ์ AI ๋๊ตฌ๊ฐ ์ดํดํ๊ธฐ ์ฝ๋๋ก JSON ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ฑํ๋ค. Scene์ binary๊ฐ ์๋๋ผ entities / materials / meshes ๋ก ๋ถ๋ฆฌ๋ ๋ช
์์ JSON ๊ตฌ์กฐ๋ก ์ ์ฅ๋๋ฉฐ, ๊ฐ Entity๋ stableID, name, transform, camera, light, renderObjectComponent ์ฒ๋ผ ์๋ฏธ ์๋ ํ๋๋ช
์ ๊ฐ์ง๋ค.
{
"stableID": "ent_camera_001",
"name": "MainCamera",
"transform": { "translation": [0, 3, -5], "rotation": [0, 0, 0], "scale": [1, 1, 1] },
"camera": { "primary": true, "nearP": 0.1, "farP": 1000.0 }
}์ด ๊ตฌ์กฐ๋ ์์ง ๋ด๋ถ์ Pool/Handle ๊ธฐ๋ฐ ๋ฐํ์ ๊ตฌ์กฐ์ ๋ถ๋ฆฌ๋์ด ์๋ค. ์คํ ์์๋ ์ฑ๋ฅ ์ค์ฌ์ ๋ฐ์ดํฐ ๋ฐฐ์น๋ฅผ ์ฌ์ฉํ๊ณ , ์ ์ฅยทํธ์ง ์์๋ ๊ฐ๋ ์ฑ๊ณผ ์๋ํ ๊ฐ๋ฅ์ฑ์ ์ฐ์ ํ ๊ตฌ์กฐ์ด๋ค.
JAssetImporter๋ OpenFBX๋ฅผ ์ฌ์ฉํด FBX โ ๋ฉ์ / ๋จธํฐ๋ฆฌ์ผ / ํ
์ค์ฒ / ์ฌ JSON์ผ๋ก ๋ณํํ๋ ๋ณ๋ ์คํ ํ์ผ์ด๋ค. ํ
์ค์ฒ๋ ์ํฌํธ ์ .jtex ์ปจํ
์ด๋(๋ฐ์ฒด์ธยท์์ถ ํฌ๋งท ํฌํจ)๋ก ๊ตฌ์์ง๊ณ , ๋ฐํ์์ ์ ์ฉ ๋ฆฌ๋๋ก ๊ทธ๋๋ก GPU์ ์ฌ๋ฆฐ๋ค. ๋ฐํ์์ FBX ์์กด์ ๋์ง ์๊ธฐ ์ํด ๋น๋์ ์ํฌํธ๋ฅผ ๋ถ๋ฆฌํ๋ค.
JAssetImporter <source.fbx> <projectDir>
src/
โโโ engine/
โ โโโ core/ JEngine, JEngineContext, JJobSystem, JPool, JHashFunction, JObject
โ โโโ scene/ JScene, JTransformPool, JCameraPool, JLightPool,
โ โ JRenderObjectComponentPool, JSceneSerializer, JSceneHandle
โ โโโ render/ JRenderer, JRenderServer, JRenderDB, JRenderSnapshotBuilder,
โ โ JCameraRenderQueueBuilder, JDrawItemCache, JMaterialFactory,
โ โ JCommandQueue, JSwapChain, JRenderContext, JRenderResource,
โ โ JGraphicResource, JRenderTarget, JGBuffer,
โ โ ํจ์ค: SceneColor / Shadow / Depth / GBuffer / SSAO / Lighting / ForwardOverlay,
โ โ JShadowMap (CSM), JReflectionProbe (IBL)
โ โโโ asset/ JMaterial, JMesh, JShader, JTextureFile (.jtex)
โ โโโ platform/ JDevice
โ โโโ dx12/ JDx12Helper, d3dx12 wrapper
โโโ client/
โ โโโ editor/ JSceneManager, JScenePanel, JSceneBuilder, JImGuiLayer,
โ โ JFBXLoader, JAssetManager
โ โโโ OpenFBX/ vendored OpenFBX
tools/
โโโ JAssetImporter/ FBX โ ํ๋ก์ ํธ JSON/.jtex ๋ณํ๊ธฐ
samples/
โโโ GaussianSmoke/ ํํฐํด ์ค๋ชจํฌ ๋ฐ๋ชจ (๋ณ๋ ์คํ ํ์ผ)
SampleProjects/
โโโ BistroExterior/ project.json ๊ธฐ๋ฐ ์ํ ํ๋ก์ ํธ (deferred + CSM + IBL)
benchmark/ OOP / AoS / SoA / WorldMatrix ๋ฐ์ดํฐ ๋ ์ด์์ ๋น๊ต (์ต์
)
third_party/
โโโ nlohmann/json
โโโ imgui ์๋ํฐ UI
๋น๋ ํ๊ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
| ํ๊ฒ | ํํ | ๋น๊ณ |
|---|---|---|
Engine |
static lib | DX12 / DXGI / D3DCompiler / WindowsCodecs |
Client |
WIN32 exe | ์๋ํฐ/๋ทฐ์ด๋ฅผ ๊ฒธํ๋ ํธ์คํธ ์์ฉ (ImGui) |
JAssetImporter |
console exe | FBX โ ํ๋ก์ ํธ/.jtex ๋ณํ ๋๊ตฌ |
GaussianSmokeSample |
WIN32 exe | ํํฐํด ์ค๋ชจํฌ ๋ฐ๋ชจ |
Benchmark |
console exe | BUILD_BENCHMARK=ON ์ต์
. oneTBB FetchContent |
- Windows 10 ์ด์
- Direct3D 12 ์ง์ GPU (
D3D_FEATURE_LEVEL_11_0+) - Visual Studio 2019/2022 + C++ desktop workload, Windows 10 SDK
- ์ ํ: Graphics Tools (D3D12 debug layer)
cmake -S . -B build
cmake --build build --config Release๋ฒค์น๋งํฌ๊น์ง ๋น๋ํ๋ ค๋ฉด:
cmake -S . -B build -DBUILD_BENCHMARK=ON
cmake --build build --config ReleaseClient๊ฐ Visual Studio์ ๊ธฐ๋ณธ ์์ ํ๋ก์ ํธ๋ก ์ค์ ๋์ด ์๋ค.
Client ์คํ ์ ๋ช
๋ น์ค ์ต์
:
Client.exe # ๊ธฐ๋ณธ ์ํ ์ฌ (res/scene/sample.jscene.json)
Client.exe --new # ๋น ์ฌ์ผ๋ก ์์ (-n)
Client.exe --scene <path> # ํน์ ์ฌ ํ์ผ (-s)
Client.exe --project <path> # ํ๋ก์ ํธ ํด๋ (-p, project.json ํ์)
Client.exe <projectPath> # ์์น ์ธ์๋ ํ๋ก์ ํธ ํด๋๋ก ํด์
์: ๋๋ด๋ Bistro ์ํ ํ๋ก์ ํธ ์ด๊ธฐ
Client.exe --project SampleProjects/BistroExterior
FBX๋ฅผ ํ๋ก์ ํธ๋ก ์ํฌํธ:
JAssetImporter <source.fbx> <projectDir>
<projectDir> ์๋์ scenes/, meshes/, materials/, textures/, shader/ ๋๋ ํฐ๋ฆฌ๊ฐ ์์ฑ๋๊ณ , ๋จธํฐ๋ฆฌ์ผยท๋ฉ์๋ JSON, ํ
์ค์ฒ๋ .jtex๋ก ์ ์ฅ๋๋ค.
- nlohmann/json โ
third_party/nlohmann/ - Dear ImGui โ
third_party/imgui/(์๋ํฐ UI) - OpenFBX โ
src/client/OpenFBX/ - oneTBB โ ๋ฒค์น๋งํฌ ํ๊ฒ ํ์ , CMake FetchContent๋ก ๊ฐ์ ธ์ด
๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ผ์ด์ ์ค๋ฅผ ๋ฐ๋ฅธ๋ค.