Added BlendTree that stores and blends multiple animations

This commit is contained in:
viktorljung
2016-02-22 15:58:38 +01:00
parent 3c9c95cff4
commit abd36c81f8
20 changed files with 641 additions and 453 deletions
+16 -17
View File
@@ -2,57 +2,56 @@
void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& animationComponent, double dt)
{
if(!entity.HasComponent("Model")) {
return;
}
EntityWrapper parent = entity.FirstParentWithComponent("Model");
Model* model;
try {
model = ResourceManager::Load<::Model, true>(entity["Model"]["Resource"]);
model = ResourceManager::Load<::Model, true>(parent["Model"]["Resource"]);
} catch (const std::exception&) {
return;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if(skeleton == nullptr) {
if (skeleton == nullptr) {
return;
}
for (int i = 1; i <= 3; i++) {
const Skeleton::Animation* animation = skeleton->GetAnimation(animationComponent["AnimationName" + std::to_string(i)]);
for (int i = 1; i <= 1; i++) {
const Skeleton::Animation* animation = skeleton->GetAnimation(animationComponent["AnimationName"]);
if (animation == nullptr) {
continue;;
}
double animationSpeed = (double)animationComponent["Speed" + std::to_string(i)];
double animationSpeed = (double)animationComponent["Speed"];
if (animationSpeed != 0.0) {
double nextTime = (double)animationComponent["Time" + std::to_string(i)] + animationSpeed * dt;
double nextTime = (double)animationComponent["Time"] + animationSpeed * dt;
if (!(bool)animationComponent["Loop" + std::to_string(i)]) {
if (!(bool)animationComponent["Loop"]) {
if (nextTime > animation->Duration) {
nextTime = animation->Duration;
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
e.Name = (std::string)animationComponent["AnimationName"];
m_EventBroker->Publish(e);
} else if (nextTime < 0) {
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
e.Name = (std::string)animationComponent["AnimationName"];
m_EventBroker->Publish(e);
nextTime = 0;
}
(double&)animationComponent["Speed" + std::to_string(i)] = 0.0;
(double&)animationComponent["Speed"] = 0.0;
} else {
if (nextTime > animation->Duration) {
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
e.Name = (std::string)animationComponent["AnimationName"];
m_EventBroker->Publish(e);
while(nextTime > animation->Duration) {
@@ -61,7 +60,7 @@ void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& a
} else if (nextTime < 0) {
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
e.Name = (std::string)animationComponent["AnimationName"];
m_EventBroker->Publish(e);
while (nextTime < 0) {
@@ -70,7 +69,7 @@ void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& a
}
}
(double&)animationComponent["Time" + std::to_string(i)] = nextTime;
(double&)animationComponent["Time"] = nextTime;
}
}
}
+255
View File
@@ -0,0 +1,255 @@
#include "Rendering/BlendTree.h"
BlendTree::BlendTree(EntityWrapper ModelEntity, Skeleton* skeleton)
{
auto itPair = ModelEntity.World->GetChildren(ModelEntity.ID);
if (itPair.first == itPair.second) {
return;
}
if (ModelEntity.HasComponent("Animation")) {
const Skeleton::Animation* animation = skeleton->GetAnimation(ModelEntity["Animation"]["AnimationName"]);
if (animation == nullptr) {
return;
}
m_Root = new Node();
m_Root->Name = ModelEntity.Name();
m_Root->Pose = skeleton->GetFrameBones(animation, (double)ModelEntity["Animation"]["Time"], (bool)ModelEntity["Animation"]["Additive"]);
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Animation;
} else if (ModelEntity.HasComponent("Blend")) {
m_Root = new Node();
m_Root->Name = ModelEntity.Name();
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Blend;
m_Root->Weight = (double)ModelEntity["Blend"]["Weight"];
m_Root->Child[0] = FillTreeByName(m_Root, (std::string)ModelEntity["Blend"]["Pose1"], ModelEntity, skeleton);
m_Root->Child[1] = FillTreeByName(m_Root, (std::string)ModelEntity["Blend"]["Pose2"], ModelEntity, skeleton);
} else if (ModelEntity.HasComponent("BlendOverride")) {
m_Root = new Node();
m_Root->Name = ModelEntity.Name();
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Override;
m_Root->Child[0] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendOverride"]["Master"], ModelEntity, skeleton);
m_Root->Child[1] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendOverride"]["Slave"], ModelEntity, skeleton);
} else if (ModelEntity.HasComponent("BlendAdditive")) {
m_Root = new Node();
m_Root->Name = ModelEntity.Name();
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Additive;
m_Root->Child[0] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendAdditive"]["Adder"], ModelEntity, skeleton);
m_Root->Child[1] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendAdditive"]["Receiver"], ModelEntity, skeleton);
}
// PrintTree();
}
BlendTree::~BlendTree()
{
}
void BlendTree::PrintTree()
{
Node* currentNode = m_Root;
LOG_INFO("\n\n");
while(currentNode->Child[0] != nullptr) {
currentNode = currentNode->Child[0];
}
while (currentNode != nullptr)
{
LOG_INFO("%s", currentNode->Name.c_str());
currentNode = currentNode->Next();
}
}
void BlendTree::FillTree(Node* parentNode, EntityWrapper parentEntity, Skeleton* skeleton)
{
auto itPair = parentEntity.World->GetChildren(parentEntity.ID);
if (itPair.first == itPair.second) {
return; // no children
}
unsigned int childIndex = 0;
for (auto it = itPair.first; it != itPair.second; ++it) {
EntityWrapper childEntity = EntityWrapper(parentEntity.World, it->second);
if(!childEntity.Valid()) {
continue;
}
if (childEntity.HasComponent("Animation")) {
const Skeleton::Animation* animation = skeleton->GetAnimation(childEntity["Animation"]["AnimationName"]);
if(animation == nullptr) {
continue;
}
Node* node = new Node();
node->Name = childEntity.Name();
node->Pose = skeleton->GetFrameBones(animation, (double)childEntity["Animation"]["Time"], (bool)childEntity["Animation"]["Additive"]);
node->Parent = parentNode;
node->Type = NodeType::Animation;
parentNode->Child[childIndex] = node;
childIndex++;
FillTree(node, childEntity, skeleton);
} else if (childEntity.HasComponent("Blend")) {
Node* node = new Node();
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Blend;
node->Weight = (double)childEntity["Blend"]["Weight"];
parentNode->Child[childIndex] = node;
childIndex++;
FillTree(node, childEntity, skeleton);
} else if (childEntity.HasComponent("BlendOverride")) {
Node* node = new Node();
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Override;
parentNode->Child[childIndex] = node;
childIndex++;
FillTree(node, childEntity, skeleton);
} else if (childEntity.HasComponent("BlendAdditive")) {
Node* node = new Node();
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Additive;
parentNode->Child[childIndex] = node;
childIndex++;
FillTree(node, childEntity, skeleton);
}
}
}
BlendTree::Node* BlendTree::FillTreeByName(Node* parentNode, std::string name, EntityWrapper parentEntity, Skeleton* skeleton)
{
EntityWrapper childEntity = parentEntity.FirstChildByName(name);
if (!childEntity.Valid()) {
return nullptr;
}
if (childEntity.HasComponent("Animation")) {
const Skeleton::Animation* animation = skeleton->GetAnimation(childEntity["Animation"]["AnimationName"]);
if (animation == nullptr) {
return nullptr;
}
Node* node = new Node();
node->Name = childEntity.Name();
node->Pose = skeleton->GetFrameBones(animation, (double)childEntity["Animation"]["Time"], (bool)childEntity["Animation"]["Additive"]);
node->Parent = parentNode;
node->Type = NodeType::Animation;
return node;
} else if (childEntity.HasComponent("Blend")) {
Node* node = new Node();
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Blend;
node->Weight = (double)childEntity["Blend"]["Weight"];
node->Child[0] = FillTreeByName(node, (std::string)childEntity["Blend"]["Pose1"], childEntity, skeleton);
node->Child[1] = FillTreeByName(node, (std::string)childEntity["Blend"]["Pose2"], childEntity, skeleton);
return node;
} else if (childEntity.HasComponent("BlendOverride")) {
Node* node = new Node();
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Override;
node->Child[0] = FillTreeByName(node, (std::string)childEntity["BlendOverride"]["Master"], childEntity, skeleton);
node->Child[1] = FillTreeByName(node, (std::string)childEntity["BlendOverride"]["Slave"], childEntity, skeleton);
return node;
} else if (childEntity.HasComponent("BlendAdditive")) {
Node* node = new Node();
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Additive;
node->Child[0] = FillTreeByName(node, (std::string)childEntity["BlendAdditive"]["Adder"], childEntity, skeleton);
node->Child[1] = FillTreeByName(node, (std::string)childEntity["BlendAdditive"]["Receiver"], childEntity, skeleton);
return node;
}
return nullptr;
}
void BlendTree::Blend(Skeleton* skeleton, std::vector<glm::mat4>& pose)
{
Node* currentNode;
Node* start = m_Root;
while (start->Child[0] != nullptr) {
start = start->Child[0];
}
currentNode = start;
LOG_INFO("\n\n");
while (m_Root->Pose.size() == 0) {
if(currentNode->Pose.size() == 0) {
if(currentNode->Child[0]->Pose.size() != 0 && currentNode->Child[1]->Pose.size() != 0) {
switch (currentNode->Type) {
case BlendTree::NodeType::Additive:
currentNode->Pose = skeleton->BlendPoses(currentNode->Child[0]->Pose, currentNode->Child[1]->Pose, currentNode->Weight);
break;
case BlendTree::NodeType::Blend:
currentNode->Pose = skeleton->BlendPoses(currentNode->Child[0]->Pose, currentNode->Child[1]->Pose, currentNode->Weight);
break;
case BlendTree::NodeType::Override:
currentNode->Pose = skeleton->OverridePose(currentNode->Child[0]->Pose, currentNode->Child[1]->Pose);
break;
case BlendTree::NodeType::Animation:
// do nothing
break;
}
LOG_INFO("Blending %s and %s", currentNode->Child[0]->Name.c_str(), currentNode->Child[1]->Name.c_str());
}
}
currentNode = currentNode->Next();
if (currentNode == nullptr) {
currentNode = start;
}
}
pose = m_Root->Pose;
}
std::vector<glm::mat4> BlendTree::GetBoneTransforms(Skeleton* skeleton)
{
if (skeleton == nullptr || m_Root == nullptr) {
std::vector<glm::mat4> pose;
for (auto& b : skeleton->Bones) {
pose.push_back(glm::mat4(1));
}
return pose;
}
std::vector<glm::mat4> pose;
Blend(skeleton, pose);
return pose;
}
@@ -40,15 +40,10 @@ void BoneAttachmentSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp
glm::mat4 boneTransform;
if (parent.HasComponent("Animation")) {
for (int i = 1; i <= 3; i++) {
::Skeleton::AnimationData animationData;
animationData.animation = model->m_RawModel->m_Skeleton->GetAnimation(parent["Animation"]["AnimationName" + std::to_string(i)]);
if (animationData.animation == nullptr) {
continue;
}
animationData.time = (double)parent["Animation"]["Time" + std::to_string(i)];
animationData.weight = (double)parent["Animation"]["Weight" + std::to_string(i)];
::Skeleton::AnimationData animationData;
animationData.animation = model->m_RawModel->m_Skeleton->GetAnimation(parent["Animation"]["AnimationName"]);
if (animationData.animation != nullptr) {
animationData.time = (double)parent["Animation"]["Time"];
Animations.push_back(animationData);
}
}
+24 -16
View File
@@ -338,11 +338,12 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
//bind textures
BindExplosionTextures(explosionSkinnedHandle, explosionEffectJob);
std::vector<glm::mat4> frameBones;
if (explosionEffectJob->AnimationOffset.animation != nullptr) {
/*if (explosionEffectJob->AnimationOffset.animation != nullptr) {
frameBones = explosionEffectJob->Skeleton->GetFrameBones(explosionEffectJob->Animations, explosionEffectJob->AnimationOffset);
} else {
frameBones = explosionEffectJob->Skeleton->GetFrameBones(explosionEffectJob->Animations);
}
}*/
frameBones = explosionEffectJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(explosionSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
m_ExplosionEffectProgram->Bind();
@@ -365,11 +366,12 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
BindExplosionTextures(explosionSplatMapSkinnedHandle, explosionEffectJob);
GLERROR("asdasd");
std::vector<glm::mat4> frameBones;
if (explosionEffectJob->AnimationOffset.animation != nullptr) {
/*if (explosionEffectJob->AnimationOffset.animation != nullptr) {
frameBones = explosionEffectJob->Skeleton->GetFrameBones(explosionEffectJob->Animations, explosionEffectJob->AnimationOffset);
} else {
frameBones = explosionEffectJob->Skeleton->GetFrameBones(explosionEffectJob->Animations);
}
}*/
frameBones = explosionEffectJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(explosionSplatMapSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
@@ -410,11 +412,12 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
//bind textures
BindModelTextures(forwardSkinnedHandle, modelJob);
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/* if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->BlendTree->GetBoneTransforms(modelJob->Skeleton);
glUniformMatrix4fv(glGetUniformLocation(forwardSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
@@ -438,11 +441,12 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
BindModelTextures(forwardSplatMapSkinnedHandle, modelJob);
GLERROR("asdasd");
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/* if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->BlendTree->GetBoneTransforms(modelJob->Skeleton);
glUniformMatrix4fv(glGetUniformLocation(forwardSplatMapSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
@@ -486,11 +490,12 @@ void DrawFinalPass::DrawShieldToStencilBuffer(std::list<std::shared_ptr<RenderJo
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/*if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
m_ShieldToStencilProgram->Bind();
@@ -544,11 +549,12 @@ void DrawFinalPass::DrawShieldedModelRenderQueue(std::list<std::shared_ptr<Rende
}
std::vector<glm::mat4> frameBones;
if (explosionEffectJob->AnimationOffset.animation != nullptr) {
/* if (explosionEffectJob->AnimationOffset.animation != nullptr) {
frameBones = explosionEffectJob->Skeleton->GetFrameBones(explosionEffectJob->Animations, explosionEffectJob->AnimationOffset);
} else {
frameBones = explosionEffectJob->Skeleton->GetFrameBones(explosionEffectJob->Animations);
}
}*/
frameBones = explosionEffectJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(explosionHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
if (GLERROR("Animation")) {
@@ -583,11 +589,12 @@ void DrawFinalPass::DrawShieldedModelRenderQueue(std::list<std::shared_ptr<Rende
BindModelTextures(forwardHandle ,modelJob);
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/* if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(forwardHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
@@ -619,11 +626,12 @@ void DrawFinalPass::DrawToDepthBuffer(std::list<std::shared_ptr<RenderJob>>& job
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/*if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
+12 -8
View File
@@ -103,11 +103,12 @@ void PickingPass::Draw(RenderScene& scene)
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/*if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
@@ -160,11 +161,12 @@ void PickingPass::Draw(RenderScene& scene)
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/* if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
m_PickingProgram->Bind();
@@ -215,11 +217,12 @@ void PickingPass::Draw(RenderScene& scene)
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/* if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
@@ -276,11 +279,12 @@ void PickingPass::Draw(RenderScene& scene)
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
/*if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
}*/
frameBones = modelJob->Skeleton->GetFrameBones();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
+99 -214
View File
@@ -41,29 +41,17 @@ const Skeleton::Animation* Skeleton::GetAnimation(std::string name)
}
}
std::vector<glm::mat4> Skeleton::GetFrameBones(std::vector<AnimationData> animations, bool noRootMotion /*= false*/)
std::vector<glm::mat4> Skeleton::GetFrameBones()
{
if (animations.size() <= 0) {
std::vector<glm::mat4> finalMatrices;
for (auto& b : Bones) {
finalMatrices.push_back(glm::mat4(1));//b.second->OffsetMatrix);
}
return finalMatrices;
}
std::map<int, glm::mat4> frameBones;
AccumulateBoneTransforms(true, animations, frameBones, RootBone, glm::mat4(1));
std::vector<glm::mat4> finalMatrices;
for (auto &kv : frameBones) {
finalMatrices.push_back(kv.second);
for (auto& b : Bones) {
finalMatrices.push_back(glm::mat4(1));
}
return finalMatrices;
}
std::vector<glm::mat4> Skeleton::GetFrameBones(std::vector<AnimationData> animations, AnimationOffset animationOffset, bool noRootMotion /*= false*/)
std::vector<glm::mat4> Skeleton::GetFrameBones(const Animation* animation, const double time, bool additive, bool noRootMotion /*= false*/)
{
if (animations.size() <= 0 || animationOffset.animation == nullptr) {
if (animation == nullptr) {
std::vector<glm::mat4> finalMatrices;
for (auto& b : Bones) {
finalMatrices.push_back(glm::mat4(1));
@@ -71,9 +59,9 @@ std::vector<glm::mat4> Skeleton::GetFrameBones(std::vector<AnimationData> animat
return finalMatrices;
}
std::map<int, glm::mat4> frameBones;
AccumulateBoneTransforms(true, animations, animationOffset, frameBones, RootBone, glm::mat4(1));
AccumulateBoneTransforms(true, animation, time, frameBones, additive, RootBone, glm::mat4(1));
std::vector<glm::mat4> finalMatrices;
for (auto &kv : frameBones) {
@@ -82,175 +70,74 @@ std::vector<glm::mat4> Skeleton::GetFrameBones(std::vector<AnimationData> animat
return finalMatrices;
}
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, std::vector<AnimationData> animations, std::map<int, glm::mat4>& boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation* animation, double time, std::map<int, glm::mat4>& boneMatrices, bool additive, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
std::vector<JointFramePose> JointPoses;
for (const AnimationData animationData : animations) {
const Animation* animation = animationData.animation;
const float time = animationData.time;
JointFramePose jointPose;
jointPose.Weight = animationData.weight;;
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
if (progress > 1.0f || progress < 0.0f) {
progress = glm::clamp(progress, 0.0f, 1.0f);
}
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
glm::vec3 position = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
glm::quat rotation = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
glm::vec3 scale = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
position.x = 0;
position.z = 0;
}
jointPose.Pose = (glm::translate(position) * glm::toMat4(rotation) * glm::scale(scale));
JointPoses.push_back(jointPose);
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
jointPose.Pose = (glm::translate(currentFrame.BoneProperties.Position) * glm::toMat4(currentFrame.BoneProperties.Rotation) * glm::scale(currentFrame.BoneProperties.Scale));
JointPoses.push_back(jointPose);
}
} else { // 0 keyframes for the current bone
}
if (additive) {
time += 1.0/60.0; // first frame is a reference frame
}
glm::mat4 boneMatrix;
if (JointPoses.size() == 0) {
if (bone->Parent) {
glm::mat4 jointPose = (glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix);
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
boneMatrix = parentMatrix * jointPose;
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
boneMatrix = glm::inverse(bone->OffsetMatrix);
boneMatrices[bone->ID] = parentMatrix;
}
} else {
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
float totalWeight = 0;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
for (JointFramePose jointFramePose : JointPoses) {
totalWeight += jointFramePose.Weight;
}
float progress;
glm::mat4 finalBlend = glm::mat4(0);
for (JointFramePose jointFramePose : JointPoses) {
if (jointFramePose.Weight == 1.0f) {
finalBlend = jointFramePose.Pose;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
finalBlend += jointFramePose.Pose * (jointFramePose.Weight / totalWeight);
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
progress = glm::clamp(progress, 0.0f, 1.0f);
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
glm::vec3 position = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
glm::quat rotation = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
glm::vec3 scale = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
position.x = 0;
position.z = 0;
}
boneMatrix = parentMatrix * (glm::translate(position) * glm::toMat4(rotation) * glm::scale(scale));
boneMatrices[bone->ID] = boneMatrix *bone->OffsetMatrix;
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
boneMatrix = parentMatrix * (glm::translate(currentFrame.BoneProperties.Position) * glm::toMat4(currentFrame.BoneProperties.Rotation) * glm::scale(currentFrame.BoneProperties.Scale));
boneMatrices[bone->ID] = boneMatrix *bone->OffsetMatrix;
}
boneMatrix = parentMatrix * finalBlend;
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
}
for (auto &child : bone->Children) {
AccumulateBoneTransforms(noRootMotion, animations, boneMatrices, child, boneMatrix);
}
}
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, std::vector<AnimationData> animations, AnimationOffset animationOffset, std::map<int, glm::mat4>& boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
std::vector<JointFramePose> JointPoses;
for (const AnimationData animationData : animations) {
if (animationData.animation->JointAnimations.find(bone->ID) != animationData.animation->JointAnimations.end()) { // Does the bone have any keyframes in this animation?
JointFramePose jointPose;
jointPose.Weight = animationData.weight;
jointPose.Type = animationData.blendType;
jointPose.Level = animationData.level;
jointPose.Pose = GetBonePose(bone, animationData.animation, animationData.time, noRootMotion);
JointPoses.push_back(jointPose);
}
}
if (JointPoses.size() == 0) { // No keyframes for the current bone
} else { // 0 keyframes for the current bone
if (bone->Parent) {
glm::mat4 jointPose = (glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix);
glm::mat4 boneTransform = AdditiveBlend(bone, animationOffset, jointPose);
boneMatrix = parentMatrix * boneTransform;
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
boneMatrix = parentMatrix * (glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix);
boneMatrices[bone->ID] = boneMatrix *bone->OffsetMatrix;
} else {
boneMatrix = glm::inverse(bone->OffsetMatrix);
boneMatrices[bone->ID] = parentMatrix;
}
} else {
glm::mat4 finalBlend = glm::mat4(0);
glm::mat4 finalOverride = glm::mat4(0);
int maxLevel = 0;
for (JointFramePose jointPose : JointPoses) {
maxLevel = jointPose.Level > maxLevel ? jointPose.Level : maxLevel;
}
for (JointFramePose jointPose : JointPoses) {
if (jointPose.Type == BlendType::Override) {
finalOverride += jointPose.Pose * jointPose.Weight; //Blend Overrides then apply to final blend
} else if(jointPose.Type == BlendType::Blend) {
finalBlend += jointPose.Pose * jointPose.Weight;
} else if (jointPose.Type == BlendType::Additive) {
//Soon
}
}
if(finalOverride != glm::mat4(0)) {
finalBlend = finalOverride;
}
glm::mat4 boneTransform = AdditiveBlend(bone, animationOffset, finalBlend);
boneMatrix = parentMatrix * boneTransform;
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
}
for (auto &child : bone->Children) {
AccumulateBoneTransforms(noRootMotion, animations, animationOffset, boneMatrices, child, boneMatrix);
AccumulateBoneTransforms(noRootMotion, animation, time, boneMatrices, additive, child, boneMatrix);
}
}
@@ -444,7 +331,6 @@ glm::mat4 Skeleton::GetBoneTransform(const Bone* bone, const Animation* animatio
}
}
glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector<AnimationData> animations, AnimationOffset animationOffset, glm::mat4 childMatrix)
{
glm::mat4 boneMatrix;
@@ -555,7 +441,6 @@ glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::v
}
}
glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector<AnimationData> animations, glm::mat4 childMatrix)
{
glm::mat4 boneMatrix;
@@ -673,6 +558,50 @@ glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::v
return boneMatrix;
}
std::vector<glm::mat4> Skeleton::BlendPoses(std::vector<glm::mat4> pose1, std::vector<glm::mat4> pose2, float weight)
{
std::vector<glm::mat4> finalPose;
if(pose1.size() != pose2.size()) {
LOG_ERROR("Number of bones does not match");
return finalPose;
}
for (int i = 0; i < pose1.size(); i++) {
glm::mat4 blendedPose = glm::mat4(0);
blendedPose += pose1[i] * weight;
blendedPose += pose2[i] * (1.f - weight);
finalPose.push_back(blendedPose);
}
return finalPose;
}
std::vector<glm::mat4> Skeleton::OverridePose(std::vector<glm::mat4> overridePose, std::vector<glm::mat4> targetPose)
{
std::vector<glm::mat4> finalPose;
if (overridePose.size() != targetPose.size()) {
LOG_ERROR("Number of bones does not match");
return finalPose;
}
for (int i = 0; i < overridePose.size(); i++) {
if(overridePose[i] != glm::mat4(1)) {
finalPose.push_back(overridePose[i]);
} else {
finalPose.push_back(targetPose[i]);
}
}
return finalPose;
}
int Skeleton::GetBoneID(std::string name)
{
if (m_BonesByName.find(name) == m_BonesByName.end()) {
@@ -681,47 +610,3 @@ int Skeleton::GetBoneID(std::string name)
return m_BonesByName.at(name)->ID;
}
}
void Skeleton::PrintSkeleton()
{
if (LOG_LEVEL < LOG_LEVEL_DEBUG) {
return;
}
PrintSkeleton(RootBone, 0);
}
void Skeleton::PrintSkeleton(const Bone* bone, int depthCount)
{
std::stringstream ss;
ss << std::string(depthCount, ' ');
ss << bone->ID << ": " << bone->Name;
std::cout << ss.str() << std::endl;
depthCount++;
for (auto &child : bone->Children) {
PrintSkeleton(child, depthCount);
}
}
int Skeleton::GetKeyframe(const Animation& animation, double time)
{
/*
if (time < 0) {
time = 0;
}
if (time >= animation.Duration) {
return animation..size() - 1;
}
for (int keyframe = 0; keyframe < animation.Keyframes.size(); ++keyframe) {
if (animation.Keyframes[keyframe].Time > time) {
return (keyframe - 1) % animation.Keyframes.size();
}
}
*/
return 0;
}