mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-15 20:08:54 +03:00
Started animation resource
This commit is contained in:
@@ -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
|
||||
|
||||
152
Nuake/src/Rendering/Mesh/Bone.cpp
Normal file
152
Nuake/src/Rendering/Mesh/Bone.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
72
Nuake/src/Rendering/Mesh/Bone.h
Normal file
72
Nuake/src/Rendering/Mesh/Bone.h
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
21
Nuake/src/Resource/SkeletalAnimation.h
Normal file
21
Nuake/src/Resource/SkeletalAnimation.h
Normal 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; }
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user