Working skeletal animations!!!

This commit is contained in:
2015-10-15 12:46:23 +02:00
parent 1e3536e060
commit a35d72cac3
16 changed files with 1235 additions and 22 deletions
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+19 -4
View File
@@ -68,6 +68,8 @@
#include "Physics/CParticle.h" #include "Physics/CParticle.h"
#include "Physics/CParticleEmitter.h" #include "Physics/CParticleEmitter.h"
#include "Rendering/AnimationSystem.h"
#include "Game/EGameStart.h" #include "Game/EGameStart.h"
#include "Sound/EPlaySound.h" #include "Sound/EPlaySound.h"
@@ -165,6 +167,9 @@ public:
m_World->SystemFactory.Register<Systems::PhysicsSystem>( m_World->SystemFactory.Register<Systems::PhysicsSystem>(
[this]() { return new Systems::PhysicsSystem(m_World.get(), m_EventBroker); }); [this]() { return new Systems::PhysicsSystem(m_World.get(), m_EventBroker); });
m_World->AddSystem<Systems::PhysicsSystem>(); m_World->AddSystem<Systems::PhysicsSystem>();
m_World->SystemFactory.Register<Systems::AnimationSystem>(
[this]() { return new Systems::AnimationSystem(m_World.get(), m_EventBroker); });
m_World->AddSystem<Systems::AnimationSystem>();
m_World->SystemFactory.Register<Systems::TravellingSystem>( m_World->SystemFactory.Register<Systems::TravellingSystem>(
[this]() { return new Systems::TravellingSystem(m_World.get(), m_EventBroker); }); [this]() { return new Systems::TravellingSystem(m_World.get(), m_EventBroker); });
m_World->AddSystem<Systems::TravellingSystem>(); m_World->AddSystem<Systems::TravellingSystem>();
@@ -457,7 +462,8 @@ public:
glm::mat4 modelMatrix = glm::translate(glm::mat4(), absoluteTransform.Position) glm::mat4 modelMatrix = glm::translate(glm::mat4(), absoluteTransform.Position)
* glm::toMat4(absoluteTransform.Orientation) * glm::toMat4(absoluteTransform.Orientation)
* glm::scale(absoluteTransform.Scale); * glm::scale(absoluteTransform.Scale);
EnqueueModel(modelAsset, modelMatrix, modelComponent->Transparent, modelComponent->Color, modelComponent->ModelFile); Components::Animation* animationComponent = m_World->GetComponent<Components::Animation>(entity);
EnqueueModel(modelAsset, modelMatrix, modelComponent, animationComponent);
} }
} }
@@ -513,7 +519,7 @@ public:
} }
//TODO: Get this out of engine.h //TODO: Get this out of engine.h
void EnqueueModel(Model* model, glm::mat4 modelMatrix, float transparent, glm::vec4 color, std::string fileName) void EnqueueModel(Model* model, glm::mat4 modelMatrix, const Components::Model* modelComponent, const Components::Animation* animationComponent)
{ {
for (auto texGroup : model->TextureGroups) for (auto texGroup : model->TextureGroups)
{ {
@@ -526,8 +532,17 @@ public:
job.ElementBuffer = model->ElementBuffer; job.ElementBuffer = model->ElementBuffer;
job.StartIndex = texGroup.StartIndex; job.StartIndex = texGroup.StartIndex;
job.EndIndex = texGroup.EndIndex; job.EndIndex = texGroup.EndIndex;
job.ModelMatrix = modelMatrix; job.ModelMatrix = modelMatrix * model->m_Matrix;
job.Color = color; job.Color = modelComponent->Color;
if (model->m_Skeleton != nullptr) {
job.Skeleton = model->m_Skeleton;
if (animationComponent != nullptr) {
job.AnimationName = animationComponent->Name;
job.AnimationTime = animationComponent->Time;
job.NoRootMotion = animationComponent->NoRootMotion;
}
}
m_RendererQueue.Deferred.Add(job); m_RendererQueue.Deferred.Add(job);
} }
+2
View File
@@ -86,6 +86,8 @@ public:
std::vector<unsigned int> m_Indices; std::vector<unsigned int> m_Indices;
Skeleton* m_Skeleton = nullptr; Skeleton* m_Skeleton = nullptr;
glm::mat4 m_Matrix;
private: private:
std::vector<glm::ivec2> BoneIndices; std::vector<glm::ivec2> BoneIndices;
std::vector<glm::vec2> BoneWeights; std::vector<glm::vec2> BoneWeights;
+6
View File
@@ -66,6 +66,12 @@ struct ModelJob : RenderJob
unsigned int StartIndex; unsigned int StartIndex;
unsigned int EndIndex; unsigned int EndIndex;
// Animation
Skeleton* Skeleton = nullptr;
bool NoRootMotion = true;
std::string AnimationName;
double AnimationTime = 0;
void CalculateHash() override void CalculateHash() override
{ {
Hash = TextureID; Hash = TextureID;
+5 -4
View File
@@ -100,16 +100,17 @@ public:
int GetBoneID(std::string name); int GetBoneID(std::string name);
std::vector<glm::mat4> GetFrameBones(std::string animationName, double time, bool noRootMotion = false); const Animation* GetAnimation(std::string name);
void AccumulateBoneTransforms(bool noRootMotion, Animation::Keyframe &currentFrame, Animation::Keyframe &nextFrame, float progress, std::map<int, glm::mat4> &boneMatrices, Bone* bone, glm::mat4 parentMatrix); std::vector<glm::mat4> GetFrameBones(const Animation& animation, double time, bool noRootMotion = false);
void AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe& currentFrame, const Animation::Keyframe& nextFrame, float progress, std::map<int, glm::mat4>& boneMatrices, const Bone* bone, glm::mat4 parentMatrix);
void PrintSkeleton(); void PrintSkeleton();
void PrintSkeleton(Bone* parent, int depthCount); void PrintSkeleton(const Bone* parent, int depthCount);
std::map<std::string, Animation> Animations; std::map<std::string, Animation> Animations;
private: private:
std::map<std::string, Bone*> m_BonesByName; std::map<std::string, Bone*> m_BonesByName;
int GetKeyframe(Animation& animation, double time); int GetKeyframe(const Animation& animation, double time);
}; };
} }
+1
View File
@@ -13,6 +13,7 @@
#include "Rendering/CModel.h" #include "Rendering/CModel.h"
#include "Rendering/CSprite.h" #include "Rendering/CSprite.h"
#include "Rendering/CPointLight.h" #include "Rendering/CPointLight.h"
#include "Rendering/CAnimation.h"
#include "Game/CBall.h" #include "Game/CBall.h"
#include "Game/CPowerUp.h" #include "Game/CPowerUp.h"
#include "Game/CLife.h" #include "Game/CLife.h"
+25
View File
@@ -0,0 +1,25 @@
#ifndef AnimationSystem_h__
#define AnimationSystem_h__
#include "Core/System.h"
#include "Core/World.h"
#include "Rendering/CAnimation.h"
namespace dd
{
namespace Systems
{
class AnimationSystem : public System
{
public:
AnimationSystem(World* world, std::shared_ptr<dd::EventBroker> eventBroker)
: System(world, eventBroker) { }
void RegisterComponents(ComponentFactory* cf) override;
void Update(double dt) override;
};
}
}
#endif
+21
View File
@@ -0,0 +1,21 @@
#ifndef COMPONENTS_CANIMATION_H__
#define COMPONENTS_CANIMATION_H__
#include "Core/Component.h"
namespace dd
{
namespace Components
{
struct Animation : Component
{
std::string Name;
double Time = 0.0;
double Speed = 0.0;
bool NoRootMotion = true;
};
}
}
#endif
+1
View File
@@ -50,6 +50,7 @@ source_group(Input FILES ${SOURCE_FILES_Input})
file(GLOB SOURCE_FILES_Rendering file(GLOB SOURCE_FILES_Rendering
"${INCLUDE_PATH}/Rendering/*.h" "${INCLUDE_PATH}/Rendering/*.h"
"Rendering/*.cpp"
) )
source_group(Rendering FILES ${SOURCE_FILES_Rendering}) source_group(Rendering FILES ${SOURCE_FILES_Rendering})
+14
View File
@@ -431,6 +431,20 @@ void dd::Renderer::DrawScene(RenderQueue &objects, ShaderProgram &program)
glBindTexture(GL_TEXTURE_2D, *m_StandardSpecular); glBindTexture(GL_TEXTURE_2D, *m_StandardSpecular);
} }
if (modelJob->Skeleton != nullptr) {
auto animation = modelJob->Skeleton->GetAnimation(modelJob->AnimationName);
if (animation != nullptr) {
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(
*animation,
modelJob->AnimationTime,
modelJob->NoRootMotion
);
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
LOG_WARNING("Tried to play unknown animation \"%s\"", modelJob->AnimationName.c_str());
}
}
glBindVertexArray(modelJob->VAO); glBindVertexArray(modelJob->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->ElementBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex); glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex);
+1 -1
View File
@@ -65,7 +65,7 @@ void main()
+ BoneWeights2[3] * Bones[int(BoneIndices2[3])]; + BoneWeights2[3] * Bones[int(BoneIndices2[3])];
} }
gl_Position = MVP * vec4(Position, 1.0); gl_Position = MVP * boneTransform * vec4(Position, 1.0);
Output.Position = (V * M * boneTransform * vec4(Position, 1.0)).xyz; Output.Position = (V * M * boneTransform * vec4(Position, 1.0)).xyz;
Output.Normal = (inverse(transpose(V * M)) * boneTransform * vec4(Normal, 0.0)).xyz; Output.Normal = (inverse(transpose(V * M)) * boneTransform * vec4(Normal, 0.0)).xyz;
+2 -2
View File
@@ -65,8 +65,8 @@ void main()
+ BoneWeights2[3] * Bones[int(BoneIndices2[3])]; + BoneWeights2[3] * Bones[int(BoneIndices2[3])];
} }
//gl_Position = MVP * boneTransform * vec4(Position, 1.0); gl_Position = MVP * boneTransform * vec4(Position, 1.0);
gl_Position = MVP * vec4(Position, 1.0); //gl_Position = MVP * vec4(Position, 1.0);
//TODO: Make sure that boneTransform works here. //TODO: Make sure that boneTransform works here.
Output.Position = (V * M * boneTransform * vec4(Position, 1.0)).xyz; Output.Position = (V * M * boneTransform * vec4(Position, 1.0)).xyz;
+16 -8
View File
@@ -48,10 +48,18 @@ dd::Skeleton::~Skeleton()
} }
} }
std::vector<glm::mat4> dd::Skeleton::GetFrameBones(std::string animationName, double time, bool noRootMotion /*= false*/) const dd::Skeleton::Animation* dd::Skeleton::GetAnimation(std::string name)
{ {
auto& animation = Animations.at(animationName); auto it = Animations.find(name);
if (it != Animations.end()) {
return const_cast<const Animation*>(&it->second);
} else {
return nullptr;
}
}
std::vector<glm::mat4> dd::Skeleton::GetFrameBones(const Animation& animation, double time, bool noRootMotion /*= false*/)
{
// HACK: Animation wrap-around // HACK: Animation wrap-around
while (time < 0) while (time < 0)
time += animation.Duration; time += animation.Duration;
@@ -60,8 +68,8 @@ std::vector<glm::mat4> dd::Skeleton::GetFrameBones(std::string animationName, do
int currentKeyframeIndex = GetKeyframe(animation, time); int currentKeyframeIndex = GetKeyframe(animation, time);
Animation::Keyframe& currentFrame = animation.Keyframes[currentKeyframeIndex]; const Animation::Keyframe& currentFrame = animation.Keyframes[currentKeyframeIndex];
Animation::Keyframe& nextFrame = animation.Keyframes[currentKeyframeIndex + 1]; const Animation::Keyframe& nextFrame = animation.Keyframes[currentKeyframeIndex + 1];
float alpha = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time); float alpha = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
//auto animationFrame = Animations[""].Keyframes[frame]; //auto animationFrame = Animations[""].Keyframes[frame];
@@ -75,7 +83,7 @@ std::vector<glm::mat4> dd::Skeleton::GetFrameBones(std::string animationName, do
return finalMatrices; return finalMatrices;
} }
void dd::Skeleton::AccumulateBoneTransforms(bool noRootMotion, Animation::Keyframe &currentFrame, Animation::Keyframe &nextFrame, float progress, std::map<int, glm::mat4> &boneMatrices, Bone* bone, glm::mat4 parentMatrix) void dd::Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe &currentFrame, const Animation::Keyframe &nextFrame, float progress, std::map<int, glm::mat4> &boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
{ {
glm::mat4 boneMatrix; glm::mat4 boneMatrix;
@@ -120,7 +128,7 @@ void dd::Skeleton::PrintSkeleton()
PrintSkeleton(RootBone, 0); PrintSkeleton(RootBone, 0);
} }
void dd::Skeleton::PrintSkeleton(Bone* bone, int depthCount) void dd::Skeleton::PrintSkeleton(const Bone* bone, int depthCount)
{ {
std::stringstream ss; std::stringstream ss;
ss << std::string(depthCount, ' '); ss << std::string(depthCount, ' ');
@@ -134,7 +142,7 @@ void dd::Skeleton::PrintSkeleton(Bone* bone, int depthCount)
} }
} }
int dd::Skeleton::GetKeyframe(Animation& animation, double time) int dd::Skeleton::GetKeyframe(const Animation& animation, double time)
{ {
if (time < 0) if (time < 0)
time = 0; time = 0;
@@ -143,7 +151,7 @@ int dd::Skeleton::GetKeyframe(Animation& animation, double time)
for (int keyframe = 0; keyframe < animation.Keyframes.size(); ++keyframe) { for (int keyframe = 0; keyframe < animation.Keyframes.size(); ++keyframe) {
if (animation.Keyframes[keyframe].Time > time) if (animation.Keyframes[keyframe].Time > time)
return keyframe - 1; return glm::max(0, keyframe - 1); // HACK: If the time is less than the first keyframe, don
} }
return 0; return 0;
+4 -2
View File
@@ -35,7 +35,9 @@ void dd::Systems::BallSystem::Initialize()
transform->Scale = glm::vec3(0.3f, 0.3f, 0.3f); transform->Scale = glm::vec3(0.3f, 0.3f, 0.3f);
transform->Velocity = glm::vec3(0.f, 0.f, 0.f); transform->Velocity = glm::vec3(0.f, 0.f, 0.f);
auto model = m_World->AddComponent<Components::Model>(ent); auto model = m_World->AddComponent<Components::Model>(ent);
model->ModelFile = "Models/Test/Ball/Sid.obj"; model->ModelFile = "Models/Sid/Sid.dae";
auto animation = m_World->AddComponent<Components::Animation>(ent);
animation->Speed = 1.0;
std::shared_ptr<Components::CircleShape> circleShape = m_World->AddComponent<Components::CircleShape>(ent); std::shared_ptr<Components::CircleShape> circleShape = m_World->AddComponent<Components::CircleShape>(ent);
circleShape->Radius = 0.4f; circleShape->Radius = 0.4f;
std::shared_ptr<Components::Ball> ball = m_World->AddComponent<Components::Ball>(ent); std::shared_ptr<Components::Ball> ball = m_World->AddComponent<Components::Ball>(ent);
@@ -421,7 +423,7 @@ void dd::Systems::BallSystem::CreateLife(int number)
lifeNr->Number = number; lifeNr->Number = number;
auto model = m_World->AddComponent<Components::Model>(life); auto model = m_World->AddComponent<Components::Model>(life);
model->ModelFile = "Models/Test/Ball/Sid.obj"; model->ModelFile = "Models/Sid/Sid.dae";
m_World->CommitEntity(life); m_World->CommitEntity(life);
+20
View File
@@ -0,0 +1,20 @@
#include "PrecompiledHeader.h"
#include "Rendering/AnimationSystem.h"
void dd::Systems::AnimationSystem::RegisterComponents(ComponentFactory* cf)
{
cf->Register<Components::Animation>();
}
void dd::Systems::AnimationSystem::Update(double dt)
{
auto animations = m_World->GetComponentsOfType<Components::Animation>();
if (animations == nullptr) {
return;
}
for (auto& component : *animations) {
auto animation = static_cast<Components::Animation*>(component.get());
animation->Time += animation->Speed * dt;
}
}