Enhanced functionality of animation clip container creation #432

Merged
XiaoQiDigipen merged 6 commits from SP3-13-Assets-Manager into main 2023-03-21 14:31:16 +08:00
38 changed files with 1027 additions and 5363 deletions

View File

@ -0,0 +1,7 @@
Name: MD_HomeownerV2Anims
ID: 217758867
Type: 12
Sub Assets:
Name: Full
ID: 227644717
Type: 13

View File

@ -3,6 +3,6 @@
SubPass: G-Buffer Write SubPass: G-Buffer Write
Properties: Properties:
data.color: {x: 1, y: 1, z: 1, w: 1} data.color: {x: 1, y: 1, z: 1, w: 1}
data.textureIndex: 57342922 data.textureIndex: 54758364
data.alpha: 0 data.alpha: 0
data.beta: {x: 1, y: 1, z: 1} data.beta: {x: 1, y: 1, z: 1}

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1,7 +0,0 @@
Name: BoneIKTest4
ID: 81814706
Type: 4
Sub Assets:
Name: Cube
ID: 137599708
Type: 8

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
Name: MD_RigTest01_SkinningTest
ID: 72178939
Type: 4
Sub Assets:
Name: Cube
ID: 141097368
Type: 8

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
Name: MD_RigTest02_HierachyTest1
ID: 80500944
Type: 4
Sub Assets:
Name: Cube.001
ID: 135102560
Type: 8

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
Name: MD_RigTest03_HierachyTest2
ID: 72063399
Type: 4
Sub Assets:
Name: Cube.001
ID: 140361184
Type: 8

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
Name: MD_RigTest04_BakedIKLegTest
ID: 80728853
Type: 4
Sub Assets:
Name: Cube
ID: 149723808
Type: 8

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
Name: MD_RigTest05_MeshDeformTest
ID: 82124728
Type: 4
Sub Assets:
Name: Sphere
ID: 138773466
Type: 8

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
Name: MD_RigTest06_Piston
ID: 76715962
Type: 4
Sub Assets:
Name: Cube
ID: 134911040
Type: 8

View File

@ -64,20 +64,20 @@
Transform Component: Transform Component:
Translate: {x: 0.332949668, y: 0, z: 0} Translate: {x: 0.332949668, y: 0, z: 0}
Rotate: {x: -0, y: 0, z: -0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 0.0710000023, y: 0.0710000023, z: 0.0710000023} Scale: {x: 0.173914507, y: 0.173914507, z: 0.173914507}
IsActive: true IsActive: true
Renderable Component: Renderable Component:
Mesh: 141097368 Mesh: 148542784
Material: 128805346 Material: 121518381
IsActive: true IsActive: true
Animator Component: Animator Component:
Rig: 72178939 Rig: 76586906
AnimationController: 0 AnimationController: 0
IsActive: true IsActive: true
Scripts: Scripts:
- Type: SHADE.Test.AnimTest - Type: SHADE.Test.AnimTest
Enabled: true Enabled: true
fullClip: 231416496 fullClip: 227644717
idleClip: 0 idleClip: 0
runClip: 0 runClip: 0
pickUpClip: 0 pickUpClip: 0

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
Name: TX_Homeowner02
ID: 54758364
Type: 3

View File

