Started animation resource

This commit is contained in:
Antoine Pilote
2023-08-13 22:54:33 -04:00
parent 0307166ce4
commit b29bc41d84
7 changed files with 334 additions and 49 deletions

View File

@@ -23,9 +23,15 @@ out vec2 UV;
void main()
{
vec3 T = normalize((u_Model * vec4(Tangent, 0.0f)).xyz);
vec3 N = normalize((u_Model * vec4(Normal, 0.0f)).xyz);
vec3 B = normalize((u_Model * vec4(Bitangent, 0.0f)).xyz);
mat4 boneTransform = u_FinalBonesMatrice[BoneIDs.x] * Weights.x;
boneTransform += u_FinalBonesMatrice[BoneIDs.y] * Weights.y;
boneTransform += u_FinalBonesMatrice[BoneIDs.z] * Weights.z;
boneTransform += u_FinalBonesMatrice[BoneIDs.w] * Weights.w;
mat3 normalMatrix = transpose(inverse(mat3(boneTransform)));
vec3 T = normalize(normalMatrix * Tangent);
vec3 N = normalize(normalMatrix * Normal);
vec3 B = normalize(normalMatrix * Bitangent);
TBN = mat3(T, B, N);
UV = UVPosition;
@@ -37,19 +43,19 @@ void main()
{
continue;
}
if (BoneIDs[i] >= MAX_BONES)
{
totalPosition = vec4(VertexPosition, 1.0f);
break;
}
vec4 localPosition = vec4(VertexPosition, 1.0f);
vec4 localPosition = u_FinalBonesMatrice[BoneIDs[i]] * vec4(VertexPosition, 1.0f);
totalPosition += localPosition * Weights[i];
// vec3 localNormal = mat3(u_FinalBonesMatrice[BoneIDs[i]]) * Normal;
}
gl_Position = u_Projection * u_View * u_Model * vec4(VertexPosition, 1.0f);
gl_Position = u_Projection * u_View * u_Model * totalPosition;
}
#shader fragment

View File

