Skip to content

Commit

Permalink
Added motion weave asset
Browse files Browse the repository at this point in the history
  • Loading branch information
Cooltomten committed Dec 28, 2023
1 parent 3ae4ca5 commit e25e21d
Show file tree
Hide file tree
Showing 13 changed files with 404 additions and 8 deletions.
86 changes: 78 additions & 8 deletions Volt/Sandbox/src/Sandbox/Window/AssetBrowser/AssetBrowserPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <Volt/Asset/ParticlePreset.h>
#include <Volt/Asset/Rendering/PostProcessingMaterial.h>
#include <Volt/Asset/Rendering/PostProcessingStack.h>
#include <Volt/Asset/Animation/MotionWeaveAsset.h>

#include <Volt/Animation/BlendSpace.h>

Expand Down Expand Up @@ -316,6 +317,7 @@ void AssetBrowserPanel::UpdateMainContent()

CreateNewShaderModal();
CreateNewMonoScriptModal();
CreateNewMotionWeaveGraphModal();
DeleteFilesModal();
}

Expand Down Expand Up @@ -926,20 +928,29 @@ void AssetBrowserPanel::RenderWindowRightClickPopup()

if (ImGui::BeginMenu("Animation##Menu"))
{
if (ImGui::MenuItem("Animated Character"))
if (ImGui::MenuItem("Motion Weave Graph"))
{
CreateNewAssetInCurrentDirectory(Volt::AssetType::AnimatedCharacter);
CreateNewAssetInCurrentDirectory(Volt::AssetType::MotionWeave);
}

if (ImGui::MenuItem("Animation Graph"))
if (ImGui::BeginMenu("Legacy##Menu"))
{
CreateNewAssetInCurrentDirectory(Volt::AssetType::AnimationGraph);
}
if (ImGui::MenuItem("Animated Character"))
{
CreateNewAssetInCurrentDirectory(Volt::AssetType::AnimatedCharacter);
}

if (ImGui::MenuItem("Blend Space"))
{
CreateNewAssetInCurrentDirectory(Volt::AssetType::BlendSpace);
if (ImGui::MenuItem("Animation Graph"))
{
CreateNewAssetInCurrentDirectory(Volt::AssetType::AnimationGraph);
}

if (ImGui::MenuItem("Blend Space"))
{
CreateNewAssetInCurrentDirectory(Volt::AssetType::BlendSpace);
}
}

ImGui::EndMenu();
}

Expand Down Expand Up @@ -1316,6 +1327,7 @@ void AssetBrowserPanel::CreateNewAssetInCurrentDirectory(Volt::AssetType type)
case Volt::AssetType::MonoScript: originalName = "idk.cs"; break;
case Volt::AssetType::PostProcessingStack: originalName = "PPS_NewPostStack"; break;
case Volt::AssetType::PostProcessingMaterial: originalName = "PPM_NewPostMaterial"; break;
case Volt::AssetType::MotionWeave: originalName = "MW_NewMotionWeave"; break;
}

tempName = originalName;
Expand Down Expand Up @@ -1422,6 +1434,13 @@ void AssetBrowserPanel::CreateNewAssetInCurrentDirectory(Volt::AssetType type)
newAssetHandle = postStack->handle;
break;
}

case Volt::AssetType::MotionWeave:
{
UI::OpenModal("New Motion Weave Graph##assetBrowser");
m_MotionWeaveTargetSkeleton = 0;
break;
}
}

Reload();
Expand Down Expand Up @@ -1691,3 +1710,54 @@ void AssetBrowserPanel::CreateNewMonoScriptModal()
UI::EndModal();
}
}