@ -71,7 +71,7 @@ namespace SHADE
Play(); Play();
// Set to initial pose // Set to initial pose
if (rig && rig->GetRootNode()) if (rig && !rig->GetRootNodes().empty())
{ {
updateCurrentAnimatorState(currClip, 0.0f); updateCurrentAnimatorState(currClip, 0.0f);
} }
@ -124,7 +124,7 @@ namespace SHADE
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity); std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Do not do anything if is not playing or there's nothing to animate // Do not do anything if is not playing or there's nothing to animate
if (!rig || !rig->GetRootNode()) if (!rig || rig->GetRootNodes().empty())
return; return;
// We want to still display a paused pose, so we only prevent progression // We want to still display a paused pose, so we only prevent progression
@ -274,7 +274,7 @@ namespace SHADE
void SHAnimatorComponent::updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime) void SHAnimatorComponent::updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime)
{ {
// Nothing to animate // Nothing to animate
if (!clip || !rig || !rig->GetRootNode()) if (!clip || !rig || rig->GetRootNodes().empty())
return; return;
// Check that we have animation data // Check that we have animation data
@ -286,7 +286,10 @@ namespace SHADE
} }
void SHAnimatorComponent::updatePoseWithClip(Handle<SHAnimationClip> clip, float poseTime) void SHAnimatorComponent::updatePoseWithClip(Handle<SHAnimationClip> clip, float poseTime)
{ {
updatePoseWithClip(poseTime, clip->GetRawAnimation(), rig->GetRootNode(), SHMatrix::Identity); for (auto rootNode : rig->GetRootNodes())
{
updatePoseWithClip(poseTime, clip->GetRawAnimation(), rootNode, SHMatrix::Identity);
}
} }
void SHAnimatorComponent::updatePoseWithClip(float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix) void SHAnimatorComponent::updatePoseWithClip(float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix)

View File

@ -26,29 +26,31 @@ namespace SHADE
SHRig::SHRig(const SHRigAsset& asset, SHResourceLibrary<SHRigNode>& nodeStore) SHRig::SHRig(const SHRigAsset& asset, SHResourceLibrary<SHRigNode>& nodeStore)
{ {
// Don't bother if empty // Don't bother if empty
if (asset.root == nullptr) if (asset.roots.empty() || *asset.roots.begin() == nullptr)
{ {
SHLOG_ERROR("[SHRig] Attempted to load an invalid rig with no root."); SHLOG_ERROR("[SHRig] Attempted to load an invalid rig with no root.");
return; return;
} }
// Do a recursive depth first traversal to populate the rig // Do a recursive depth first traversal to populate the rig
rootNode = recurseCreateNode(asset, asset.root, nodeStore); for (auto root : asset.roots)
{
auto rootNode = recurseCreateNode(asset, root, nodeStore);
if (rootNode) if (rootNode)
{ {
globalInverseMatrix = SHMatrix::Inverse(rootNode->TransformMatrix); rootNodes.emplace_back(rootNode);
}
} }
} }
SHRig::SHRig(SHRig&& rhs) SHRig::SHRig(SHRig&& rhs)
: rootNode { rhs.rootNode } : rootNodes { std::move(rhs.rootNodes) }
, nodeNames { std::move(rhs.nodeNames) } , nodeNames { std::move(rhs.nodeNames) }
, nodesByName { std::move(rhs.nodesByName) } , nodesByName { std::move(rhs.nodesByName) }
, nodes { std::move(rhs.nodes) } , nodes { std::move(rhs.nodes) }
, nodeIndexMap { std::move(rhs.nodeIndexMap) } , nodeIndexMap { std::move(rhs.nodeIndexMap) }
, globalInverseMatrix { std::move(rhs.globalInverseMatrix) }
{ {
rhs.rootNode = {}; rhs.nodes = {};
} }
SHRig::~SHRig() SHRig::~SHRig()
{ {
@ -63,17 +65,17 @@ namespace SHADE
SHRig& SHRig::operator=(SHRig&& rhs) SHRig& SHRig::operator=(SHRig&& rhs)
{ {
rootNode = rhs.rootNode; rootNodes = std::move(rhs.rootNodes);
nodeNames = std::move(rhs.nodeNames); nodeNames = std::move(rhs.nodeNames);
nodesByName = std::move(rhs.nodesByName); nodesByName = std::move(rhs.nodesByName);
nodes = std::move(rhs.nodes); nodes = std::move(rhs.nodes);
nodeIndexMap = std::move(rhs.nodeIndexMap); nodeIndexMap = std::move(rhs.nodeIndexMap);
globalInverseMatrix = std::move(rhs.globalInverseMatrix);
rhs.rootNode = {}; rhs.rootNodes = {};
return *this; return *this;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Usage Functions */ /* Usage Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -104,11 +104,10 @@ namespace SHADE
/// </returns> /// </returns>
const std::string& GetName(Handle<SHRigNode> node) const noexcept; const std::string& GetName(Handle<SHRigNode> node) const noexcept;
/// <summary> /// <summary>
/// Retrieves the root node of the rig. /// Retrieves a read only reference to the root nodes of this rig.
/// </summary> /// </summary>
/// <returns>Handle to the root node of the rig.</returns> /// <returns>Vector of handles to the root node of the rig.</returns>
Handle<SHRigNode> GetRootNode() const noexcept { return rootNode; } const std::vector<Handle<SHRigNode>>& GetRootNodes() const noexcept { return rootNodes; }
const SHMatrix& GetGlobalInverseMatrix() const noexcept { return globalInverseMatrix; }
/// <summary> /// <summary>
/// Retrieves a node via name. /// Retrieves a node via name.
/// </summary> /// </summary>
@ -132,12 +131,11 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Handle<SHRigNode> rootNode; std::vector<Handle<SHRigNode>> rootNodes;
std::unordered_map<Handle<SHRigNode>, std::string> nodeNames; std::unordered_map<Handle<SHRigNode>, std::string> nodeNames;
std::unordered_map<std::string, Handle<SHRigNode>> nodesByName; std::unordered_map<std::string, Handle<SHRigNode>> nodesByName;
std::vector<Handle<SHRigNode>> nodes; std::vector<Handle<SHRigNode>> nodes;
std::unordered_map<Handle<SHRigNode>, int> nodeIndexMap; std::unordered_map<Handle<SHRigNode>, int> nodeIndexMap;
SHMatrix globalInverseMatrix;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */

View File

@ -5,7 +5,7 @@ namespace SHADE
{ {
SHRigAsset::~SHRigAsset() SHRigAsset::~SHRigAsset()
{ {
if (root != nullptr) if(!roots.empty())
delete[] root; delete[] *roots.begin();
} }
} }

View File

@ -54,6 +54,6 @@ namespace SHADE
~SHRigAsset(); ~SHRigAsset();
SHRigDataHeader header; SHRigDataHeader header;
std::vector<SHRigNodeData> nodeDataCollection{}; std::vector<SHRigNodeData> nodeDataCollection{};
SHRigNodeAsset* root; std::vector<SHRigNodeAsset*> roots;
}; };
} }