@@ -0,0 +1,152 @@
#include "Bone.h"
#include "src/Core/Logger.h"
namespace Nuake
{
Bone::Bone(const std::string& name, int id)
{
Name = name;
Id = id;
m_LocalTransform = Matrix4(1.0f);
}
void Bone::PushPositionKeyframe(KeyPosition& key)
{
m_Positions.push_back(std::move(key));
}
void Bone::PushRotationframe(KeyRotation& key)
{
m_Rotations.push_back(std::move(key));
}
void Bone::PushScaleKeyframe(KeyScale& key)
{
m_Scales.push_back(std::move(key));
}
void Bone::Update(float time)
{
Matrix4 translation = InterpolatePosition(time);
Matrix4 rotation = InterpolateRotation(time);
Matrix4 scale = InterpolateScaling(time);
m_LocalTransform = translation * rotation * scale;
}
Matrix4 Bone::GetLocalTransform() const
{
return m_LocalTransform;
}
int Bone::GetPositionIndex(float time) const
{
for (uint32_t i = 0; i < m_NumPositions - 1; i++)
{
if (time < m_Positions[i + 1].Timestamp)
{
return i;
}
}
Logger::Log("Bone position keyframe not found", "Bone system", CRITICAL);
assert(false);
return 0;
}
int Bone::GetRotationIndex(float time) const
{
for (uint32_t i = 0; i < m_NumRotations - 1; i++)
{
if (time < m_Rotations[i + 1].Timestamp)
{
return i;
}
}
Logger::Log("Bone rotation keyframe not found", "Bone system", CRITICAL);
assert(false);
return 0;
}
int Bone::GetScaleIndex(float time) const
{
for (uint32_t i = 0; i < m_NumScales - 1; i++)
{
if (time < m_Scales[i + 1].Timestamp)
{
return i;
}
}
Logger::Log("Bone scale keyframe not found", "Bone system", CRITICAL);
assert(false);
return 0;
}
float Bone::GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime) const
{
float scaleFactor = 0.0f;
float midWayLength = animationTime - lastTimeStamp;
float framesDiff = nextTimeStamp - lastTimeStamp;
scaleFactor = midWayLength / framesDiff;
return scaleFactor;
}
Matrix4 Bone::InterpolatePosition(float animationTime) const
{
if (m_NumPositions == 1)
{
return glm::translate(Matrix4(1.0f), m_Positions[0].Position);
}
const int keyFramePresentIndex = GetPositionIndex(animationTime);
const int keyFrameFutureIndex = keyFramePresentIndex + 1;
const KeyPosition& keyFramePresent = m_Positions[keyFramePresentIndex];
const KeyPosition& keyFrameFuture = m_Positions[keyFrameFutureIndex];
const float scaleFactor = GetScaleFactor(keyFramePresent.Timestamp, keyFrameFuture.Timestamp, animationTime);
const Vector3 finalPosition = glm::mix(keyFramePresent.Position, keyFrameFuture.Position, scaleFactor);
return glm::translate(Matrix4(1.0f), finalPosition);
}
Matrix4 Bone::InterpolateRotation(float animationTime) const
{
if (m_NumRotations == 1)
{
auto rotation = glm::normalize(m_Rotations[0].Orientation);
return glm::toMat4(rotation);
}
const int keyFramePresentIndex = GetRotationIndex(animationTime);
const int keyFrameFutureIndex = keyFramePresentIndex + 1;
const KeyRotation& keyFramePresent = m_Rotations[keyFramePresentIndex];
const KeyRotation& keyFrameFuture = m_Rotations[keyFrameFutureIndex];
const float scaleFactor = GetScaleFactor(keyFramePresent.Timestamp, keyFrameFuture.Timestamp, animationTime);
const Quat& finalRotation = glm::slerp(keyFramePresent.Orientation, keyFramePresent.Orientation, scaleFactor);
return glm::toMat4(finalRotation);
}
Matrix4 Bone::InterpolateScaling(float animationTime) const
{
if (m_NumScales == 1)
{
return glm::scale(Matrix4(1.0f), m_Scales[0].Scale);
}
const int keyFramePresentIndex = GetScaleIndex(animationTime);
const int keyFrameFutureIndex = keyFramePresentIndex + 1;
const KeyScale& keyFramePresent = m_Scales[keyFramePresentIndex];
const KeyScale& keyFrameFuture = m_Scales[keyFrameFutureIndex];
const float scaleFactor = GetScaleFactor(keyFramePresent.Timestamp, keyFrameFuture.Timestamp, animationTime);
const Vector3 finalScale = glm::mix(keyFramePresent.Scale, keyFramePresent.Scale, scaleFactor);
return glm::scale(Matrix4(1.0f), finalScale);
}
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
namespace Nuake
{
struct KeyPosition
{
Vector3 Position;
float Timestamp;
};
struct KeyRotation
{
Quat Orientation;
float Timestamp;
};
struct KeyScale
{
Vector3 Scale;
float Timestamp;
};
struct BoneVertexWeight
{
uint32_t VertexID;
float Weight;
};
class Bone
{
public:
std::string Name;
uint32_t Id;
Matrix4 Offset;
std::vector<BoneVertexWeight> VertexWeights;
private:
std::vector<KeyPosition> m_Positions;
std::vector<KeyRotation> m_Rotations;
std::vector<KeyScale> m_Scales;
uint32_t m_NumPositions;
uint32_t m_NumRotations;
uint32_t m_NumScales;
Matrix4 m_LocalTransform;
public:
Bone() = default;
Bone(const std::string& name, int id);
void PushPositionKeyframe(KeyPosition& key);
void PushRotationframe(KeyRotation& key);
void PushScaleKeyframe(KeyScale& key);
void Update(float time);
Matrix4 GetLocalTransform() const;
int GetPositionIndex(float time) const;
int GetRotationIndex(float time) const;
int GetScaleIndex(float time) const;
private:
float GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime) const;
Matrix4 InterpolatePosition(float animationTime) const ;
Matrix4 InterpolateRotation(float animationTime) const;
Matrix4 InterpolateScaling(float animationTime) const;
};
}

View File

