응애맘마조
230627 강의 본문
모델에 뼈를 구성하는 본(bone)에 대해서 강의했었습니다. 모델은 T-Pose가 기본자세이며 여기에서 위치 변경이나 애니메이션 효과를 계산합니다. 만약 다른 자세가 기본자세라면 한쪽이 너무 치우치거나 원하는 모습대로 나오지 않을 수 있습니다.
#pragma once
#define MAX_BONE 256
class Skeleton
{
static ID3D11Buffer* bonesBuffer;
public:
Skeleton() {};
Matrix bones[MAX_BONE];
Matrix bonesOffset[MAX_BONE];
string file;
void BonesUpdate(GameObject* node);
static void CreateStaticMember();
static void DeleteStaticMember();
virtual void Set();
void LoadFile(string file);
void SaveFile(string file);
};
#include "framework.h"
ID3D11Buffer* Skeleton::bonesBuffer = nullptr;
void Skeleton::BonesUpdate(GameObject* node)
{
if (node->root->skeleton)
{
bones[node->boneIndex] = node->W;
for (auto it = node->children.begin(); it != node->children.end(); it++)
BonesUpdate(it->second);
}
}
void Skeleton::CreateStaticMember()
{
D3D11_BUFFER_DESC desc = { 0 };
desc.ByteWidth = sizeof(Matrix) * MAX_BONE;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;
HRESULT hr = D3D->GetDevice()->CreateBuffer(&desc, NULL, &bonesBuffer);
D3D->GetDC()->VSSetConstantBuffers(2, 1, &bonesBuffer);
assert(SUCCEEDED(hr));
}
void Skeleton::DeleteStaticMember()
{
SafeRelease(bonesBuffer);
}
void Skeleton::Set()
{
{
D3D11_MAPPED_SUBRESOURCE mappedResource;
D3D->GetDC()->Map(bonesBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
memcpy_s(mappedResource.pData, sizeof(Matrix) * MAX_BONE, &bones, sizeof(Matrix) * MAX_BONE);
D3D->GetDC()->Unmap(bonesBuffer, 0);
}
}
void Skeleton::LoadFile(string file)
{
this->file = file;
BinaryReader in;
wstring path = L"../Contents/Skeleton/" + Util::ToWString(file);
in.Open(path);
for (int i = 0; i < MAX_BONE; i++)
{
bones[i] = in.matrix();
}
for (int i = 0; i < MAX_BONE; i++)
{
bonesOffset[i] = in.matrix();
}
in.Close();
}
void Skeleton::SaveFile(string file)
{
this->file = file;
BinaryWriter out;
wstring path = L"../Contents/Skeleton/" + Util::ToWString(file);
out.Open(path);
for (int i = 0; i < MAX_BONE; i++)
{
out.matrix(bones[i]);
}
for (int i = 0; i < MAX_BONE; i++)
{
out.matrix(bonesOffset[i]);
}
out.Close();
}
프레임워크에 따로 Skeleton헤더와 cpp 파일을 추가했습니다. 시간 부족으로 완성되지는 못했고 내일 완성됩니다. T-Pose를 기본으로 한 번만 저장하기 위해 static으로 된 버퍼로 저장했습니다. 움직임이 생길 때마다 루트부터 다시 SRT를 하기엔 낭비가 너무 심하기 때문입니다. 오프셋에서는 각 모델의 파츠별로 원점으로 위치시킨 후 월드 좌표로 다시 재배치를 하게 됩니다. 하지 않게 되면 bone의 위치가 맞지 않고 원래 모델도 크게 나오는데 bone은 이 모델보다 더 크게 위치할 수 있기 때문입니다. ImGui에 bone이 몇 번째 bone인지 볼 수 있게 했습니다. 이전에 출력했던 Boss의 경우 70번이 넘어가는 걸 확인했습니다. 거의 100번에 가까운 계산을 하게 되는데 위에 작성했던 대로 버퍼로 저장하지 않으면 이 모델 같은 경우에 그래픽카드에 영향을 주지 않겠지만 같은 모델을 여러 개 출력하거나 정점이 더 많은 모델 출력 시 큰 낭비가 생길 수 있습니다.
읽어주셔서 감사합니다.