View File

@ -102,14 +102,12 @@ namespace SHADE
{ {
ReadRigHeader(file, asset.rig.header); ReadRigHeader(file, asset.rig.header);
ReadRigData(file, asset.rig.header, asset.rig.nodeDataCollection); ReadRigData(file, asset.rig.header, asset.rig.nodeDataCollection);
ReadRigTree(file, asset.rig.header, asset.rig.root); ReadRigTree(file, asset.rig.header, asset.rig.roots);
for (auto& mesh : asset.meshes) for (auto& mesh : asset.meshes)
{ {
mesh->BoneCount = asset.rig.nodeDataCollection.size(); mesh->BoneCount = asset.rig.nodeDataCollection.size();
} }
//BuildTransformMatrices(asset.rig);
} }
} }
@ -140,26 +138,6 @@ namespace SHADE
); );
} }
void SHModelLoader::BuildTransformMatrices(SHRigAsset& rig)
{
std::queue<SHRigNodeAsset const*> nodeQueue;
nodeQueue.push(rig.root);
while(!nodeQueue.empty())
{
auto& current = nodeQueue.front();
nodeQueue.pop();
auto& parentData {rig.nodeDataCollection[current->idRef]};
for (auto const& child: current->children)
{
nodeQueue.push(child);
auto& childData {rig.nodeDataCollection[child->idRef]};
childData.transform = childData.transform * parentData.transform;
}
}
}
void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header) void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header)
{ {
file.read( file.read(
@ -254,7 +232,7 @@ namespace SHADE
} }
} }
void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNodeAsset*& root) void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeAsset*>& roots)
{ {
// Read All nodes into one contiguous data block // Read All nodes into one contiguous data block
struct NodeTemp struct NodeTemp
@ -271,7 +249,7 @@ namespace SHADE
// Build and populate tree // Build and populate tree
SHRigNodeAsset* nodePool = new SHRigNodeAsset[header.nodeCount]; SHRigNodeAsset* nodePool = new SHRigNodeAsset[header.nodeCount];
root = nodePool; roots.push_back(nodePool);
std::queue<std::pair<SHRigNodeAsset*, NodeTemp*>> nodeQueue; std::queue<std::pair<SHRigNodeAsset*, NodeTemp*>> nodeQueue;
nodeQueue.emplace(std::make_pair(nodePool, dst)); nodeQueue.emplace(std::make_pair(nodePool, dst));
@ -279,6 +257,8 @@ namespace SHADE
SHRigNodeAsset* depthPtr = nodePool + 1; SHRigNodeAsset* depthPtr = nodePool + 1;
NodeTemp* depthTempPtr = dst + 1; NodeTemp* depthTempPtr = dst + 1;
uint32_t nodeCount{ 0 };
while(!nodeQueue.empty()) while(!nodeQueue.empty())
{ {
auto currPair = nodeQueue.front(); auto currPair = nodeQueue.front();
@ -288,12 +268,26 @@ namespace SHADE
currNode->idRef = currTemp->id; currNode->idRef = currTemp->id;
nodeCount++;
if (
nodeQueue.empty() &&
currTemp->numChild == 0 &&
nodeCount < header.nodeCount
)
{
roots.push_back(depthPtr);
nodeQueue.emplace(depthPtr++, depthTempPtr++);
}
for (auto i{0}; i < currTemp->numChild; ++i) for (auto i{0}; i < currTemp->numChild; ++i)
{ {
currNode->children.push_back(depthPtr); currNode->children.push_back(depthPtr);
nodeQueue.emplace(depthPtr++, depthTempPtr++); nodeQueue.emplace(depthPtr++, depthTempPtr++);
} }
} }
std::cout << "hi";
} }
void SHModelLoader::ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers, void SHModelLoader::ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers,