@@ -3,7 +3,10 @@
#include "src/Rendering/AABB.h"
#include "src/Resource/Resource.h"
#include "src/Resource/Serializable.h"
#include "src/Rendering/Vertex.h"
#include "src/Rendering/Mesh/Bone.h"
namespace Nuake
{
@@ -13,19 +16,6 @@ namespace Nuake
struct Vertex;
class Shader;
struct BoneVertexWeight
{
uint32_t VertexID;
float Weight;
};
struct Bone
{
std::string Name;
Matrix4 Offset;
std::vector<BoneVertexWeight> VertexWeights;
};
class SkinnedMesh : ISerializable, Resource
{
public:

View File

@@ -120,36 +120,52 @@ namespace Nuake
auto& indices = ProcessIndices(node);
auto& material = ProcessMaterials(scene, node);
auto& bones = std::vector<Bone>();
auto& bonesMap = std::unordered_map<std::string, Bone>();
if (node->HasBones())
{
uint32_t boneCounter = 0;
for (uint32_t i = 0; i < node->mNumBones; i++)
{
aiBone* bone = node->mBones[i];
const std::string& boneName = bone->mName.C_Str();
const auto& boneMatrix = bone->mOffsetMatrix;
Bone newBone;
newBone.Name = boneName;
newBone.Offset = ConvertMatrixToGLMFormat(bone->mOffsetMatrix);
int32_t boneId = -1;
if (bonesMap.find(boneName) == bonesMap.end())
{
boneId = boneCounter;
boneCounter++;
Bone newBone = Bone(boneName, boneId);
newBone.Offset = ConvertMatrixToGLMFormat(bone->mOffsetMatrix);
bones.push_back(newBone);
bonesMap[boneName] = newBone;
}
else
{
boneId = bonesMap[boneName].Id;
}
assert(boneId != -1);
const uint32_t numWeight = bone->mNumWeights;
newBone.VertexWeights.reserve(numWeight);
for (uint32_t j = 0; j < numWeight; j++)
{
aiVertexWeight vertexWeight = bone->mWeights[j];
const uint32_t vertexWeightVertexId = vertexWeight.mVertexId;
vertices[vertexWeightVertexId].boneIDs[j] = i;
vertices[vertexWeightVertexId].weights[j] = vertexWeight.mWeight;
BoneVertexWeight boneVertexWeight
{
vertexWeightVertexId,
vertexWeight.mWeight
};
newBone.VertexWeights.push_back(std::move(boneVertexWeight));
SetVertexBoneData(vertices[vertexWeightVertexId], boneId, vertexWeight.mWeight);
//BoneVertexWeight boneVertexWeight
//{
// vertexWeightVertexId,
// vertexWeight.mWeight
//};
//
//Bone& newBone = bones[boneId];
//newBone.VertexWeights.push_back(std::move(boneVertexWeight));
}
bones.push_back(std::move(newBone));
}
}
else
@@ -189,30 +205,30 @@ namespace Nuake
// Position
current.x = mesh->mVertices[i].x;
current.y = mesh->mVertices[i].y;
current.z = mesh->mVertices[i].z;
current.y = mesh->mVertices[i].z;
current.z = mesh->mVertices[i].y;
vertex.position = current;
// Normals
current.x = mesh->mNormals[i].x;
current.y = mesh->mNormals[i].y;
current.z = mesh->mNormals[i].z;
current.y = mesh->mNormals[i].z;
current.z = mesh->mNormals[i].y;
vertex.normal = current;
// Tangents
if (mesh->mTangents)
{
current.x = mesh->mTangents[i].x;
current.y = mesh->mTangents[i].y;
current.z = mesh->mTangents[i].z;
current.y = mesh->mTangents[i].z;
current.z = mesh->mTangents[i].y;
vertex.tangent = current;
}
if (mesh->mBitangents)
{
current.x = mesh->mBitangents[i].x;
current.y = mesh->mBitangents[i].y;
current.z = mesh->mBitangents[i].z;
current.y = mesh->mBitangents[i].z;
current.z = mesh->mBitangents[i].y;
vertex.bitangent = current;
}
@@ -291,6 +307,19 @@ namespace Nuake
return vertices;
}
void ModelLoader::SetVertexBoneData(SkinnedVertex& vertex, int boneID, float weight)
{
for (int i = 0; i < MAX_BONE_INFLUENCE; ++i)
{
if (vertex.boneIDs[i] < 0)
{
vertex.weights[i] = weight;
vertex.boneIDs[i] = boneID;
break;
}
}
}
std::vector<uint32_t> ModelLoader::ProcessIndices(aiMesh* mesh)
{
auto indices = std::vector<uint32_t>();

View File

@@ -45,16 +45,31 @@ namespace Nuake
void ProcessSkinnedNode(aiNode* node, const aiScene* scene);
Ref<SkinnedMesh> ProcessSkinnedMesh(aiMesh* node, const aiScene* scene);
std::vector<SkinnedVertex> ProcessSkinnedVertices(aiMesh* mesh);
void SetVertexBoneData(SkinnedVertex& vertex, int boneId, float weight);
static inline Matrix4 ConvertMatrixToGLMFormat(const aiMatrix4x4& from)
{
Matrix4 to;
//the a,b,c,d in assimp is the row ; the 1,2,3,4 is the column
to[0][0] = from.a1; to[1][0] = from.a2; to[2][0] = from.a3; to[3][0] = from.a4;
to[0][1] = from.b1; to[1][1] = from.b2; to[2][1] = from.b3; to[3][1] = from.b4;
to[0][2] = from.c1; to[1][2] = from.c2; to[2][2] = from.c3; to[3][2] = from.c4;
to[0][3] = from.d1; to[1][3] = from.d2; to[2][3] = from.d3; to[3][3] = from.d4;
return to;
Matrix4 result;
for (auto i = 0; i < 3; i++)
{
for (auto j = 0; j < 3; j++)
{
result[i][j] = from[i][j];
}
}
// The rest would be zero, other than the 4,4.
result[0][3] = 0.0f;
result[1][3] = 0.0f;
result[2][3] = 0.0f;
result[3][0] = 0.0f;
result[3][1] = 0.0f;
result[3][2] = 0.0f;
result[3][3] = 1.0f;
return result;
}
};
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <src/Rendering/Mesh/Bone.h>
namespace Nuake
{
class Animation
{
private:
float m_Duration;
int m_TicksPerSecond;
std::vector<Bone> m_Bones;
//std::map<std::string, BoneInfo> m_BoneInfoMap;
public:
Animation() = default;
Animation();
Bone& FindBone(const std::string& boneName);
float GetTicksPerSecond() const { return m_TicksPerSecond; }
};
}