응애맘마조
230630 강의 본문
어제 애니메이션 로드에 실패했지만 오늘 성공했습니다. 스켈레톤 클래스를 제거하고 애니메이션 클래스를 따로 만들어서 프레임과 뼈대를 합치게 되었습니다.
#pragma once
#define MAX_BONE 256
class Animation
{
public:
UINT frameMax;
UINT boneMax;
Matrix** arrFrameBone;
float tickPerSecond;
string file;
Animation();
~Animation();
void LoadFile(string file);
void SaveFile(string file);
};
class Animations
{
private:
static shared_ptr<Animation> TPose;
public:
static void CreateStaticMember();
static void DeleteStaticMember();
private:
ID3D11Buffer* frameBuffer;
struct AnimBuffer
{
Matrix Frame[MAX_BONE];
};
public:
Animations();
~Animations();
void Set();
void RenderDetail();
vector<shared_ptr<Animation>> playList;
int aniFrame = 0;
int aniIdx = 0;
};
#include "framework.h"
Animation::Animation()
{
frameMax = 0;
boneMax = 0;
tickPerSecond = 0;
arrFrameBone = nullptr;
file = "";
}
Animation::~Animation()
{
for (UINT i = 0; i < frameMax; i++)
{
delete[] arrFrameBone[i];
}
delete[] arrFrameBone;
}
void Animation::LoadFile(string file)
{
this->file = file;
BinaryReader in;
wstring path = L"../Contents/Animation/" + Util::ToWString(file);
in.Open(path);
frameMax = in.Int();
boneMax = in.Int();
tickPerSecond = in.Float();
arrFrameBone = new Matrix * [frameMax];
for (UINT i = 0; i < frameMax; i++)
{
arrFrameBone[i] = new Matrix[MAX_BONE];
}
for (UINT i = 0; i < frameMax; i++)
{
for (UINT j = 0; j < boneMax; j++)
{
arrFrameBone[i][j] = in.matrix();
}
}
in.Close();
}
void Animation::SaveFile(string file)
{
this->file = file;
BinaryWriter out;
wstring path = L"../Contents/Animation/" + Util::ToWString(file);
out.Open(path);
out.Int(frameMax);
out.Int(boneMax);
out.Float(tickPerSecond);
for (UINT i = 0; i < frameMax; i++)
{
for (UINT j = 0; j < boneMax; j++)
{
out.matrix(arrFrameBone[i][j]);
}
}
out.Close();
}
void Animations::Set()
{
if (playList.size() > 0)
{
D3D11_MAPPED_SUBRESOURCE mappedResource;
D3D->GetDC()->Map(frameBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
memcpy_s(mappedResource.pData, sizeof(AnimBuffer), playList[aniIdx]->arrFrameBone[aniFrame], sizeof(AnimBuffer));
D3D->GetDC()->Unmap(frameBuffer, 0);
}
D3D->GetDC()->VSSetConstantBuffers(2, 1, &frameBuffer);
}
Animations::Animations()
{
D3D11_BUFFER_DESC desc = { 0 };
desc.ByteWidth = sizeof(AnimBuffer);
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, &frameBuffer);
assert(SUCCEEDED(hr));
}
Animations::~Animations()
{
for (int i = 0; i < playList.size(); i++)
{
SafeReset(playList[i]);
}
SafeRelease(frameBuffer);
}
shared_ptr<Animation> Animations::TPose = nullptr;
void Animations::CreateStaticMember()
{
}
void Animations::DeleteStaticMember()
{
}
애니메이션의 헤더와 cpp파일입니다. 여기에서 T-Pose를 저장하고 애니메이션을 받아옵니다.
#pragma once
class Main : public Scene
{
private:
Camera* Cam;
Grid* grid;
Actor* temp;
string file;
Assimp::Importer importer;
const aiScene* scene;
vector<map<string, Matrix>> aniMap;
shared_ptr<Animation> Anim;
Matrix bonesOffset[MAX_BONE];
public:
Main();
~Main();
virtual void Init() override;
virtual void Release() override; //해제
virtual void Update() override;
virtual void LateUpdate() override;//갱신
virtual void Render() override;
virtual void PreRender() override;
virtual void ResizeScreen() override;
void MakeHierarchy(aiNode* node, GameObject* node2);
void MakeMesh(aiNode* node, GameObject* node2);
void MakeAnim( GameObject* node ,int frame);
void MakeMaterial();
Matrix ToMatrix(aiMatrix4x4& value)
{
return Matrix
(
value.a1, value.b1, value.c1, value.d1,
value.a2, value.b2, value.c2, value.d2,
value.a3, value.b3, value.c3, value.d3,
value.a4, value.b4, value.c4, value.d4
);
};
void ReadBoneData(aiMesh* mesh, vector<class VertexWeights>& vertexWeights);
};
#define MAX_WEIGHTS 4
struct VertexWeights
{
UINT boneIdx[MAX_WEIGHTS];
float boneWeights[MAX_WEIGHTS];
VertexWeights()
{
ZeroMemory(boneIdx, sizeof(UINT) * MAX_WEIGHTS);
ZeroMemory(boneWeights, sizeof(float) * MAX_WEIGHTS);
}
void AddData(UINT boneId, float weight)
{
for (UINT i = 0; i < MAX_WEIGHTS; i++)
{
if (boneWeights[i] == 0.0f)
{
boneIdx[i] = boneId;
boneWeights[i] = weight;
return;
}
}
}
void Normalize()
{
float total = 0.0f;
for (UINT i = 0; i < MAX_WEIGHTS; i++)
{
if (boneWeights[i] != 0.0f)
{
total += boneWeights[i];
}
}
for (UINT i = 0; i < MAX_WEIGHTS; i++)
{
if (boneWeights[i] != 0.0f)
{
boneWeights[i] /= total;
}
}
}
};
struct AnimPosition
{
float time;
Vector3 pos;
};
struct AnimScale
{
float time;
Vector3 scale;
};
struct AnimRotation
{
float time;
Quaternion quater;
};
struct AnimNode
{
string name;
//각 벡터 사이즈가 다를수있다.
vector<AnimPosition> position;
vector<AnimScale> scale;
vector<AnimRotation> rotation;
};
namespace Interpolated
{
Vector3 CalcInterpolatedScaling(AnimNode* iter, float time, int Duration);
Quaternion CalcInterpolatedRotation(AnimNode* iter, float time, int Duration);
Vector3 CalcInterpolatedPosition(AnimNode* iter, float time, int Duration);
int FindScale(AnimNode* iter, float time);
int FindRot(AnimNode* iter, float time);
int FindPos(AnimNode* iter, float time);
}
#include "stdafx.h"
#include "Main.h"
Main::Main()
{
}
Main::~Main()
{
}
void Main::Init()
{
Cam = Camera::Create();
Cam->LoadFile("Cam.xml");
Camera::main = Cam;
Cam->width = App.GetWidth();
Cam->height = App.GetHeight();
Cam->viewport.width = App.GetWidth();
Cam->viewport.height = App.GetHeight();
grid = Grid::Create();
temp = Actor::Create();
}
void Main::Release()
{
}
void Main::Update()
{
ImGui::Begin("Hierarchy");
Cam->RenderHierarchy();
temp->RenderHierarchy();
grid->RenderHierarchy();
ImGui::End();
if (GUI->FileImGui("ModelImporter", "ModelImporter",
".fbx,.obj,.x", "../Assets"))
{
file = ImGuiFileDialog::Instance()->GetCurrentFileName();
string path = "../Assets/" + file;
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
scene = importer.ReadFile
(
path,
aiProcess_ConvertToLeftHanded
| aiProcess_Triangulate
| aiProcess_GenUVCoords
| aiProcess_GenNormals
| aiProcess_CalcTangentSpace
);
assert(scene != NULL and "Import Error");
temp->ReleaseMember();
MakeMaterial();
GameObject* empty = GameObject::Create("empty");
temp->AddBone(empty);
temp->Update();
MakeHierarchy(scene->mRootNode, empty);
MakeMesh(scene->mRootNode, empty);
SafeDelete(temp->animations);
temp->animations = new Animations();
importer.FreeScene();
}
if (GUI->FileImGui("AnimationImporter", "AnimationImporter",
".fbx,.obj,.x", "../Assets"))
{
file = ImGuiFileDialog::Instance()->GetCurrentFileName();
string path = "../Assets/" + file;
importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
scene = importer.ReadFile
(
path,
aiProcess_ConvertToLeftHanded
| aiProcess_Triangulate
| aiProcess_GenUVCoords
| aiProcess_GenNormals
| aiProcess_CalcTangentSpace
);
assert(scene != NULL and "Import Error");
//애니메이션 갯수 i
for (UINT i = 0; i < scene->mNumAnimations; i++)
{
Anim = make_shared<Animation>();
aiAnimation* srcAnim = scene->mAnimations[i];
size_t tok2 = file.find_last_of(".");
Anim->file = file.substr(0, tok2) + to_string(i);
Anim->frameMax = (int)srcAnim->mDuration + 1;
Anim->tickPerSecond = srcAnim->mTicksPerSecond != 0.0 ? (float)srcAnim->mTicksPerSecond : 25.0f;
Anim->boneMax = temp->boneIndexCount;
Anim->arrFrameBone = new Matrix * [Anim->frameMax];
//프레임 j
for (UINT j = 0; j < Anim->frameMax; j++)
{
Anim->arrFrameBone[j] = new Matrix[MAX_BONE];
}
aniMap.clear();
aniMap.resize(Anim->frameMax);
//채널갯수 -> 본에 대응
for (UINT j = 0; j < srcAnim->mNumChannels; j++)
{
AnimNode* animNode = new AnimNode();
aiNodeAnim* srcAnimNode = srcAnim->mChannels[j];
animNode->name = srcAnimNode->mNodeName.C_Str();
//Scale
for (UINT k = 0; k < srcAnimNode->mNumScalingKeys; k++)
{
AnimScale srcScale;
srcScale.time = (float)srcAnimNode->mScalingKeys[k].mTime;
srcScale.scale.x = (float)srcAnimNode->mScalingKeys[k].mValue.x;
srcScale.scale.y = (float)srcAnimNode->mScalingKeys[k].mValue.y;
srcScale.scale.z = (float)srcAnimNode->mScalingKeys[k].mValue.z;
animNode->scale.push_back(srcScale);
}
//Position
for (UINT k = 0; k < srcAnimNode->mNumPositionKeys; k++)
{
AnimPosition srcPosition;
srcPosition.time = (float)srcAnimNode->mPositionKeys[k].mTime;
srcPosition.pos.x = (float)srcAnimNode->mPositionKeys[k].mValue.x;
srcPosition.pos.y = (float)srcAnimNode->mPositionKeys[k].mValue.y;
srcPosition.pos.z = (float)srcAnimNode->mPositionKeys[k].mValue.z;
animNode->position.push_back(srcPosition);
}
//Rotation
for (UINT k = 0; k < srcAnimNode->mNumRotationKeys; k++)
{
AnimRotation srcRotation;
srcRotation.time = (float)srcAnimNode->mRotationKeys[k].mTime;
srcRotation.quater.x = (float)srcAnimNode->mRotationKeys[k].mValue.x;
srcRotation.quater.y = (float)srcAnimNode->mRotationKeys[k].mValue.y;
srcRotation.quater.z = (float)srcAnimNode->mRotationKeys[k].mValue.z;
srcRotation.quater.w = (float)srcAnimNode->mRotationKeys[k].mValue.w;
animNode->rotation.push_back(srcRotation);
}
GameObject* chanel = temp->Find(animNode->name);
if (chanel)
{
Matrix S, R, T;
Quaternion quter;
Vector3 pos, scale;
for (UINT k = 0; k < Anim->frameMax; k++)
{
pos = Interpolated::CalcInterpolatedPosition(animNode, (float)k, Anim->frameMax);
scale = Interpolated::CalcInterpolatedScaling(animNode, (float)k, Anim->frameMax);
quter = Interpolated::CalcInterpolatedRotation(animNode, (float)k, Anim->frameMax);
S = Matrix::CreateScale(scale);
R = Matrix::CreateFromQuaternion(quter);
T = Matrix::CreateTranslation(pos);
Matrix W = S * R * T;
//Anim->arrFrameBone[k][chanel->boneIndex] =
//aniMap[k][animNode->name] = chanel->GetLocalInverse() * W;
aniMap[k][animNode->name] = W;
}
}
//여기서 채널끝(본)
}
for (UINT j = 0; j < Anim->frameMax; j++)
{
MakeAnim(temp,j);
}
for (UINT j = 0; j < Anim->frameMax; j++)
{
for (UINT k = 0; k < Anim->boneMax; k++)
{
Anim->arrFrameBone[j][k] = Anim->arrFrameBone[j][k].Transpose();
}
}
//여기서 애님끝
temp->animations->playList.push_back(Anim);
{
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Animation/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string filePath = file.substr(0, tok) + "/";
Anim->file = filePath + Anim->file + ".anim";
Anim->SaveFile(Anim->file);
}
}
importer.FreeScene();
}
Camera::ControlMainCam();
Cam->Update();
grid->Update();
temp->Update();
}
void Main::LateUpdate()
{
}
void Main::PreRender()
{
}
void Main::Render()
{
Cam->Set();
grid->Render();
temp->Render();
}
void Main::ResizeScreen()
{
}
void Main::MakeAnim(GameObject* node, int frame)
{
int idx = node->boneIndex;
if (aniMap[frame].find(node->name) != aniMap[frame].end())
{
node->W = aniMap[frame][node->name];
}
else
{
node->W = node->GetLocal();
}
//노드가 부모가 있으면
if (node->parent)
{
node->W *= node->parent->W;
}
Anim->arrFrameBone[frame][idx] = bonesOffset[idx] * node->W;
for (auto it = node->children.begin(); it != node->children.end(); it++)
MakeAnim(it->second, frame);
}
void Main::MakeHierarchy(aiNode* node, GameObject* node2)
{
Matrix tempMat = ToMatrix(node->mTransformation);
Vector3 s, r, t; Quaternion q;
tempMat.Decompose(s, q, t);
r = Util::QuaternionToYawPtichRoll(q);
node2->scale = s;
node2->rotation = r;
node2->SetLocalPos(t);
temp->Update();
bonesOffset[node2->boneIndex] = node2->W.Invert();
for (int i = 0; i < node->mNumChildren; i++)
{
GameObject* child = GameObject::Create(node->mChildren[i]->mName.C_Str());
node2->AddBone(child);
MakeHierarchy(node->mChildren[i], child);
}
}
void Main::MakeMesh(aiNode* node, GameObject* node2)
{
for (int i = 0; i < node->mNumMeshes; i++)
{
int index = node->mMeshes[i];
aiMesh* mesh = scene->mMeshes[index];
aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex];
string mtlFile = mtl->GetName().C_Str();
int tok = file.find_last_of(".");
string filePath = file.substr(0, tok) + "/";
mtlFile = filePath + mtlFile + ".mtl";
GameObject* Current = node2;
//메쉬가 두개 이상일때
if (i != 0)
{
Current =
GameObject::Create(node2->name + "meshObject" + to_string(i));
node2->AddChild(Current);
}
Current->shader = RESOURCE->shaders.Load("4.Cube.hlsl");
Current->material =new Material();
Current->material->LoadFile(mtlFile);
Current->mesh = make_shared<Mesh>();
Current->mesh->byteWidth = sizeof(VertexModel);
Current->mesh->primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
Current->mesh->vertexType = VertexType::MODEL;
Current->mesh->vertexCount = mesh->mNumVertices;
Current->mesh->vertices = new VertexModel[mesh->mNumVertices];
//Current->mesh->indexCount =
vector<UINT> indexList;
vector<VertexWeights> VertexWeights;
VertexWeights.resize(mesh->mNumVertices);
ReadBoneData(mesh, VertexWeights);
for (int j = 0; j < mesh->mNumVertices; j++)
{
VertexModel* vertex = (VertexModel*)Current->mesh->vertices;
//aiVector3D
//텍스쳐 좌표가 있다면
if (mesh->HasTextureCoords(0))
{
vertex[j].uv.x =mesh->mTextureCoords[0][j].x;
vertex[j].uv.y =mesh->mTextureCoords[0][j].y;
}
if (mesh->HasNormals())
{
vertex[j].normal.x = mesh->mNormals[j].x;
vertex[j].normal.y = mesh->mNormals[j].y;
vertex[j].normal.z = mesh->mNormals[j].z;
}
if (mesh->HasPositions())
{
vertex[j].position.x = mesh->mVertices[j].x;
vertex[j].position.y = mesh->mVertices[j].y;
vertex[j].position.z = mesh->mVertices[j].z;
}
if (mesh->HasTangentsAndBitangents())
{
vertex[j].tangent.x = mesh->mTangents[j].x;
vertex[j].tangent.y = mesh->mTangents[j].y;
vertex[j].tangent.z = mesh->mTangents[j].z;
}
//본데이터가 있을때
if (!VertexWeights.empty())
{
VertexWeights[j].Normalize();
vertex[j].indices.x = (float)VertexWeights[j].boneIdx[0];
vertex[j].indices.y = (float)VertexWeights[j].boneIdx[1];
vertex[j].indices.z = (float)VertexWeights[j].boneIdx[2];
vertex[j].indices.w = (float)VertexWeights[j].boneIdx[3];
vertex[j].weights.x = VertexWeights[j].boneWeights[0];
vertex[j].weights.y = VertexWeights[j].boneWeights[1];
vertex[j].weights.z = VertexWeights[j].boneWeights[2];
vertex[j].weights.w = VertexWeights[j].boneWeights[3];
}
}
for (int j = 0; j < mesh->mNumFaces; j++)
{
for (int k = 0; k < mesh->mFaces[j].mNumIndices; k++)
{
indexList.push_back(mesh->mFaces[j].mIndices[k]);
}
}
Current->mesh->indexCount = indexList.size();
Current->mesh->indices = new UINT[indexList.size()];
copy(indexList.begin(), indexList.end(),
stdext::checked_array_iterator<UINT*>
(Current->mesh->indices, indexList.size()));
Current->mesh->Reset();
{
int tok = file.find_last_of(".");
string checkPath = "../Contents/Mesh/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string filePath = file.substr(0, tok) + "/";
string meshFile = mesh->mName.C_Str();
Current->mesh->file = filePath + meshFile + ".mesh";
Current->mesh->SaveFile(Current->mesh->file);
}
}
for (UINT i = 0; i < node->mNumChildren; i++)
{
MakeMesh(node->mChildren[i],node2->children[node->mChildren[i]->mName.C_Str()]);
}
}
void Main::MakeMaterial()
{
for (int i = 0; i < scene->mNumMaterials; i++)
{
aiMaterial* srcMtl = scene->mMaterials[i];
Material* destMtl = new Material();
aiColor3D tempColor;
destMtl->file = srcMtl->GetName().C_Str();
//ambient
srcMtl->Get(AI_MATKEY_COLOR_AMBIENT, tempColor);
destMtl->ambient.x = tempColor.r;
destMtl->ambient.y = tempColor.g;
destMtl->ambient.z = tempColor.b;
//diffuse
srcMtl->Get(AI_MATKEY_COLOR_DIFFUSE, tempColor);
destMtl->diffuse.x = tempColor.r;
destMtl->diffuse.y = tempColor.g;
destMtl->diffuse.z = tempColor.b;
//specular
srcMtl->Get(AI_MATKEY_COLOR_SPECULAR, tempColor);
destMtl->specular.x = tempColor.r;
destMtl->specular.y = tempColor.g;
destMtl->specular.z = tempColor.b;
//emissive
srcMtl->Get(AI_MATKEY_COLOR_EMISSIVE, tempColor);
destMtl->emissive.x = tempColor.r;
destMtl->emissive.y = tempColor.g;
destMtl->emissive.z = tempColor.b;
//Shininess
srcMtl->Get(AI_MATKEY_SHININESS, destMtl->shininess);
//opacity
srcMtl->Get(AI_MATKEY_OPACITY, destMtl->opacity);
//Normal
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_NORMALS, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->ambient.w = 1.0f;
destMtl->normalMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->normalMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
//Diffuse
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_DIFFUSE, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->diffuse.w = 1.0f;
destMtl->diffuseMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->diffuseMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
//specular
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_SPECULAR, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->specular.w = 1.0f;
destMtl->specularMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->specularMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
//emissive
{
aiString aifile;
string TextureFile;
aiReturn texFound;
texFound = srcMtl->GetTexture(aiTextureType_EMISSIVE, 0, &aifile);
TextureFile = aifile.C_Str();
size_t index = TextureFile.find_last_of('/');
TextureFile = TextureFile.substr(index + 1, TextureFile.length());
//텍스쳐가 있다.
if (texFound == AI_SUCCESS && file != "")
{
destMtl->emissive.w = 1.0f;
destMtl->emissiveMap = make_shared<Texture>();
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Texture/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string orgin = "../Assets/" + TextureFile;
string copy = "../Contents/Texture/" + file.substr(0, tok) + "/" + TextureFile;
bool isCheck = true;
CopyFileA(orgin.c_str(), copy.c_str(), isCheck);
destMtl->emissiveMap->LoadFile(file.substr(0, tok) + "/" + TextureFile);
}
}
size_t tok = file.find_last_of(".");
string checkPath = "../Contents/Material/" + file.substr(0, tok);
if (!PathFileExistsA(checkPath.c_str()))
{
CreateDirectoryA(checkPath.c_str(), NULL);
}
string filePath = file.substr(0, tok) + "/";
destMtl->file = filePath + destMtl->file + ".mtl";
destMtl->SaveFile(destMtl->file);
}
}
void Main::ReadBoneData(aiMesh* mesh, vector<class VertexWeights>& vertexWeights)
{
//메쉬가 가지고 있는 본 개수 만큼
for (UINT i = 0; i < mesh->mNumBones; i++)
{
//현재본이 하이어라이키에서 몇번째 인덱스인가?
string boneName = mesh->mBones[i]->mName.C_Str();
int boneIndex = temp->Find(boneName)->boneIndex;
for (UINT j = 0; j < mesh->mBones[i]->mNumWeights; j++)
{
UINT vertexID = mesh->mBones[i]->mWeights[j].mVertexId;
vertexWeights[vertexID].AddData(boneIndex, mesh->mBones[i]->mWeights[j].mWeight);
}
}
}
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR param, int command)
{
App.SetAppName(L"ObjLoader");
App.SetInstance(instance);
WIN->Create();
D3D->Create();
Main * main = new Main();
main->Init();
int wParam = (int)WIN->Run(main);
main->Release();
SafeDelete(main);
D3D->DeleteSingleton();
WIN->DeleteSingleton();
return wParam;
}
Vector3 Interpolated::CalcInterpolatedScaling(AnimNode* iter, float time, int Duration)
{
//비어있으면 1,1,1반환
if (iter->scale.empty())
return Vector3(1.0f, 1.0f, 1.0f);
//한개만 있는놈은 첫번째 값 반환
if (iter->scale.size() == 1)
return iter->scale.front().scale;
//마지막 놈은 마지막값 반환
if (time == Duration - 1)
{
return iter->scale.back().scale;
}
//보간 시작
int scaling_index = FindScale(iter, time);
if (scaling_index == -1)
{
return iter->scale.back().scale;
}
UINT next_scaling_index = scaling_index + 1;
assert(next_scaling_index < iter->scale.size());
float delta_time = (float)(iter->scale[next_scaling_index].time
- iter->scale[scaling_index].time);
float factor = (time - (float)(iter->scale[scaling_index].time)) / delta_time;
if (factor < 0.0f)
{
return iter->scale.front().scale;
}
auto start = iter->scale[scaling_index].scale;
auto end = iter->scale[next_scaling_index].scale;
start = Vector3::Lerp(start, end, factor);
return start;
}
Quaternion Interpolated::CalcInterpolatedRotation(AnimNode* iter, float time, int Duration)
{
if (iter->rotation.empty())
return Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
if (iter->rotation.size() == 1)
return iter->rotation.front().quater;
if (time == Duration - 1)
{
return iter->rotation.back().quater;
}
int quter_index = FindRot(iter, time);
if (quter_index == -1)
{
return iter->rotation.back().quater;
}
UINT next_quter_index = quter_index + 1;
assert(next_quter_index < iter->rotation.size());
float delta_time = static_cast<float>(iter->rotation[next_quter_index].time - iter->rotation[quter_index].time);
float factor = (time - static_cast<float>(iter->rotation[quter_index].time)) / delta_time;
if (factor < 0.0f)
{
return iter->rotation.front().quater;
}
auto start = iter->rotation[quter_index].quater;
auto end = iter->rotation[next_quter_index].quater;
start = Quaternion::Slerp(start, end, factor);
return start;
}
Vector3 Interpolated::CalcInterpolatedPosition(AnimNode* iter, float time, int Duration)
{
if (iter->position.empty())
return Vector3(0.0f, 0.0f, 0.0f);
if (iter->position.size() == 1)
return iter->position.front().pos;
if (time == Duration - 1)
{
return iter->position.back().pos;
}
int position_index = FindPos(iter, time);
if (position_index == -1)
{
return iter->position.back().pos;
}
UINT next_position_index = position_index + 1;
assert(next_position_index < iter->position.size());
float delta_time = static_cast<float>(iter->position[next_position_index].time - iter->position[position_index].time);
float factor = (time - static_cast<float>(iter->position[position_index].time)) / delta_time;
if (factor < 0.0f)
{
return iter->position.front().pos;
}
auto start = iter->position[position_index].pos;
auto end = iter->position[next_position_index].pos;
start = Vector3::Lerp(start, end, factor);
return start;
}
int Interpolated::FindScale(AnimNode* iter, float time)
{
if (iter->scale.empty())
return -1;
for (UINT i = 0; i < iter->scale.size() - 1; i++)
{
if (time < (float)(iter->scale[i + 1].time))
return i;
}
return -1;
}
int Interpolated::FindRot(AnimNode* iter, float time)
{
if (iter->rotation.empty())
return -1;
for (UINT i = 0; i < iter->rotation.size() - 1; i++)
{
if (time < static_cast<float>(iter->rotation[i + 1].time))
return i;
}
return -1;
}
int Interpolated::FindPos(AnimNode* iter, float time)
{
if (iter->position.empty())
return -1;
for (UINT i = 0; i < iter->position.size() - 1; i++)
{
if (time < static_cast<float>(iter->position[i + 1].time))
return i;
}
return -1;
}
클래스가 바뀜에 따라 Main의 헤더와 cpp파일도 변경되었습니다. 이후 obj나 fbx 파일과 애니메이션 파일을 로드라고 SlideInt를 하게 되면 프레임별로 애니메이션 효과를 볼 수 있습니다.
읽어주셔서 감사합니다.