정적 버퍼의 내용은 초기화 시점에서 고정되지만, 동적 버퍼의 내용은 실행 시점에서 얼마든지 변할 수 있다. 예를 들어 파도 시뮬레이션에서 필요할 것이다. 파도는 시간의 흐름에 따라 높이가 바뀔것이다. 시간은 프레임이 될 것이고 정해진 프레임마다 파도의 정점의 위치는 바꿔야 하낟. 바뀐 정점의 위치들을 반영하기 위해서는 동적 정점 버퍼가 필요하다.
버퍼를 동적으로 만들기 위해서 버퍼의 용도를 D3D11_USAGE_DYNAMIC으로 지정해야 한다. 또한 CPU에서 버퍼에 자료를 기록해야 하므로 CPU 접근 플래그를 반드시 D3D11_CPU_ACCESS_WRITE로 지정해야 한다.
D3D11_BUFFER_DESC desc;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = sizeof(Vertex) * mWaves.VertexCount();
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
HR(md3dDevice->CreateBuffer(&buffer, 0, &mWavesBuffer);
동적 정점 버퍼를 갱신할 때는 ID3D11DeviceContext::Map 메소드를 호출해야 한다.
HRESULT ID3D11DeviceContext::Map(
ID3D11Resource* pResource,
UINT Subresource,
D3D11_MAP MapType,
UINT MapFlags,
D3D11_MAPPED_SUBRESOURCE* pMappedResource
);
1.pResource : 접근을 원하는 자원을 가리키는 포인터
2.Subresource : 자원에 담긴 부분자원의 인덱스
3.MapType : 자원에 대한 CPU의 읽기 및 쓰기 권한을 지정(*주 1)
4.MapFlags : GPU가 사용 중일 때 CPU가 수행하는 작업을 지정하는 플래그
5.pMappedResource : 버퍼에 자료를 기록하거나 읽는 구조체를 가리키는 포인터 반환(*주 2)
버퍼를 갱신한 후에는 반드시 ID3D11DeviceContext::Unmap 메소드를 호출해야 한다.
void ID3D11DeviceContext::Unmap(ID3D11Resource* pResource, UINT Subresource);
1.pResource : 갱신한 자원을 가리키는 포인터
2.Subresource : 매핑 해체할 자원에 담긴 부분자원의 인덱스
아래의 코드는 정점 버퍼를 갱신하는 과정이다.
D3D11_MAPPED_SUBRESOURCE subResource;
Vertex* v = reinterpret_cast<Vertex*>(subResource.pData);
HR(md3dImmediateContext->Map(mWavesBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource));
{
for (UINT i = 0; i < mWaves.VertexCount(); ++i)
{
v[i].Pos = mWaves[i];
v[i].Color = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
}
}
md3dImmediateContext->Unmap(mWavesBuffer, 0);
동적 버퍼를 사용하면 새 자료를 CPU 메모리에서 GPU 메모리로 전송해야 하므로 추가 비용이 생긴다. 정적 버퍼로 가능한 일이라면 동적 버퍼보단 정적 버퍼를 사용하는 것이 바람직하다. Direct3D는 동적 버퍼의 필요성을 줄여주는 새로운 기능들이 추가되었다.
- 간단한 애니메이션은 정점 셰이더에서 수행할 수 있다.
- 텍스처로의 렌더링 기능 또는 계산 셰이더, 그리고 정점 텍스처 조회 기능을 사용하면 전적으로 GPU에서 실행하는 것이 가능하다.
- 기하 셰이더를 이용하면, 예전에는 CPU에서 수행해야 했던 기본도형의 생성 및 파괴 작업을 GPU에서 수행할 수 있다.
(*주 1)D3D11_MAP 열거형
CPU에서 읽고 쓰기 위해서 액세스할 리소스를 식별한다.
typedef enum D3D11_MAP
{
D3D11_MAP_READ = 1,
D3D11_MAP_WRITE = 2,
D3D11_MAP_READ_WRITE = 3,
D3D11_MAP_WRITE_DISCARD = 4,
D3D11_MAP_WRITE_NO_OVERWRITE = 5
};
D3D11_MAP_READ : 자원이 읽기용으로 매핑된다. 읽기 액세스 권한으로 생성되어야 한다(D3D11_CPU_ACCESS_READ).
D3D11_MAP_WRITE : 자원이 쓰기용으로 매핑된다. 쓰기 액세스 권한으로 생성되어야 한다(D3D11_CPU_ACCESS_WRITE).
D3D11_MAP_READ_WRITE : 자원이 읽기 및 쓰기용으로 매핑된다. 읽기 및 쓰기 권한으로 생성되어야 한다.(D3D11_CPU_ACCESS_READ 및 D3D11_CPU_ACCESS_WRITE)
D3D11_MAP_WRITE_DISCARD : 자원이 쓰기용으로 매핑된다. 이전 내용은 정의되지 않는다. 쓰기 액세스 및 동적 사용으로 생성되어야 한다(D3D11_CPU_ACCESS_WRITE 및 D3D11_USAGE_DYNAMIC).
D3D11_MAP_WRITE_NO_OVERWRITE : 자원이 쓰기용으로 매핑된다. 기존 내용을 덮어쓸 수 없다. 정점 및 인덱스 버퍼에서만 유요하다. 쓰기 액세스 권한으로 생성되어야 한다(D3D11_CPU_ACCESS_WRITE). D3D11_BIND_CONSTANT_BUFFER 플래그로 생성된 자원에는 사용할 수 없다.
(*주 2)D3D11_MAPPED_SUBRESOURCE 구조체
하위 리소스 데이터에 대한 액세스를 제공한다.
typedef struct D3D11_MAPPED_SUBRESOURCE
{
void *pData;
UINT RowPitch;
UINT DepthPitch;
} D3D11_MAPPED_SUBRESOURCE;
1.pData : 읽고 쓸 수 있는 자원의 메모리 블록을 가리키는 포인터. 자원에 담긴 자료에 맞는 형식으로 캐스팅할 필요가 있다.
2.RowPitch : 자원의 자료 한 줄의 byte 단위.
3.DepthPitch : 자원의 자표 한 페이지의 byte 단위
RowPitch와 DepthPitch의 차이는 쉽게 생각해서 3차원 배열의 행과 높이라고 생각하면 된다.
'서적 정리 > DirectX11을 이용한 3D 게임 프로그래밍 입문' 카테고리의 다른 글
59.람베르트의 코사인 법칙(Lambert's cosine law) (0) | 2022.03.02 |
---|---|
58.법선 벡터(Normal Vector) (0) | 2022.03.01 |
57.빛과 재질의 상호작용 (0) | 2022.03.01 |
56.Direct3D의 그리기 연산 요약 (0) | 2022.02.21 |
54.파일에서 기하구조 불러오기 (0) | 2022.02.15 |
53.도형 예제 (0) | 2022.02.15 |
52.언덕 예제 (0) | 2022.02.15 |
51.상자 예제 (0) | 2022.02.15 |
댓글