1. 개발 현황
1. Subdivision
2. Draw Normal Vector
2. 상세 개발 내용
1. Subdivision
void Subdivide(VertexIn inVerts[3], out VertexIn outVerts[6])
{
// 1(5)
// *
// / \
// / \
// m0(1) *-----* m1(3)
// / \ / \
// / \ / \
// *-----*-----*
// 0(0) m2(2) 2(4)
VertexIn m[3];
// 각 변의 중점을 계산
m[0].PosL = 0.5f * (inVerts[0].PosL + inVerts[1].PosL);
m[1].PosL = 0.5f * (inVerts[1].PosL + inVerts[2].PosL);
m[2].PosL = 0.5f * (inVerts[2].PosL + inVerts[0].PosL);
// // 단위 구에 투영
// m[0].PosL = normalize(m[0].PosL);
// m[1].PosL = normalize(m[1].PosL);
// m[2].PosL = normalize(m[2].PosL);
// 법선을 유도
m[0].NormalL = m[0].PosL;
m[1].NormalL = m[1].PosL;
m[2].NormalL = m[2].PosL;
// 텍스처 좌표를 보간
m[0].TexC = 0.5f * (inVerts[0].TexC + inVerts[1].TexC);
m[1].TexC = 0.5f * (inVerts[1].TexC + inVerts[2].TexC);
m[2].TexC = 0.5f * (inVerts[2].TexC + inVerts[0].TexC);
outVerts[0] = inVerts[0];
outVerts[1] = m[0];
outVerts[2] = m[2];
outVerts[3] = m[1];
outVerts[4] = inVerts[2];
outVerts[5] = inVerts[1];
}
void OutputSubdivision(VertexIn v[6], inout TriangleStream<GeoOut> triStream)
{
GeoOut gout[6];
[unroll]
for (int i = 0; i < 6; ++i)
{
// world space로 변환
float4 posW = mul(float4(v[i].PosL, 1.0f), gWorld);
gout[i].PosW = posW.xyz;
gout[i].NormalW = mul(v[i].NormalL, (float3x3) gWorldInvTranspose);
// homogeneous clip space로 변환
gout[i].PosH = mul(posW, gViewProj);
float4 texC = mul(float4(v[i].TexC, 0.0f, 1.0f), gTexTransform);
gout[i].TexC = mul(texC, gMatTransform).xy;
}
// 1(5) 1(5)
// * *
// / \ / \ <- Strip 2 (1 5 3)
// / \ / \
// m0(1) *-----* m1(3) -> m0(1) *-----* m1(3)
// / \ / \ / \ / \
// / \ / \ / 0 \ / \ <- Strip 1 (0 1 2 3 4) -> (0 1 2) / (1 2 3) / (2 3 4)
// *-----*-----* *-----*-----*
// 0(0) m2(2) 2(4) 0(0) m2(2) 2(4)
// 삼각형을 2개의 띠로 그린다.
// 1. 띠 1: 아래쪽 삼각형 세 개
// 2. 띠 2: 위쪽 삼각형 1개
[unroll]
for (int j = 0; j < 5; ++j)
{
triStream.Append(gout[j]);
}
triStream.RestartStrip();
triStream.Append(gout[1]);
triStream.Append(gout[5]);
triStream.Append(gout[3]);
}
[maxvertexcount(8)]
void main(triangle VertexIn gin[3], inout TriangleStream<GeoOut> triStream)
{
VertexIn v[6];
Subdivide(gin, v);
OutputSubdivision(v, triStream);
}
2. Draw Normal Vector
1) Shader
1.1) Vertex Shader:
모델의 위치 정보 전달
1.2) Geometry Shader
vertex shader에서 전달된 위치, 노멀 정보를 바탕으로, 현재 위치와 노멀 방향으로 이동된 두 점을 만들어 pixel shader로 전달
[maxvertexcount(2)]
void main(point NormalGeometryShaderInput input[1], inout LineStream<NormalPixelShaderInput> outputStream)
{
NormalPixelShaderInput output;
float4 posW = mul(input[0].PosL, gWorld);
float4 normalL = float4(input[0].NormalL, 0.0);
float4 normalW = mul(normalL, gWorldInvTranspose); // 노멀벡터의 수직 속성을 유지하기 위해 inv transpose 적용
normalW = float4(normalize(normalW.xyz), 0.0);
output.pos = mul(posW, gViewProj);
output.color = float3(1.0, 1.0, 0.0);
outputStream.Append(output);
output.pos = mul(posW + lineScale * normalW, gViewProj);
output.color = float3(1.0, 0.0, 0.0);
outputStream.Append(output);
}
1.3) Pixel Shader
전달된 위치 정보에 맞춰 색 출력
2) PSO 설정
구현한 Shader와 쌍이 맞는 PrimitiveTopologyType을 선택해주어 오류가 발생하지 않도록 한다. (D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT)
D3D12_GRAPHICS_PIPELINE_STATE_DESC normalPsoDesc
{
/* ID3D12RootSignature* pRootSignature */.pRootSignature = mRootSignature.Get(),
/* D3D12_SHADER_BYTECODE VS */.VS = {reinterpret_cast<BYTE*>(mShaders["normalVS"]->GetBufferPointer()), mShaders["normalVS"]->GetBufferSize()},
/* D3D12_SHADER_BYTECODE PS */.PS = {reinterpret_cast<BYTE*>(mShaders["normalPS"]->GetBufferPointer()), mShaders["normalPS"]->GetBufferSize()},
/* D3D12_SHADER_BYTECODE DS */.DS = {NULL, 0},
/* D3D12_SHADER_BYTECODE HS */.HS = {NULL, 0},
/* D3D12_SHADER_BYTECODE GS */.GS = {reinterpret_cast<BYTE*>(mShaders["normalGS"]->GetBufferPointer()), mShaders["normalGS"]->GetBufferSize()},,
/* D3D12_STREAM_OUTPUT_DESC StreamOutput{ */.StreamOutput = {
/* const D3D12_SO_DECLARATION_ENTRY* pSODeclaration{ */ NULL,
/* UINT Stream; */
/* LPCSTR SemanticName; */
/* UINT SemanticIndex; */
/* BYTE StartComponent; */
/* BYTE ComponentCount; */
/* BYTE OutputSlot; */
/* } */
/* UINT NumEntries; */ 0,
/* const UINT* pBufferStrides; */ 0,
/* UINT NumStrides; */ 0,
/* UINT RasterizedStream; */ 0
/* } */},
/* D3D12_BLEND_DESC BlendState{ */.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT),
/* BOOL AlphaToCoverageEnable */
/* BOOL IndependentBlendEnable */
/* D3D12_RENDER_TARGET_BLEND_DESC RenderTarget[8] */
/* } */
/* UINT SampleMask */.SampleMask = UINT_MAX,
/* D3D12_RASTERIZER_DESC RasterizerState{ */.RasterizerState = { // CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
/* D3D12_FILL_MODE FillMode */ D3D12_FILL_MODE_SOLID, // D3D12_FILL_MODE_WIREFRAME,
/* D3D12_CULL_MODE CullMode */ D3D12_CULL_MODE_BACK,
/* BOOL FrontCounterClockwise */ false,
/* INT DepthBias */ D3D12_DEFAULT_DEPTH_BIAS,
/* FLOAT DepthBiasClamp */ D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
/* FLOAT SlopeScaledDepthBias */ D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
/* BOOL DepthClipEnable */ true,
/* BOOL MultisampleEnable */ false,
/* BOOL AntialiasedLineEnable */ false,
/* UINT ForcedSampleCount */ 0,
/* D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster */ D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF,
/* } */},
/* D3D12_DEPTH_STENCIL_DESC DepthStencilState { */.DepthStencilState = { // CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
/* BOOL DepthEnable */ .DepthEnable = true,
/* D3D12_DEPTH_WRITE_MASK DepthWriteMask */ .DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL,
/* D3D12_COMPARISON_FUNC DepthFunc */ .DepthFunc = D3D12_COMPARISON_FUNC_LESS,
/* BOOL StencilEnable */ .StencilEnable = false,
/* UINT8 StencilReadMask */ .StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK,
/* UINT8 StencilWriteMask */ .StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK,
/* D3D12_DEPTH_STENCILOP_DESC FrontFace { */ .FrontFace = {
/* D3D12_STENCIL_OP StencilFailOp */ .StencilFailOp = D3D12_STENCIL_OP_KEEP,
/* D3D12_STENCIL_OP StencilDepthFailOp */ .StencilDepthFailOp = D3D12_STENCIL_OP_KEEP,
/* D3D12_STENCIL_OP StencilPassOp */ .StencilPassOp = D3D12_STENCIL_OP_KEEP,
/* D3D12_COMPARISON_FUNC StencilFunc */ .StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS
/* } */ },
/* D3D12_DEPTH_STENCILOP_DESC BackFace */ .BackFace = {
/* D3D12_STENCIL_OP StencilFailOp */ .StencilFailOp = D3D12_STENCIL_OP_KEEP,
/* D3D12_STENCIL_OP StencilDepthFailOp */ .StencilDepthFailOp = D3D12_STENCIL_OP_KEEP,
/* D3D12_STENCIL_OP StencilPassOp */ .StencilPassOp = D3D12_STENCIL_OP_KEEP,
/* D3D12_COMPARISON_FUNC StencilFunc */ .StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS
/* } */ },
/* } */ },
/* D3D12_INPUT_LAYOUT_DESC InputLayout{ */.InputLayout = {
/* const D3D12_INPUT_ELEMENT_DESC* pInputElementDescs */ .pInputElementDescs = mInputLayout.data(),
/* UINT NumElements */ .NumElements = (UINT)mInputLayout.size()
/* } */ },
/* D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue */.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED,
/* D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType */.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT, // D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
/* UINT NumRenderTargets */.NumRenderTargets = 1,
/* DXGI_FORMAT RTVFormats[8] */.RTVFormats = {mBackBufferFormat, DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN}, // 0
/* DXGI_FORMAT DSVFormat */.DSVFormat = mDepthStencilFormat,
/* DXGI_SAMPLE_DESC SampleDesc{ */.SampleDesc = {
/* UINT Count; */ .Count = m4xMsaaState ? 4u : 1u,
/* UINT Quality; */ .Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0
/* } */},
/* UINT NodeMask */.NodeMask = 0,
/* D3D12_CACHED_PIPELINE_STATE CachedPSO */.CachedPSO = {NULL, 0},
/* D3D12_PIPELINE_STATE_FLAGS Flags */.Flags = D3D12_PIPELINE_STATE_FLAG_NONE
};
3. TODO
- Subdivision 동작 중 Texture 좌표 전달 오류 수정
4. 참고자료
- Introduction to 3D Game Programming with DirectX 12, Luna, Frank (2016)
728x90
반응형
'---------개인공부-------- > |DirectX (C++)|' 카테고리의 다른 글
[DirectX12] Imgui Render Target 출력 (0) | 2025.01.22 |
---|---|
[DirectX] Imgui Texture Image 출력 (0) | 2025.01.21 |
[DirectX] 3D 엔진 개발 현황 (0) | 2025.01.20 |