void AssetBrowserPanel::CreateNewMotionWeaveGraphModal()
{
if (UI::BeginModal("New Motion Weave Graph##assetBrowser"))
{
static std::string name;

if (UI::BeginProperties("MotionWeaveProperties"))
{
UI::Property("Name", name);
EditorUtils::Property("Target Skeleton", m_MotionWeaveTargetSkeleton, Volt::AssetType::Skeleton);

UI::EndProperties();
}

const bool cantCreate = m_MotionWeaveTargetSkeleton == 0;
ImGui::BeginDisabled(cantCreate);
if (ImGui::Button("Create"))
{
const std::string extension = Volt::AssetManager::GetExtensionFromAssetType(Volt::AssetType::MotionWeave);
Ref<Volt::MotionWeaveAsset> motionWeave = Volt::AssetManager::CreateAsset<Volt::MotionWeaveAsset>(
Volt::AssetManager::GetRelativePath(myCurrentDirectory->path), name + extension, m_MotionWeaveTargetSkeleton);
Volt::AssetManager::SaveAsset(motionWeave);

ImGui::CloseCurrentPopup();
}
ImGui::EndDisabled();
if (cantCreate)
{
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
{
ImGui::BeginTooltip();
if (m_MotionWeaveTargetSkeleton == 0)
{
ImGui::Text("Need to select a skeleton to create");
}
ImGui::EndTooltip();
}

}
ImGui::SameLine();

if (ImGui::Button("Cancel"))
{
name = "";
ImGui::CloseCurrentPopup();
}

UI::EndModal();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class AssetBrowserPanel : public EditorWindow
void CreateNewAssetInCurrentDirectory(Volt::AssetType type);
void CreateNewShaderModal();
void CreateNewMonoScriptModal();
void CreateNewMotionWeaveGraphModal();

struct NewShaderData
{
Expand Down Expand Up @@ -119,6 +120,9 @@ class AssetBrowserPanel : public EditorWindow
///// Animation Graph creation /////
NewAnimationGraphData myNewAnimationGraphData{};

///// Motion Weave creation /////
Volt::AssetHandle m_MotionWeaveTargetSkeleton = 0;

Ref<AssetBrowser::DirectoryItem> ProcessDirectory(const std::filesystem::path& path, AssetBrowser::DirectoryItem* parent);
std::unordered_map <std::filesystem::path, Ref<AssetBrowser::DirectoryItem>> myDirectories;
Ref<AssetBrowser::SelectionManager> mySelectionManager;
Expand Down
86 changes: 86 additions & 0 deletions Volt/Volt/src/Volt/Animation/MotionWeaver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "vtpch.h"
#include "MotionWeaver.h"
#include "Volt/Log/Log.h"

#include "Volt/Animation/AnimationManager.h"

#include "Volt/Asset/Animation/Animation.h"
#include "Volt/Asset/Animation/Skeleton.h"
#include "Volt/Asset/AssetManager.h"

namespace Volt
{

MotionWeaver::MotionWeaver(Ref<MotionWeaveAsset> motionWeaveAsset, Ref<Skeleton> skeleton)
: m_MotionWeaveAsset(motionWeaveAsset), m_Skeleton(skeleton)
{
assert(m_MotionWeaveAsset);
assert(m_Skeleton);
}

MotionWeaver::~MotionWeaver()
{
}

void MotionWeaver::Update(float deltaTime)
{
if (m_MotionWeaveAsset->GetMotionWeaveAssetEntries().empty())
{
return;
}

if (m_Entries.empty())
{
MotionWeaveAssetEntry& entry = m_MotionWeaveAsset->GetMotionWeaveAssetEntries()[0];

MotionWeaveEntry newEntry;
newEntry.animation = AssetManager::GetAsset<Animation>(entry.animation);
newEntry.speed = 1;
newEntry.weight = 1;
newEntry.looping = true;
newEntry.startTime = 0;

m_Entries.push_back(newEntry);
}
}

const std::vector<glm::mat4> MotionWeaver::Sample()
{
if (m_Entries.empty())
{
return std::vector<glm::mat4>();
}

auto targetEntry = m_Entries.front();
const Animation::Pose sample = targetEntry.animation->SamplePose(targetEntry.startTime, AnimationManager::globalClock, m_Skeleton, targetEntry.looping, targetEntry.speed);
const auto& invBindPose = m_Skeleton->GetInverseBindPose();

if(sample.localTRS.size() != invBindPose.size())
{
VT_CORE_ERROR("Sampled pose size does not match inverse bind pose size");
return std::vector<glm::mat4>();
}
if (sample.localTRS.empty())
{
VT_CORE_ERROR("Sampled pose is empty");
return std::vector<glm::mat4>();
}

std::vector<glm::mat4> result{};
result.resize(sample.localTRS.size());

glm::vec3 rootMotion = sample.localTRS[0].position - m_PrevRootPosition;
m_PrevRootPosition = sample.localTRS[0].position;

for (size_t i = 0; i < sample.localTRS.size(); i++)
{
const auto& trs = sample.localTRS.at(i);

const glm::mat4 transform = glm::translate(glm::mat4{ 1.f }, trs.position)* glm::mat4_cast(trs.rotation)* glm::scale(glm::mat4{ 1.f }, trs.scale);
result[i] = transform * invBindPose[i];
}

return result;
}

}
43 changes: 43 additions & 0 deletions Volt/Volt/src/Volt/Animation/MotionWeaver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include "Volt/Asset/Animation/MotionWeaveAsset.h"

#include <glm/glm.hpp>

//this class will be used to control the animation of a character
//It works by having a main animation and a list of all the previous animations, the main animation has a weight that increases to 1 over time, the previous animations have a weight that decreases to 0 over time
//when the weight of a previous animation reaches 0, it is removed from the list
namespace Volt
{
class Animation;
class Skeleton;

struct MotionWeaveEntry
{
Ref<Animation> animation;
float weight = 0.f;
float speed = 1.f;
float startTime = 0.f;
bool looping = true;
};
class MotionWeaver
{
public:
MotionWeaver(Ref<MotionWeaveAsset> motionWeaveAsset, Ref<Skeleton> skeleton);
~MotionWeaver();

void Update(float deltaTime);

const std::vector<glm::mat4> Sample();

private:
Ref<MotionWeaveAsset> m_MotionWeaveAsset;
Ref<Skeleton> m_Skeleton;

glm::vec3 m_PrevRootPosition;

std::vector<MotionWeaveEntry> m_Entries;

};

}
70 changes: 70 additions & 0 deletions Volt/Volt/src/Volt/Asset/Animation/Animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,50 @@ namespace Volt
return result;
}

const Animation::Pose Animation::SamplePose(float aStartTime, float aCurrentTime, Ref<Skeleton> aSkeleton, bool looping, float speed) const
{
VT_PROFILE_FUNCTION();

const float finalDuration = myDuration / speed;

const float localTime = aCurrentTime - aStartTime;
const float normalizedTime = localTime / finalDuration;

const int32_t frameCount = (int32_t)myFrames.size();
int32_t currentFrameIndex = (int32_t)(std::floor(normalizedTime * (float)frameCount)) % frameCount;

if (normalizedTime > 1.f && !looping)
{
currentFrameIndex = frameCount - 1;
}

currentFrameIndex = std::clamp(currentFrameIndex, 0, frameCount - 1);

const float blendValue = (fmodf(normalizedTime, 1.f) * ((float)frameCount)) - (float)currentFrameIndex;

int32_t nextFrameIndex = currentFrameIndex + 1;

if (nextFrameIndex >= frameCount)
{
if (looping)
{
nextFrameIndex = 0;
}
else
{
nextFrameIndex = currentFrameIndex;
}
}

const Pose& currentFrame = myFrames.at(currentFrameIndex);
const Pose& nextFrame = myFrames.at(nextFrameIndex);

Pose result = currentFrame;
result.BlendWith(nextFrame, blendValue);

return result;
}

const bool Animation::IsAtEnd(float startTime, float speed)
{
const float localTime = AnimationManager::globalClock - startTime;
Expand Down Expand Up @@ -293,5 +337,31 @@ namespace Volt

return animData;
}

void Animation::Pose::BlendWith(const Pose& other, float weight)
{
assert(localTRS.size() == other.localTRS.size());
for (size_t i = 0; i < localTRS.size(); i++)
{
// Blend
localTRS[i].position = glm::mix(localTRS[i].position, other.localTRS[i].position, weight);
localTRS[i].rotation = glm::slerp(glm::normalize(localTRS[i].rotation), glm::normalize(other.localTRS[i].rotation), weight);
localTRS[i].scale = glm::mix(localTRS[i].scale, other.localTRS[i].scale, weight);
}
}
std::vector<glm::mat4> Animation::Pose::GetGlobalTransforms(const std::vector<glm::mat4>& invBindPose) const
{
std::vector<glm::mat4> result{};
result.resize(localTRS.size());

for (size_t i = 0; i < localTRS.size(); i++)
{
const Animation::TRS& trs = localTRS.at(i);

const glm::mat4 transform = glm::translate(glm::mat4{ 1.f }, trs.position)* glm::mat4_cast(trs.rotation)* glm::scale(glm::mat4{ 1.f }, trs.scale);
result[i] = transform * invBindPose[i];
}
return result;
}
}

6 changes: 6 additions & 0 deletions Volt/Volt/src/Volt/Asset/Animation/Animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ namespace Volt
struct Pose
{
std::vector<TRS> localTRS;

void BlendWith(const Pose& other, float weight);
std::vector<glm::mat4> GetGlobalTransforms(const std::vector<glm::mat4>& invBindPose) const;
};

const std::vector<glm::mat4> Sample(float aStartTime, Ref<Skeleton> aSkeleton, bool looping);
const std::vector<glm::mat4> Sample(uint32_t frameIndex, Ref<Skeleton> aSkeleton);

const std::vector<TRS> SampleTRS(float aStartTime, Ref<Skeleton> aSkeleton, bool looping, float speed = 1.f) const;

const Pose SamplePose(float aStartTime,float aCurrentTime, Ref<Skeleton> aSkeleton, bool looping, float speed = 1.f) const;

const bool IsAtEnd(float startTime, float speed);
const bool HasPassedTime(float startTime, float speed, float time);

Expand Down
14 changes: 14 additions & 0 deletions Volt/Volt/src/Volt/Asset/Animation/MotionWeaveAsset.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "vtpch.h"
#include "MotionWeaveAsset.h"

namespace Volt
{
MotionWeaveAsset::MotionWeaveAsset(Volt::AssetHandle targetSkeletonHandle)
:m_TargetSkeletonHandle(targetSkeletonHandle)
{
}
std::vector<MotionWeaveAssetEntry> Volt::MotionWeaveAsset::GetMotionWeaveAssetEntries()
{
return m_MotionWeaveAssetEntries;
}
}
Loading

0 comments on commit e25e21d

Please sign in to comment.