View File

@ -23,14 +23,12 @@ namespace SHADE
void ReadRigHeader(FileReference file, SHRigDataHeader& header); void ReadRigHeader(FileReference file, SHRigDataHeader& header);
void ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& data); void ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& data);
void ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNodeAsset*& root); void ReadRigTree(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeAsset*>& roots);
void ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers, std::vector<SHMeshAsset*>& meshes); void ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers, std::vector<SHMeshAsset*>& meshes);
void ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers, std::vector<SHAnimAsset*>& anims); void ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers, std::vector<SHAnimAsset*>& anims);
void ReadAnimNode(FileReference file, uint32_t frameCount, SHAnimNode& data); void ReadAnimNode(FileReference file, uint32_t frameCount, SHAnimNode& data);
void BuildTransformMatrices(SHRigAsset& rig);
void ReadHeaders(FileReference file, SHModelAsset& asset); void ReadHeaders(FileReference file, SHModelAsset& asset);
void ReadData(FileReference file, SHModelAsset& asset); void ReadData(FileReference file, SHModelAsset& asset);
public: public:

View File

@ -494,6 +494,13 @@ namespace SHADE
{ {
auto const models {SHAssetManager::GetAllRecordOfType(AssetType::MODEL)}; auto const models {SHAssetManager::GetAllRecordOfType(AssetType::MODEL)};
std::vector<SHAsset> displayModels;
for (auto const& model : models)
{
auto const data = SHAssetManager::GetConstData<SHModelAsset>(model.id);
if (!data->animHeaders.empty())
displayModels.push_back(model);
}
ImGui::RadioButton("Animation Clip Container", true); ImGui::RadioButton("Animation Clip Container", true);
ImGui::SameLine(); ImGui::SameLine();
@ -502,7 +509,7 @@ namespace SHADE
AssetID selected {0}; AssetID selected {0};
if (ImGui::BeginCombo("##combo", currentItem, ImGuiComboFlags_None)) if (ImGui::BeginCombo("##combo", currentItem, ImGuiComboFlags_None))
{ {
for (auto const& model : models) for (auto const& model : displayModels)
{ {
bool isSelected = currentItem == model.name; bool isSelected = currentItem == model.name;
if (ImGui::Selectable(model.name.data(), isSelected)) if (ImGui::Selectable(model.name.data(), isSelected))