Direct3D의 그리기 연산

3 minute read

Direct3D의 그리기 연산

정점과 입력 배치

원하는 자료를 담기 위해 정점 구조체를 정의

정점 구조체의 각 필드로 무엇을 해야하는지 Direct3D에 알려주기 위해 입력 배치 서술을 사용

입력 배치 서술은 INPUT_LAYOUT_DESC라는 구조체로 대표되며 그 안에는 D3D12_INPUT_ELEMENT_DESE 구조체를 담고 있다. 이 구조체는 정점 구조체의 성분들과 일대일 대응 되어야하기 때문에 정점 구조체 성분의 갯수와 동일해야한다.

정점 버퍼

정점들을 저장하는 버퍼

ID3D12Device::CreateCommittedResource 메서드를 이용하여 ID3D12Resource 객체를 생성

정점 버퍼를 초기화하기 위해서는 임시 업로드용 버퍼 자원을 생성해야한다. CPU 메모리에서 GPU 메모리로 자료를 복사하기 위해 업로드 힙에 자원을 맡긴다.

정점 버퍼를 파이프라인에 묶기 위해서는 정점 버퍼 뷰가 필요하다.

정점 버퍼 뷰는 RTV(렌더 대상 뷰)와 달리 서술자 힙이 필요하지 않다.

ID3D12GraphicsCommandList::IASetVertexBuffers 메소드를 이용하여 정점 버퍼를 파이프라인에 묶는다.

여러 개의 정점 버퍼들을 여러개의 입력슬롯에 묶을 수 있다.

정점들을 실제로 그리기 위해서는 ID3D12GraphicsCommandList::DrawInstanced 메소드를 호출해야 한다.

ID3D12GraphicsCommandList::IASetPrimitiveTopology 메서드를 이용하여 기본 도형 위상구조 상태를 결정한다.(점, 선목록, 삼각형 목록 등으로 취급할지)

색인과 색인 버퍼

색인(index)들을 담는 버퍼를 색인 버퍼라고 한다.

d3dUtil::CreateDefaultBuffer 함수를 통해 버퍼를 생성한다.

D3D12_INDEX_BUFFER_VIEW 구조체가 색인 버퍼 뷰를 대표하며 색인 버퍼 뷰 또한 서술자 힙이 필요 없다.

색인들을 이용해서 기본도형을 그리려면 DrawInstanced 메서드가 아닌 ID3D12GraphicsCommnacList::DrawIndexedInstanced 메서드를 사용해야한다.

여러개의 도형을 하나의 정점 버퍼와 색인 버퍼를 이용하여 그릴때는 전역 정점 버퍼에 맞게 색인들을 다시 계산해야한다.

그 후 다시 계산한 정점과, 색인의 위치 값을 DrawIndexedInstanced의 매개변수에 적절히 입력해야한다.

정점 셰이더

셰이더는 HSLS언어로 작성

정점 셰이더의 각 매개변수와 정점 성분(D3D12_INPUT_ELEMENT_DESC 배열을 이용)에 의미소를 부여하여 서로를 대응시킨다. ex) POSITION, COLOR 입력서명과 정점 자료가 일치하지 않으면 에러가 발생한다.

모든 경우에 에러가 생기지는 않고 정점 셰이더에서 사용하는데 정점 자료가 제공되지 않을때 에러 발생(없는데 사용하려고 하는 경우)

픽셀 셰이더

픽셀 단편마다 실행되며 주어진 입력으로부터 픽셀 단편의 색상을 계산한다.

상수 버퍼

셰이더 프로그램에서 참조하는 자료를 담는 GPU 자원

상수버퍼의 크기는 최소 하드웨어 할당 크기(256바이트)의 배수이어야한다.

d3dUtil::CalcConstantBufferByteSize 메서드는 최소 하드웨어 할당 크기의 배수가 되게 하는 계산을 수행해 준다.

구조체가 256바이트 경계에 맞게 채워지지 않았다면 바이트들이 경계에 맞도록 암묵적으로 채워진다.(명시적으로 256바이트 경계를 맞출수도 있다)

업로드 버퍼 보조 클래스의 CopyData 메서드를 이용하여 업로드 버퍼의 내용을 쉽게 변경 할수 있다.

업로드 버퍼 보조 클래스를 상수버퍼로 사용할 때에는 isConstantBuffer 매개 변수를 true로 설정해야 각 상수 버퍼가 256바이트의 배수가 되도록 바이트를 채운다.

상수 버퍼 서술자를 저장하기 위해서는 서술자 힙이 필요하다.

D3D12_DESCRIPTOR_HEAP_DESC 를 사용한다.

루트 서명과 서술자 테이블

렌더링 파이프라인에 묶어야 하는 자원들이 무엇이고 그 자원들이 셰이더 입력 레지스터들에 어떻게 대응되는지 정의하는것

셰이더에서 사용하는 모든 자원을 제공해줘야한다.

루트 서명은 자원을 서술하는 루트 매개변수들의 배열로 정의된다.

루트 매개변수의 종류는 루트 상수, 루트 서술자, 서술자 테이블로 구분된다.

루트 상수와 루트 서술자는 7장에서 서술

CD3DX12_ROOT_PARAMETER 와 CD3DX12_DESCRIPTOR_RANGE를 이용하여 서술자 테이블을 생성한다.

생성 후 초기화 과정을 거치면 루트 서명을 설정 할 수 있다.

루트서명이 실제로 자원들을 렌더링 파이프라인에 묶지는 않기 때문에 ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable 메서드를 호출하여 서술자 테이블을 파이프라인에 묶을 수 있다.

셰이더의 컴파일

프로그램 실행시에 셰이더를 컴파일 하는 방법과 빌드과정에 컴파일하는 방법이 있다.

래스터화기 상태

D3D12_RASTERIZER_DESC 구조체의 값을 변경하여 와이어 프레임 렌더링 등과 같은 모드를 설정할 수 있다.

파이프라인 상태 객체

렌더링 파이프라인의 상태를 제어하는 대부분의 객체는 PSO(pipline state object)라고 부르는 집합체를 통해서 지정된다.

D3D12_GRAPHICS_PIPELINE_STATE_DESC 구조체 인스턴스를 채운 후 ID3D12Device::CreateGraphicsPipelineState 메서드를 이용하여 ID3D12PipelineState 객체를 생성한다.

기하구조 보조 구조체

정점 버퍼와 색인 버퍼를 한데 엮는 보조 구조체

MeshGeometry

예제 연습

연습문제 4번 - 사각뿔 그리기

책의 예제인 상자의 정점과 색인을 변경하여 사각뿔을 그릴 수 있었다.

piramid

연습문제 6번 - 정점을 게임 시간에 따라 주기적으로 변형하기(정점 셰이더)

상수 버퍼 변수 gTime을 추가하고 GameTimer::TotalTime 메소드의 값이 gTime에 갱신되도록 상수 버퍼를 갱신하여 주기적으로 변형되도록 설정할 수 있었다.

gTime

연습문제 7번 - 상자의 정점과 사각뿔의 정점을 하나의 정점 버퍼로 통합하고 색인 버퍼도 마찬가지로 통합하여 두개의 도형을 그리기, 도형을 겹치지 않게 하기

연습문제 8번 - 상자를 와이어프레임 모드로 렌더링하기

연습문제 7번은 두개의 도형을 그리기는 성공하였으나 도형이 겹치는 것을 해결하지 못하여 와이어 프레임 모드로 렌더링하여 두개의 도형이 그려진것을 확인하였다.

7장에 여러가지 도형을 그리는 내용이 있기 때문에 7장을 공부하고 다시 연습하기로 하였다.

two