🎨DirectX

[DX] Animator 작업 : Create Texture (Texture2D)

공대 컴린이 2023. 6. 27. 11:37
728x90

Texture의 Format은 일반적으로 R,G,B,A (각각 1비트, 총 4바이트 = R8G8B8A8)를 사용한다.

DX11부터는 R32G32B32A21 - Float 자료형을 사용할 수 있다. 각각 RGBA 값이 4바이트를 가져 총 16바이트로 구성된다. UNORM이 붙으면 0~1까지 값을 사용하고, NORM 이 붙으면 -1~1 까지의 값을 사용한다.

 

그러나 해당 자료형을 사용하면 만들고자했던 Texture에 문제가 생긴다.

만들고자했던 Texture의 행에는 keyframe에 해당하는 Bone의 행렬을 적고, 열에는 Bone의 정보를 써서 행과 열에 들어가는 값이 Bone이 된다. 

 

이때 Bone 행렬 하나는 64바이트인데, Texture의 픽셀 하나가 쓸 수 있는 값은 16바이트라서 문제가 생긴다.

이러한 문제를 해결하기 위해 64바이트인 Bone행렬 하나를 떼어서 4칸으로 나눠 0행, 1행, 2행, 3행으로 나누어  사용하고, Shader에서 다시 하나의 행으로 만들어 사용하였다.

 

넓이를 잡을 때는 Bone Transform * 4가 곱해져야 픽셀 하나당 최댓값이었던 16바이트가 64바이트가 될 수 있다.

 

 

Texture에는 Texture1D가 있고 그에 해당하는 Array가 있다. Texture2D도 있고 그에  상응하는 Array가 있다. Texture3D도 마찬가지로 상응하는 Array가 있다.

 

상응하는 Array라는게 무슨 말이냐면, Array Size를 쓰면 Array가 먹혀서(?) Array 값은 Texture2DArray가 된다.

Texture2D에서 Array가 붙는 명령값들은 Dynamic으로 절대 사용할 수 없다. (나는 Immutable로 사용하기 때문에 상관없긴 하다)

애니메이션을 굳이 편집하고 싶다면 Usage가 Dynamic이 되어야 하기 때문에, 한 단계 위인 Texture3D를 사용하면 된다.

Texture2D나 Texture3D는 별 차이없이 비슷하게 사용할 수 있다.

 

위와 같은 개념들을 토대로, Texture2D를 만들기 위한 DESC 변수를 초기화 해 주었다.

📄 CreateTexture

void ModelAnimator::CreateTexture()
{
	clipTransforms = new ClipTransform[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_KEYFRAMES * 4;				// Texture의 넓이에는 Bone 값이 들어간다.
		desc.Height = MAX_MODEL_KEYFRAMES;
		desc.ArraySize = model->ClipCount();
		desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;		// 16Byte * 4 = 64Byte (쪼개서 다시 가져오는건 Shader에서 처리)
		desc.Usage = D3D11_USAGE_IMMUTABLE;
		desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
		desc.MipLevels = 1;
		desc.SampleDesc.Count = 1;

		// 한 면의 크기는 Transform에 픽셀 하나 당 16Byte가 4개씩 들어가고, 행렬이니 16을 곱하면 된다.
		// pageSize = 250(Transforms) * 4 * 16 * 500(Keyframes) = 8,000,000 (8메가) -> malloc으로 복사 불가능 + 스택오버플로우
		UINT pageSize = MAX_MODEL_TRANSFORMS * 4 * 16 * MAX_MODEL_KEYFRAMES;
		//void* p = malloc(pageSize * model->ClipCount());
		void* p = VirtualAlloc(NULL, pageSize * model->ClipCount(), MEM_RESERVE, PAGE_READWRITE);

		// MEMORY_BASIC_INFORMATION, VirtualQuery : 실제로 예약한 사이즈를 알 수 있다.

		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; // (BYTE*)를 void*로 정의하여 1바이트 넘기도록 설정

				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(int 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);
	}
}

 

 

728x90