1
0
forked from Redacted/Re3D

Skeletal Animation

This commit is contained in:
2024-02-01 21:05:08 -05:00
parent c73f7562bf
commit cf9d3bcaeb
11 changed files with 2095 additions and 6 deletions

View File

@@ -52,7 +52,7 @@ CPMAddPackage(
CPMAddPackage(
NAME J3ML
URL https://git.redacted.cc/josh/j3ml/archive/Prerelease-7.zip
URL https://git.redacted.cc/josh/j3ml/archive/Prerelease-16.zip
)
CPMAddPackage(

1130
include/assimp/config.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
#pragma once
// SkeletalModel
namespace SA
{
class SkeletalModel;
}
// Assimp
struct aiScene;
namespace AssimpConverter
{
// Converts an Assimp scene to something we can render and animate
bool Convert(const aiScene* a_pScene, SA::SkeletalModel& a_OutModel);
};

View File

@@ -0,0 +1,125 @@
#pragma once
#include <types/animation/skeleton/types.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra/Matrix4x4.h>
namespace SA
{
class SkeletalModel
{
public:
SkeletalModel();
~SkeletalModel();
void Update(float a_Dt);
unsigned int GetNumMeshes() const { return m_Meshes.size(); }
const sAnimatedMesh& GetMesh(unsigned int i) const { return m_Meshes[i]; }
void AddMesh(const sAnimatedMesh& a_Mesh) { m_Meshes.push_back(a_Mesh); }
void SetGlobalInverseTransform(const LinearAlgebra::Matrix4x4& a_Transform) { m_GlobalInverseTransform = a_Transform; }
const LinearAlgebra::Matrix4x4& GetGlobalInverseTransform() const { return m_GlobalInverseTransform; }
sSkeleton& GetSkeleton() { return m_Skeleton; }
const sSkeleton& GetSkeleton() const { return m_Skeleton; }
sAnimation& GetAnimation() { return m_Animation; }
const sAnimation& GetAnimation() const { return m_Animation; }
void Clear();
private:
std::vector<sAnimatedMesh> m_Meshes;
sSkeleton m_Skeleton;
sAnimation m_Animation;
LinearAlgebra::Matrix4x4 m_GlobalInverseTransform;
float m_AnimationTime;
private:
void ReadNodeHierarchy(float AnimationTime, sAnimation& a_Animation, sSkeleton& a_Skeleton, sBone& a_Bone, const LinearAlgebra::Matrix4x4& ParentTransform);
void TransformVertices(const sSkeleton& a_Skeleton);
};
}
namespace SA
{
// Helper functions
static LinearAlgebra::Vector3 NodeAnimation_FindInterpolatedPosition(const sNodeAnimation& a_NodeAnimation, float a_AnimationTime);
static LinearAlgebra::Quaternion NodeAnimation_FindInterpolatedRotation(const sNodeAnimation& a_NodeAnimation, float a_AnimationTime);
template <typename _Ty> static _Ty NodeAnimation_FindInterpolatedValue(std::vector<sNodeAnimationKey<_Ty> > a_Keys, float a_AnimationTime);
template <typename _Ty> static unsigned int NodeAnimation_FindIndex(const _Ty& a_Keys, float a_AnimationTime);
extern const sNodeAnimation* FindNodeAnim(const sAnimation& a_Animation, const std::string& a_NodeName);
extern LinearAlgebra::Vector3 InterpolateValue(const LinearAlgebra::Vector3& a_Start, const LinearAlgebra::Vector3& a_End, float a_Factor);
extern LinearAlgebra::Quaternion InterpolateValue(const LinearAlgebra::Quaternion& a_Start, const LinearAlgebra::Quaternion& a_End, float a_Factor);
extern unsigned int Skeleton_FindBoneIndex(const sSkeleton& a_Skeleton, const std::string& a_Name);
extern sBone* Skeleton_FindBone(sSkeleton& a_Skeleton, const std::string& a_Name);
}
namespace SA
{
LinearAlgebra::Vector3 NodeAnimation_FindInterpolatedPosition(const sNodeAnimation& a_NodeAnimation, float a_AnimationTime)
{
return NodeAnimation_FindInterpolatedValue(a_NodeAnimation.PositionKeys, a_AnimationTime);
}
LinearAlgebra::Quaternion NodeAnimation_FindInterpolatedRotation(const sNodeAnimation& a_NodeAnimation, float a_AnimationTime)
{
return NodeAnimation_FindInterpolatedValue(a_NodeAnimation.RotationKeys, a_AnimationTime);
}
template <typename _Ty>
_Ty NodeAnimation_FindInterpolatedValue(std::vector<sNodeAnimationKey<_Ty> > a_Keys, float a_AnimationTime)
{
if (a_Keys.size() == 1)
{
return a_Keys[0].Value;
}
unsigned int PositionIndex = NodeAnimation_FindIndex(a_Keys, a_AnimationTime);
unsigned int NextPositionIndex = (PositionIndex + 1);
//CORE_ASSERT(NextPositionIndex < a_Keys.size());
float DeltaTime = a_Keys[NextPositionIndex].Time - a_Keys[PositionIndex].Time;
float Factor = (a_AnimationTime - a_Keys[PositionIndex].Time) / DeltaTime;
//CORE_ASSERT(Factor >= 0.0f && Factor <= 1.0f);
const _Ty& StartPosition = a_Keys[PositionIndex].Value;
const _Ty& EndPosition = a_Keys[NextPositionIndex].Value;
return InterpolateValue(StartPosition, EndPosition, Factor);
}
template <typename _Ty>
unsigned int NodeAnimation_FindIndex(const _Ty& a_Keys, float a_AnimationTime)
{
for (unsigned int i = 0; i < a_Keys.size() - 1; ++i)
{
if (a_AnimationTime < a_Keys[i + 1].Time)
return i;
}
//CORE_ASSERT(false);
return -1;
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <string>
namespace SA
{
class SkeletalModel;
// Serialization methods
extern std::string ModelToData(const SkeletalModel& a_Model);
extern bool ModelToData(const SkeletalModel& a_Model, std::string& a_OutData);
extern unsigned int ModelToData(const SkeletalModel& a_Model, char* a_pOutData);
extern bool DataToModel(const char* a_pData, SkeletalModel& a_OutModel);
};

View File

@@ -0,0 +1,73 @@
#pragma once
#include <J3ML/LinearAlgebra/Matrix4x4.h>
// STD
#include <vector>
#include <string>
namespace SA
{
struct sWeight
{
unsigned int VertexID;
float Weight;
};
struct sBone
{
std::string Name;
LinearAlgebra::Matrix4x4 NodeTransform;
LinearAlgebra::Matrix4x4 OffsetMatrix; // T-Pose to local bone space
LinearAlgebra::Matrix4x4 FinalTransformation;
unsigned int NumWeights;
sWeight* pWeights;
unsigned int NumChildren;
unsigned int* pChildren;
};
struct sAnimatedMesh
{
unsigned int NumVertices;
LinearAlgebra::Vector3* pVertices;
LinearAlgebra::Vector3* pNormals;
LinearAlgebra::Vector3* pTransformedVertices;
LinearAlgebra::Vector3* pTransformedNormals;
unsigned int NumIndices;
unsigned int* pIndices;
};
struct sSkeleton
{
std::vector<sBone> Bones;
};
template <typename _Ty>
struct sNodeAnimationKey
{
_Ty Value;
float Time;
};
struct sNodeAnimation
{
std::string Name;
std::vector<sNodeAnimationKey<LinearAlgebra::Vector3> > PositionKeys;
std::vector<sNodeAnimationKey<LinearAlgebra::Quaternion> > RotationKeys;
};
struct sAnimation
{
std::vector<sNodeAnimation> NodeAnimations;
float TicksPerSecond;
float Duration;
};
}

View File

@@ -7,11 +7,11 @@
#include <glad/glad.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra/Vector2.h>
#include <types/texture.h>
struct Vertex {
float x, y, z;
GLfloat u, v;
LinearAlgebra::Vector3 normal;
};
class VertexArray {

View File

@@ -0,0 +1,195 @@
#include <types/animation/AssimpConverter.h>
// Assimp
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
// SkeletalModel
#include <types/animation/skeleton/SkeletalModel.h>
#include <cassert>
// SkeletalModel
using namespace SA;
namespace AssimpConverter
{
//////////////////////////////////////////////////////////////////////////
// Private functions to convert from Assimp data types to glm
static LinearAlgebra::Matrix4x4 aiToGlm(const aiMatrix4x4& v)
{
LinearAlgebra::Matrix4x4 out;
assert(sizeof(out) == sizeof(v));
memcpy(&out, &v, sizeof(v));
return out.Transpose();
}
static LinearAlgebra::Vector3 aiToGlm(const aiVector3D& v)
{
LinearAlgebra::Vector3 out;
assert(sizeof(out) == sizeof(v));
memcpy(&out, &v, sizeof(v));
return out;
}
static LinearAlgebra::Quaternion aiToGlm(const aiQuaternion& v)
{
return LinearAlgebra::Quaternion(v.w, v.x, v.y, v.z);
}
//////////////////////////////////////////////////////////////////////////
// Recursively add all nodes from scene to skeleton
static unsigned int AddNodesToSkeleton(aiNode* a_pNode, sSkeleton& a_Skeleton)
{
unsigned int BoneID = a_Skeleton.Bones.size();
{
sBone NewBone;
NewBone.Name = a_pNode->mName.C_Str();
NewBone.NodeTransform = aiToGlm(a_pNode->mTransformation);
NewBone.NumChildren = a_pNode->mNumChildren;
NewBone.pChildren = new unsigned int[NewBone.NumChildren];
NewBone.NumWeights = 0;
NewBone.pWeights = NULL;
for (unsigned int i = 0; i < NewBone.NumChildren; ++i)
NewBone.pChildren[i] = -1;
//
a_Skeleton.Bones.push_back(NewBone);
}
for (unsigned int i = 0; i < a_pNode->mNumChildren; ++i)
{
unsigned int ChildBoneID = AddNodesToSkeleton(a_pNode->mChildren[i], a_Skeleton);
a_Skeleton.Bones[BoneID].pChildren[i] = ChildBoneID;
}
return BoneID;
}
//////////////////////////////////////////////////////////////////////////
// Adds meshes to AnimatedModel and populates bones in skeleton with weights
static void AddMeshesAndBones(const aiScene* a_pScene, SkeletalModel& a_OutModel)
{
sSkeleton& Skeleton = a_OutModel.GetSkeleton();
//
for (unsigned int i = 0; i < a_pScene->mNumMeshes; ++i)
{
aiMesh* pMesh = a_pScene->mMeshes[i];
//
sAnimatedMesh AnimMesh;
AnimMesh.NumVertices = pMesh->mNumVertices;
AnimMesh.pVertices = new LinearAlgebra::Vector3[AnimMesh.NumVertices];
AnimMesh.pTransformedVertices = new LinearAlgebra::Vector3[AnimMesh.NumVertices];
AnimMesh.pNormals = new LinearAlgebra::Vector3[AnimMesh.NumVertices];
AnimMesh.pTransformedNormals = new LinearAlgebra::Vector3[AnimMesh.NumVertices];
AnimMesh.NumIndices = pMesh->mNumFaces * 3;
AnimMesh.pIndices = new unsigned int[AnimMesh.NumIndices];
memcpy(AnimMesh.pVertices, pMesh->mVertices, AnimMesh.NumVertices*sizeof(aiVector3D));
memcpy(AnimMesh.pNormals, pMesh->mNormals, AnimMesh.NumVertices*sizeof(aiVector3D));
for (unsigned int i = 0; i < pMesh->mNumBones; ++i)
{
aiBone* pBone = pMesh->mBones[i];
sBone& Bone = *Skeleton_FindBone(Skeleton, pBone->mName.C_Str());
Bone.OffsetMatrix = aiToGlm(pBone->mOffsetMatrix);
Bone.NumWeights = pBone->mNumWeights;
Bone.pWeights = new sWeight[pBone->mNumWeights];
for (unsigned int i = 0; i < Bone.NumWeights; ++i)
{
Bone.pWeights[i].VertexID = pBone->mWeights[i].mVertexId;
Bone.pWeights[i].Weight = pBone->mWeights[i].mWeight;
}
}
for (unsigned int i = 0; i < pMesh->mNumFaces; ++i)
{
aiFace Face = pMesh->mFaces[i];
//CORE_ASSERT(Face.mNumIndices == 3);
AnimMesh.pIndices[i * 3 + 0] = Face.mIndices[0];
AnimMesh.pIndices[i * 3 + 1] = Face.mIndices[1];
AnimMesh.pIndices[i * 3 + 2] = Face.mIndices[2];
}
//
a_OutModel.AddMesh(AnimMesh);
}
}
//////////////////////////////////////////////////////////////////////////
// Adds animations to AnimatedModel
void AddAnimations(const aiScene* a_pScene, SkeletalModel& a_OutModel)
{
if (a_pScene->mNumAnimations > 0)
{
sAnimation& Animation = a_OutModel.GetAnimation();
// Only use the first animation
aiAnimation* pAnimation = a_pScene->mAnimations[0];
for (unsigned int i = 0; i < pAnimation->mNumChannels; ++i)
{
aiNodeAnim* pChannel = pAnimation->mChannels[i];
sNodeAnimation NodeAnimation;
NodeAnimation.Name = pChannel->mNodeName.C_Str();
for (unsigned int i = 0; i < pChannel->mNumPositionKeys; ++i)
{
sNodeAnimationKey<LinearAlgebra::Vector3> Vec3Key;
Vec3Key.Time = (float)pChannel->mPositionKeys[i].mTime;
Vec3Key.Value = aiToGlm(pChannel->mPositionKeys[i].mValue);
NodeAnimation.PositionKeys.push_back(Vec3Key);
}
for (unsigned int i = 0; i < pChannel->mNumRotationKeys; ++i)
{
sNodeAnimationKey<LinearAlgebra::Quaternion> QuatKey;
QuatKey.Time = (float)pChannel->mRotationKeys[i].mTime;
QuatKey.Value = aiToGlm(pChannel->mRotationKeys[i].mValue);
NodeAnimation.RotationKeys.push_back(QuatKey);
}
Animation.NodeAnimations.push_back(NodeAnimation);
}
Animation.TicksPerSecond = (float)a_pScene->mAnimations[0]->mTicksPerSecond;
Animation.Duration = (float)a_pScene->mAnimations[0]->mDuration;
}
}
//////////////////////////////////////////////////////////////////////////
// Converts aiScene to AnimatedModel
bool Convert(const aiScene* a_pScene, SkeletalModel& a_OutModel)
{
if (a_pScene == NULL)
return false;
a_OutModel.SetGlobalInverseTransform(aiToGlm(a_pScene->mRootNode->mTransformation.Inverse()));
AddNodesToSkeleton(a_pScene->mRootNode, a_OutModel.GetSkeleton());
AddMeshesAndBones(a_pScene, a_OutModel);
AddAnimations(a_pScene, a_OutModel);
return true;
}
}

View File

@@ -0,0 +1,222 @@
#include <types/animation/skeleton/SkeletalModel.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra/Matrix4x4.h>
#include <J3ML/LinearAlgebra/Matrix3x3.h>
#include <cstring>
//////////////////////////////////////////////////////////////////////////
// Based on: http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html //
//////////////////////////////////////////////////////////////////////////
namespace SA
{
SkeletalModel::SkeletalModel()
: m_AnimationTime(0.0f)
{
Clear();
}
SkeletalModel::~SkeletalModel()
{
Clear();
}
void SkeletalModel::Clear()
{
for (unsigned int i = 0; i < m_Meshes.size(); ++i)
{
delete[] m_Meshes[i].pVertices;
delete[] m_Meshes[i].pNormals;
delete[] m_Meshes[i].pTransformedVertices;
delete[] m_Meshes[i].pTransformedNormals;
delete[] m_Meshes[i].pIndices;
}
m_Meshes.clear();
for (unsigned int i = 0; i < m_Skeleton.Bones.size(); ++i)
{
delete[] m_Skeleton.Bones[i].pWeights;
delete[] m_Skeleton.Bones[i].pChildren;
}
m_Skeleton.Bones.clear();
m_Animation.NodeAnimations.clear();
m_Animation.Duration = 0.0f;
m_Animation.TicksPerSecond = 0.0f;
m_GlobalInverseTransform = LinearAlgebra::Matrix4x4(1);
m_AnimationTime = 0.0f;
}
void SkeletalModel::Update(float a_Dt)
{
m_AnimationTime = fmodf(m_AnimationTime + a_Dt * m_Animation.TicksPerSecond, m_Animation.Duration);
//
ReadNodeHierarchy(m_AnimationTime, m_Animation, m_Skeleton, m_Skeleton.Bones[0], LinearAlgebra::Matrix4x4(1));
TransformVertices(m_Skeleton);
}
void SkeletalModel::ReadNodeHierarchy(float AnimationTime, sAnimation& a_Animation, sSkeleton& a_Skeleton, sBone& a_Bone, const LinearAlgebra::Matrix4x4& ParentTransform)
{
std::string NodeName(a_Bone.Name);
LinearAlgebra::Matrix4x4 NodeTransformation(a_Bone.NodeTransform);
const sNodeAnimation* pNewNodeAnim = FindNodeAnim(a_Animation, NodeName);
if (pNewNodeAnim)
{
LinearAlgebra::Vector3 Translation = NodeAnimation_FindInterpolatedPosition(*pNewNodeAnim, AnimationTime);
LinearAlgebra::Quaternion RotationQ = NodeAnimation_FindInterpolatedRotation(*pNewNodeAnim, AnimationTime);
// LinearAlgebra::Vector3 Scaling2(1, 1, 1);
// LinearAlgebra::Matrix4x4 ScalingM2 = glm::scale(Scaling2);
LinearAlgebra::Matrix4x4 RotationM2 = RotationQ.ToMatrix4x4();
LinearAlgebra::Matrix4x4 TranslationM2; TranslationM2.SetTranslatePart(Translation);
// Combine the above transformations
NodeTransformation = TranslationM2 * RotationM2;// * ScalingM2;
}
LinearAlgebra::Matrix4x4 GlobalTransformation = ParentTransform * NodeTransformation;
unsigned int BoneIndex = Skeleton_FindBoneIndex(a_Skeleton, NodeName);
if (BoneIndex != -1)
{
sBone* pBone = &a_Skeleton.Bones[BoneIndex];
pBone->FinalTransformation = m_GlobalInverseTransform * GlobalTransformation * pBone->OffsetMatrix;
}
for (unsigned int i = 0; i < a_Bone.NumChildren; i++)
{
ReadNodeHierarchy(AnimationTime, a_Animation, a_Skeleton, a_Skeleton.Bones[a_Bone.pChildren[i]], GlobalTransformation);
}
}
void SkeletalModel::TransformVertices(const sSkeleton& a_Skeleton)
{
for (unsigned int i = 0; i < m_Meshes.size(); ++i)
{
// Reset mesh vertices and normals
sAnimatedMesh& AnimMesh = m_Meshes[i];
memset(AnimMesh.pTransformedVertices, 0, AnimMesh.NumVertices*sizeof(LinearAlgebra::Vector3));
memset(AnimMesh.pTransformedNormals, 0, AnimMesh.NumVertices*sizeof(LinearAlgebra::Vector3));
//
for (unsigned int i = 0; i < a_Skeleton.Bones.size(); ++i)
{
const sBone& Bone = a_Skeleton.Bones[i];
//
LinearAlgebra::Matrix4x4 Transformation = Bone.FinalTransformation;
LinearAlgebra::Matrix3x3 Rotation = Transformation.GetRotatePart();
//
for (unsigned int i = 0; i < Bone.NumWeights; ++i)
{
sWeight Weight = Bone.pWeights[i];
//
LinearAlgebra::Vector3 inVertex = AnimMesh.pVertices[Weight.VertexID];
LinearAlgebra::Vector3& outVertex = AnimMesh.pTransformedVertices[Weight.VertexID];
LinearAlgebra::Vector4 inVertex4 = {inVertex.x, inVertex.y, inVertex.z, 1};
LinearAlgebra::Vector3 t = (Transformation * inVertex) * Weight.Weight;
outVertex = outVertex + t;
//
LinearAlgebra::Vector3 inNormal = AnimMesh.pNormals[Weight.VertexID];
LinearAlgebra::Vector3& outNormal = AnimMesh.pTransformedNormals[Weight.VertexID];
outNormal = outNormal + (Rotation * inNormal) * Weight.Weight;
}
}
}
// Normalize normals
for (unsigned int i = 0; i < m_Meshes.size(); ++i)
{
sAnimatedMesh& AnimMesh = m_Meshes[i];
for (unsigned int i = 0; i < AnimMesh.NumVertices; ++i)
{
AnimMesh.pTransformedNormals[i] = AnimMesh.pTransformedNormals[i].Normalize();
}
}
}
const sNodeAnimation* FindNodeAnim(const sAnimation& a_Animation, const std::string& a_NodeName)
{
for (unsigned int i = 0; i < a_Animation.NodeAnimations.size(); ++i)
{
const sNodeAnimation& NodeAnim = a_Animation.NodeAnimations[i];
if (NodeAnim.Name == a_NodeName)
{
return &NodeAnim;
}
}
return NULL;
}
LinearAlgebra::Vector3 InterpolateValue(const LinearAlgebra::Vector3& a_Start, const LinearAlgebra::Vector3& a_End, float a_Factor)
{
return a_Start.Lerp(a_End,a_Factor);
}
LinearAlgebra::Quaternion InterpolateValue(const LinearAlgebra::Quaternion& a_Start, const LinearAlgebra::Quaternion& a_End, float a_Factor)
{
return a_Start.Slerp(a_End, a_Factor);
}
unsigned int Skeleton_FindBoneIndex(const sSkeleton& a_Skeleton, const std::string& a_Name)
{
for (unsigned int i = 0; i < a_Skeleton.Bones.size(); ++i)
{
if (a_Skeleton.Bones[i].Name == a_Name)
return i;
}
return -1;
}
sBone* Skeleton_FindBone(sSkeleton& a_Skeleton, const std::string& a_Name)
{
return &a_Skeleton.Bones[Skeleton_FindBoneIndex(a_Skeleton, a_Name)];
}
}

View File

@@ -0,0 +1,314 @@
#include <types/animation/skeleton/SkeletalModelSerializer.h>
#include <types/animation/skeleton/SkeletalModel.h>
#include <cstring>
namespace SA
{
// Helper function used for reading and writing
template <typename _Ty>
static void WriteBinary(unsigned int& a_InOutPos, char* a_pDestination, const _Ty& a_Source)
{
if (a_pDestination != NULL)
{
memcpy(a_pDestination + a_InOutPos, &a_Source, sizeof(_Ty));
}
a_InOutPos += sizeof(_Ty);
}
template <typename _Ty>
static void ReadBinary(unsigned int& a_InOutPos, _Ty& a_Destination, const char* a_pSource)
{
memcpy(&a_Destination, a_pSource + a_InOutPos, sizeof(_Ty));
a_InOutPos += sizeof(_Ty);
}
template <typename _Ty>
static void WriteBinary(unsigned int& a_InOutPos, char* a_pDestination, const _Ty* a_Source, unsigned int a_NumElements)
{
if (a_pDestination != NULL)
{
memcpy(a_pDestination + a_InOutPos, a_Source, sizeof(_Ty) * a_NumElements);
}
a_InOutPos += sizeof(_Ty) * a_NumElements;
}
template <typename _Ty>
static void ReadBinary(unsigned int& a_InOutPos, _Ty*& a_pDestination, const char* a_pSource, unsigned int a_NumElements)
{
a_pDestination = NULL;
if (a_NumElements > 0)
{
a_pDestination = new _Ty[a_NumElements];
memcpy(a_pDestination, a_pSource + a_InOutPos, sizeof(_Ty) * a_NumElements);
a_InOutPos += sizeof(_Ty) * a_NumElements;
}
}
static void WriteString(unsigned int& a_InOutPos, char* a_pDestination, const std::string& a_Source)
{
unsigned int StringLength = a_Source.size();
WriteBinary(a_InOutPos, a_pDestination, StringLength);
WriteBinary(a_InOutPos, a_pDestination, a_Source.c_str(), StringLength);
}
static void ReadString(unsigned int& a_InOutPos, std::string& a_Destination, const char* a_pSource)
{
unsigned int StringLength = 0;
ReadBinary(a_InOutPos, StringLength, a_pSource);
if (StringLength > 0)
{
a_Destination.resize(StringLength + 1);
memcpy((void*)a_Destination.data(), a_pSource + a_InOutPos, StringLength);
a_InOutPos += StringLength;
}
}
template <typename _Ty>
static void WriteKeys(unsigned int& a_InOutPos, char* a_pDestination, const std::vector<sNodeAnimationKey<_Ty> >& a_Source)
{
unsigned int NumKeys = a_Source.size();
WriteBinary(a_InOutPos, a_pDestination, NumKeys);
for (unsigned int i = 0; i < NumKeys; ++i)
{
WriteBinary(a_InOutPos, a_pDestination, a_Source[i].Time);
WriteBinary(a_InOutPos, a_pDestination, a_Source[i].Value);
}
}
template <typename _Ty>
static void ReadKeys(unsigned int& a_InOutPos, std::vector<sNodeAnimationKey<_Ty> >& a_Destination, const char* a_pSource)
{
unsigned int NumKeys = 0;
ReadBinary(a_InOutPos, NumKeys, a_pSource);
for (unsigned int i = 0; i < NumKeys; ++i)
{
sNodeAnimationKey<_Ty> PosKey;
ReadBinary(a_InOutPos, PosKey.Time, a_pSource);
ReadBinary(a_InOutPos, PosKey.Value, a_pSource);
a_Destination.push_back(PosKey);
}
}
extern std::string ModelToData(const SkeletalModel& a_Model)
{
std::string OutData;
ModelToData(a_Model, OutData);
return OutData;
}
extern bool ModelToData(const SkeletalModel& a_Model, std::string& a_OutData)
{
unsigned int DataSize = ModelToData(a_Model, NULL);
a_OutData.resize(DataSize);
return ModelToData(a_Model, (char*)a_OutData.data()) > 0;
}
unsigned int ModelToData(const SkeletalModel& a_Model, char* a_pOutData)
{
unsigned int DataPos = 0;
int a = 1, b = 2, c = 3;
WriteBinary(DataPos, a_pOutData, a);
WriteBinary(DataPos, a_pOutData, b);
WriteBinary(DataPos, a_pOutData, c);
// Write meshes
unsigned int NumMeshes = a_Model.GetNumMeshes();
WriteBinary(DataPos, a_pOutData, NumMeshes);
for (unsigned int i = 0; i < NumMeshes; ++i)
{
const sAnimatedMesh& Mesh = a_Model.GetMesh(i);
// Write vertices and normals
WriteBinary(DataPos, a_pOutData, Mesh.NumVertices);
WriteBinary(DataPos, a_pOutData, Mesh.pVertices, Mesh.NumVertices);
WriteBinary(DataPos, a_pOutData, Mesh.pNormals, Mesh.NumVertices);
// Write indices
WriteBinary(DataPos, a_pOutData, Mesh.NumIndices);
WriteBinary(DataPos, a_pOutData, Mesh.pIndices, Mesh.NumIndices);
}
// Write skeleton
unsigned int NumBones = a_Model.GetSkeleton().Bones.size();
WriteBinary(DataPos, a_pOutData, NumBones);
for (unsigned int i = 0; i < NumBones; ++i)
{
const sBone& Bone = a_Model.GetSkeleton().Bones[i];
// Write bone name
WriteString(DataPos, a_pOutData, Bone.Name);
// Write matrices
WriteBinary(DataPos, a_pOutData, Bone.NodeTransform);
WriteBinary(DataPos, a_pOutData, Bone.OffsetMatrix);
// Write weights
WriteBinary(DataPos, a_pOutData, Bone.NumWeights);
for (unsigned int i = 0; i < Bone.NumWeights; ++i)
{
const sWeight& Weight = Bone.pWeights[i];
WriteBinary(DataPos, a_pOutData, Weight.VertexID);
WriteBinary(DataPos, a_pOutData, Weight.Weight);
}
// Write children IDs
WriteBinary(DataPos, a_pOutData, Bone.NumChildren);
WriteBinary(DataPos, a_pOutData, Bone.pChildren, Bone.NumChildren);
}
// Write animation
WriteBinary(DataPos, a_pOutData, a_Model.GetAnimation().TicksPerSecond);
WriteBinary(DataPos, a_pOutData, a_Model.GetAnimation().Duration);
unsigned int NumNodeAnimations = a_Model.GetAnimation().NodeAnimations.size();
WriteBinary(DataPos, a_pOutData, NumNodeAnimations);
for (unsigned int i = 0; i < NumNodeAnimations; ++i)
{
const sNodeAnimation Animation = a_Model.GetAnimation().NodeAnimations[i];
// Write node name
WriteString(DataPos, a_pOutData, Animation.Name);
// Write keyframes
WriteKeys(DataPos, a_pOutData, Animation.PositionKeys);
WriteKeys(DataPos, a_pOutData, Animation.RotationKeys);
}
WriteBinary(DataPos, a_pOutData, a_Model.GetGlobalInverseTransform());
return DataPos;
}
bool DataToModel(const char* a_pData, SkeletalModel& a_OutModel)
{
unsigned int DataPos = 0;
int a = 0, b = 0, c = 0;
ReadBinary(DataPos, a, a_pData);
ReadBinary(DataPos, b, a_pData);
ReadBinary(DataPos, c, a_pData);
unsigned int NumMeshes = 0;
ReadBinary(DataPos, NumMeshes, a_pData);
for (unsigned int i = 0; i < NumMeshes; ++i)
{
sAnimatedMesh Mesh;
// Read vertices and normals
ReadBinary(DataPos, Mesh.NumVertices, a_pData);
ReadBinary(DataPos, Mesh.pVertices, a_pData, Mesh.NumVertices);
ReadBinary(DataPos, Mesh.pNormals, a_pData, Mesh.NumVertices);
if (Mesh.NumVertices > 0)
{
Mesh.pTransformedVertices = new LinearAlgebra::Vector3[Mesh.NumVertices];
Mesh.pTransformedNormals = new LinearAlgebra::Vector3[Mesh.NumVertices];
}
else
{
Mesh.pTransformedVertices = NULL;
Mesh.pTransformedNormals = NULL;
}
// Read indices
ReadBinary(DataPos, Mesh.NumIndices, a_pData);
ReadBinary(DataPos, Mesh.pIndices, a_pData, Mesh.NumIndices);
a_OutModel.AddMesh(Mesh);
}
unsigned int NumBones = 0;
ReadBinary(DataPos, NumBones, a_pData);
for (unsigned int i = 0; i < NumBones; ++i)
{
sBone Bone;
// Read bone name
ReadString(DataPos, Bone.Name, a_pData);
// Read matrices
ReadBinary(DataPos, Bone.NodeTransform, a_pData);
ReadBinary(DataPos, Bone.OffsetMatrix, a_pData);
// Read weights
ReadBinary(DataPos, Bone.NumWeights, a_pData);
if (Bone.NumWeights > 0)
{
Bone.pWeights = new sWeight[Bone.NumWeights];
for (unsigned int i = 0; i < Bone.NumWeights; ++i)
{
sWeight Weight;
ReadBinary(DataPos, Weight.VertexID, a_pData);
ReadBinary(DataPos, Weight.Weight, a_pData);
Bone.pWeights[i] = Weight;
}
}
else
{
Bone.pWeights = NULL;
}
// Read children IDs
ReadBinary(DataPos, Bone.NumChildren, a_pData);
ReadBinary(DataPos, Bone.pChildren, a_pData, Bone.NumChildren);
a_OutModel.GetSkeleton().Bones.push_back(Bone);
}
// Read animation
ReadBinary(DataPos, a_OutModel.GetAnimation().TicksPerSecond, a_pData);
ReadBinary(DataPos, a_OutModel.GetAnimation().Duration, a_pData);
unsigned int NumNodeAnimations = 0;
ReadBinary(DataPos, NumNodeAnimations, a_pData);
for (unsigned int i = 0; i < NumNodeAnimations; ++i)
{
sNodeAnimation Animation;
// Read node name
ReadString(DataPos, Animation.Name, a_pData);
// Read position keys
ReadKeys(DataPos, Animation.PositionKeys, a_pData);
// Read rotation keys
ReadKeys(DataPos, Animation.RotationKeys, a_pData);
a_OutModel.GetAnimation().NodeAnimations.push_back(Animation);
}
LinearAlgebra::Matrix4x4 GlobalInverseTransform;
ReadBinary(DataPos, GlobalInverseTransform, a_pData);
a_OutModel.SetGlobalInverseTransform(GlobalInverseTransform);
return true;
}
}

View File

@@ -109,10 +109,10 @@ void Camera::post_render() {
this->ticksAlive++;
}
Geometry::Frustum Camera::getFrustum() {
Geometry::Camera cam = {this->position,this->fAngle(),this->rAngle(),this->upVector};
return Geometry::CreateFrustumFromCamera(cam, engine->window->getSize()[0] / engine->window->getSize()[1], engine->fov, engine->nearPlane, engine->farPlane);
}
//Geometry::Frustum Camera::getFrustum() {
//Geometry::Camera cam = {this->position,this->fAngle(),this->rAngle(),this->upVector};
//return Geometry::CreateFrustumFromCamera(cam, engine->window->getSize()[0] / engine->window->getSize()[1], engine->fov, engine->nearPlane, engine->farPlane);
//}
void Camera::hMove(LinearAlgebra::Vector3 a, float vel) {
if (cameraMode == CameraMode::FREECAM) {