ModelAnimator
텍스처로 만들어 보내야 한다. 하지만 문제가 있다.
텍스처에서 사용하고 있는 자료형은 최대 R32G32B32A32 4 + 4 + 4 + 4 = 16Byte를 사용하고 있다. 그런데 지금 저장하려고 하는 자료형은 4X4 FLOAT 행렬로 64Byte를 사용하고 있다. 그럼 어떻게 해야 할까
생각보다 간단하다 1칸이 아닌 4칸에 데이터를 저장하면 된다.
이렇게 되어있기 때문에 각 페이지는 MAX_MODEL_TRANSFORMS * 4 * MAX_MODEL_KEYFRAMES * 16 = 8000000byte 총 8MB가 나온다.
이 부분에 다른 문제가 발생한다. 이 데이터를 GPU에 만들어 보내려면 스택에서 만들어 보내야 하는데 우리가 사용하는 동적할당(new, malloc)의 경우에는 최대 스택(default : 2MB)이 정해져있다. 스텍 크기를 늘리면 되지만, 그렇다고 너무 늘리면 스택을 관리하기 힘들어지기 때문에 안좋다.출처
이렇게 에러가 나온다.
그래서 VirtualAlloc을 사용해서 할당받아야 한다.
- VirtualAlloc
- RESERVE
- Process주소공간에 대하여 추후 사용할 영역을 미리 할당하여 차후 물리적 저장소와 매칭 될 수 있도록 준비작업을 하는것
- COMMIT
- RESERVE를 통해 예약한 공간을 실제 사용하기 위해 물리적 저장소를 할당하고 할당된 영역과 예약된 주소곡ㅇ간간에 매핑 작업을 수행해준다.
- RESERVE
원하는 크기의 공간을 미리 할당 받지만, 예약만 하고 나중에 물리적으로 채워 넣는다.
ModelAnimator.cpp
void ModelAnimator::CreateTexture()
{
//Matrix matrix[MAX_MODEL_KEYFRAMES][MAX_MODLE_TRANSFORMS];
clipTransforms = new ClipTransforms[model->ClipCount()];
for (UINT i = 0; i < model->ClipCount(); i++)
{
CreateClipTransform(i);
}
// Create Texture
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = MAX_MODEL_TRANSFORMS * 4;
desc.Height = MAX_MODEL_KEYFRAMES;
desc.ArraySize = model->ClipCount(); // Array는 동적 할당 X 하지만 width height는 가능
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; // 16byte * 4 = 64byte
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
UINT pageSize = MAX_MODEL_TRANSFORMS * 4 * MAX_MODEL_KEYFRAMES * 16;
// malloc은 스텍의 한계가 있음 (2mb)
void* p = VirtualAlloc(NULL, pageSize * model->ClipCount(), MEM_RESERVE, PAGE_READWRITE);
// MEMORY_BASIC_INFORMATION
for (UINT c = 0; c < model->ClipCount(); c++)
{
UINT start = c * pageSize;
for (UINT k = 0; k < MAX_MODEL_KEYFRAMES; k++)
{
void* temp = (BYTE *)p + MAX_MODEL_TRANSFORMS * k * sizeof(Matrix) + start;
VirtualAlloc(temp, MAX_MODEL_TRANSFORMS * sizeof(Matrix), MEM_COMMIT, PAGE_READWRITE);
memcpy(temp, clipTransforms[c].Transform[k], MAX_MODEL_TRANSFORMS * sizeof(Matrix));
}
}// for(c)
D3D11_SUBRESOURCE_DATA* subResources = new D3D11_SUBRESOURCE_DATA[model->ClipCount()];
for (UINT c = 0; c < model->ClipCount(); c++)
{
void* temp = (BYTE *)p + c * pageSize;
subResources[c].pSysMem = temp;
subResources[c].SysMemPitch = MAX_MODEL_TRANSFORMS * sizeof(Matrix);
subResources[c].SysMemSlicePitch = pageSize;
}
Check(D3D::GetDevice()->CreateTexture2D(&desc, subResources, &texture));
SafeDeleteArray(subResources);
VirtualFree(p, 0, MEM_RELEASE);
}
//Create SRV
{
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MipLevels = 1;
desc.Texture2DArray.ArraySize = model->ClipCount();
Check(D3D::GetDevice()->CreateShaderResourceView(texture, &desc, &srv));
}
for (ModelMesh* mesh : model->Meshes())
{
mesh->TransformsSRV(srv);
}
}
텍스처를 생성해주는 부분이다. 값을 읽어오고 그 값들을 GPU에 텍스처로 만들어 보내준다.
텍스처는 1D,2D,3D가 있으며 각 텍스처는 Array가 있다 하지만, 이 Array는 동적할당이 불가능하기 때문이 미리 크기를 정해줘야 한다.
width는 위에 말한 대로 크기를 * 4 해주고 Height는 열 ArraySize는 Clip의 갯수를 넣어준다.
그리고 각 페이지 크기를 할당받는다.
그리고 각 클립마다 열을 돌아다니며 행의 값들을 넣어준다.
그리고 서브리소스에 이 값을 넣어 GPU로 보내주고 할당받은 주소를 해제해준다.
마지막으로 쉐이더 리소스 뷰를 만들어 넘겨준다.
TransformsSRV 이것은 Mesh에
ID3D11ShaderResourceView* transformsSRV = NULL;
ID3DX11EffectShaderResourceVariable* sTransformsSRV;
만들어 주고 렌더링에 넣어준다. TransformsSRV은 쉐이더의 TransformsMap을 참조한다.