응애맘마조

230627 강의 본문

공부/3D강의

230627 강의

TH.Wert 2023. 6. 27. 18:57

모델에 뼈를 구성하는 본(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번에 가까운 계산을 하게 되는데 위에 작성했던 대로 버퍼로 저장하지 않으면 이 모델 같은 경우에 그래픽카드에 영향을 주지 않겠지만 같은 모델을 여러 개 출력하거나 정점이 더 많은 모델 출력 시 큰 낭비가 생길 수 있습니다.

 

읽어주셔서 감사합니다.

'공부 > 3D강의' 카테고리의 다른 글

230629 강의  (0) 2023.06.29
230628 강의  (0) 2023.06.28
230626 강의  (0) 2023.06.26
230623 강의  (0) 2023.06.23
230622 강의  (0) 2023.06.22