지금까지의 버퍼들은 정점 버퍼들을 사용했는데, 정적 버퍼의 내용은 초기화 시점에서 고정된다. 반면에 동적 버퍼의 내용은 실행 시점에서 얼마든지 변할 수 있다. 그리고, 매 프레임마다 변하는 경우가 많다. 예를 들어 파도를 구현한다고 하자. 평범한 언덕과는 달리 파도는 시시각각 높이가 변한다. 또한 복잡한 물리 계산과 충돌 검출을 수반하는 입자 시스템에도 동적 정점 버퍼가 필요하다. 매 프레임마다 CPU에서 물리 계산과 추돌 검출을 수행해서 각 입자의 새 위치를 구해야 하기 때문이다. 이처럼 시간의 흐름에 따라 갱신되는 메시를 표현하기 위해서는 동적 정점 버퍼가 필요하다.
버퍼를 동적으로 만들기 위해서라면 버퍼의 용도를 반드시 D3D11_USAGE_DYNAMIC으로 지정해야 한다. 또 CPU에서 버퍼에 자료를 기록해야 하므로 CPU 접근 플래그를 반드시 D3D11_CPU_ACCESS_WRITE로 지정해야 한다.
D3D11_BUFFER_DESC vbd;
vbd. Usage = D3D11_USAGE_DYNAMIC ;
vbd.ByteWidth = sizeof(Vertex) * mWaves.VertexCount();
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbd.MiscFlags = 0;
HR(md3dDevice->CreateBuffer(&vbd, 0, &mWavesVB));
동적 정점 버퍼를 갱신할 때에는 ID3D11DeviceContext::Map 함수로 버퍼의 메모리 블록의 시작을 가리키는 포인터를 얻어서 그 메모리 블록에 자료를 기록하면 된다.
HRESULT ID3DllDeviceContext::Map(
ID3D11Resource *pResource,
UINT Subresource,
D3D11_MAP MapType,
UINT MapFlags,
D3D11_MAPPED_SUBRES0URCE *pMappedResource
);
D3D11_MAPPED_SUBRESOURCE 구조체의 정의는 다음과 같다.
struct D3D11_MAPPED_SUBRESOURCE {
void *pData;
UINT RowPitch;
UINT DepthPitch;
}
다음은 정점 버퍼를 갱신하는 코드의 예시이다.
D3D11_MAPPED_SUBRESOURCE mappedData;
HR(md3dImmediateContext->Map(mWavesVB, 0,
D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
Vertex* v = reinterpret_cast<Vertex*>(mappedData.pData);
for(UINT i = 0; i < mWaves.VertexCount(); ++i)
{
v[i].Pos = mWaves[i];
v[i].Color = XMFLOAT4(O.Of, O.Of, O.Of, l.Of);
}
md3dImmediateContext->Unmap(mWavesVB, 0);
버퍼를 다 갱신한 후에는 반드시 ID3D11DeviceContext::Unmap 메서드를 호출해야 한다. 동적 버퍼를 사용하면 새 자료를 CPU 메모리에서 GPU 메모리로 전송해야 하므로 약간의 추가 부담이 생긴다. 따라서 정적 버퍼로도 가능한 일이라면 동적 버퍼보다는 정적 버퍼를 사용하는 것이 바람직하다.