• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 24일차(ModelAnimator - CreateTexture)

30 Jun 2021

Reading time ~2 minutes

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를 통해 예약한 공간을 실제 사용하기 위해 물리적 저장소를 할당하고 할당된 영역과 예약된 주소곡ㅇ간간에 매핑 작업을 수행해준다.

원하는 크기의 공간을 미리 할당 받지만, 예약만 하고 나중에 물리적으로 채워 넣는다.

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을 참조한다.



DirectX Share Tweet +1