Animation WIP merge #321
|
@ -83,10 +83,21 @@ namespace SHADE
|
||||||
if (currClip == newClip)
|
if (currClip == newClip)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Set parameters
|
||||||
currClip = newClip;
|
currClip = newClip;
|
||||||
secsPerTick = 1.0f / currClip->GetTicksPerSecond();
|
secsPerTick = 1.0f / currClip->GetTicksPerSecond();
|
||||||
|
|
||||||
if (rig)
|
// Build channel map
|
||||||
|
channelMap.clear();
|
||||||
|
if (currClip)
|
||||||
|
{
|
||||||
|
for (const auto& channel : currClip->GetChannels())
|
||||||
|
{
|
||||||
|
channelMap.emplace(channel.Name, &channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rig && currClip)
|
||||||
{
|
{
|
||||||
updatePoseWithClip(0.0f);
|
updatePoseWithClip(0.0f);
|
||||||
}
|
}
|
||||||
|
@ -123,36 +134,45 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
void SHAnimatorComponent::updatePoseWithClip(float poseTime)
|
void SHAnimatorComponent::updatePoseWithClip(float poseTime)
|
||||||
{
|
{
|
||||||
for (const auto& channel : currClip->GetChannels())
|
|
||||||
{
|
|
||||||
// Get the bone
|
|
||||||
std::queue<Handle<SHRig::Node>> bones;
|
|
||||||
bones.push(rig->GetNode(channel.Name));
|
|
||||||
while (!bones.empty())
|
|
||||||
{
|
|
||||||
// Select bone at front of the queue
|
|
||||||
auto bone = bones.front(); bones.pop();
|
|
||||||
if (!bone)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Add any children to the queue
|
|
||||||
for (auto child : bone->Children)
|
|
||||||
{
|
|
||||||
bones.push(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get closest frame index
|
// Get closest frame index
|
||||||
const int CLOSEST_FRAME_IDX = static_cast<int>(std::floorf(poseTime * currClip->GetTicksPerSecond()));
|
const int CLOSEST_FRAME_IDX = static_cast<int>(std::floorf(poseTime * currClip->GetTicksPerSecond()));
|
||||||
|
updatePoseWithClip(CLOSEST_FRAME_IDX, poseTime, rig->GetRootNode(), SHMatrix::Identity);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the matrix from interpolated values
|
void SHAnimatorComponent::updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix)
|
||||||
const int BONE_MTX_IDX = rig->GetNodeIndex(bone);
|
{
|
||||||
boneMatrices[BONE_MTX_IDX] = boneMatrices[BONE_MTX_IDX] * SHMatrix::Transform
|
// Check if there is a channel for this node
|
||||||
|
const std::string& BONE_NAME = rig->GetName(node);
|
||||||
|
SHMatrix transformMatrix = SHMatrix::Identity;
|
||||||
|
if (channelMap.contains(BONE_NAME))
|
||||||
|
{
|
||||||
|
const auto CHANNEL = channelMap[BONE_NAME];
|
||||||
|
transformMatrix = SHMatrix::Transform
|
||||||
(
|
(
|
||||||
getInterpolatedValue(channel.PositionKeyFrames, CLOSEST_FRAME_IDX, poseTime),
|
getInterpolatedValue(CHANNEL->PositionKeyFrames, closestFrameIndex, poseTime),
|
||||||
getInterpolatedValue(channel.RotationKeyFrames, CLOSEST_FRAME_IDX, poseTime),
|
getInterpolatedValue(CHANNEL->RotationKeyFrames, closestFrameIndex, poseTime),
|
||||||
getInterpolatedValue(channel.ScaleKeyFrames , CLOSEST_FRAME_IDX, poseTime)
|
getInterpolatedValue(CHANNEL->ScaleKeyFrames, closestFrameIndex, poseTime)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transformMatrix = SHMatrix::Inverse(node->OffsetMatrix); // TODO: Use TransformMatrix for the bone
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply parent's transformation
|
||||||
|
transformMatrix = parentMatrix * transformMatrix;
|
||||||
|
|
||||||
|
// Apply transformations to this node
|
||||||
|
const int BONE_MTX_IDX = rig->GetNodeIndex(node);
|
||||||
|
if (BONE_MTX_IDX >= 0)
|
||||||
|
{
|
||||||
|
boneMatrices[BONE_MTX_IDX] = boneMatrices[BONE_MTX_IDX] * transformMatrix * node->OffsetMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply pose to children
|
||||||
|
for (auto& child : node->Children)
|
||||||
|
{
|
||||||
|
updatePoseWithClip(closestFrameIndex, poseTime, child, transformMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace SHADE
|
||||||
/* Forward Declarations */
|
/* Forward Declarations */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
class SHRig;
|
class SHRig;
|
||||||
|
struct SHRigNode;
|
||||||
class SHAnimationClip;
|
class SHAnimationClip;
|
||||||
class SHVkBuffer;
|
class SHVkBuffer;
|
||||||
|
|
||||||
|
@ -133,11 +134,14 @@ namespace SHADE
|
||||||
float secsPerTick = 0.0f;
|
float secsPerTick = 0.0f;
|
||||||
// Buffer
|
// Buffer
|
||||||
std::vector<SHMatrix> boneMatrices;
|
std::vector<SHMatrix> boneMatrices;
|
||||||
|
// Caches
|
||||||
|
std::unordered_map<std::string, const SHAnimationClip::Channel*> channelMap;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Helper Functions */
|
/* Helper Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
void updatePoseWithClip(float poseTime);
|
void updatePoseWithClip(float poseTime);
|
||||||
|
void updatePoseWithClip(int closestFrameIndex, float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, int closestFrameIndex, float poseTime);
|
T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, int closestFrameIndex, float poseTime);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Usage Functions */
|
/* Usage Functions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
const std::string& SHRig::GetName(Handle<Node> node) const noexcept
|
const std::string& SHRig::GetName(Handle<SHRigNode> node) const noexcept
|
||||||
{
|
{
|
||||||
static const std::string EMPTY_STRING = "";
|
static const std::string EMPTY_STRING = "";
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace SHADE
|
||||||
return EMPTY_STRING;
|
return EMPTY_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<SHRig::Node> SHRig::GetNode(const std::string& name) const noexcept
|
Handle<SHRigNode> SHRig::GetNode(const std::string& name) const noexcept
|
||||||
{
|
{
|
||||||
if (nodesByName.contains(name))
|
if (nodesByName.contains(name))
|
||||||
return nodesByName.at(name);
|
return nodesByName.at(name);
|
||||||
|
@ -62,7 +62,7 @@ namespace SHADE
|
||||||
return static_cast<int>(nodes.size());
|
return static_cast<int>(nodes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int SHRig::GetNodeIndex(Handle<Node> node) const noexcept
|
int SHRig::GetNodeIndex(Handle<SHRigNode> node) const noexcept
|
||||||
{
|
{
|
||||||
if (nodeIndexMap.contains(node))
|
if (nodeIndexMap.contains(node))
|
||||||
{
|
{
|
||||||
|
@ -75,14 +75,14 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Helper Functions */
|
/* Helper Functions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
Handle<SHRig::Node> SHRig::recurseCreateNode(const SHRigAsset& asset, const SHRigNode* sourceNode)
|
Handle<SHRigNode> SHRig::recurseCreateNode(const SHRigAsset& asset, const SHRigNodeAsset* sourceNode)
|
||||||
{
|
{
|
||||||
// Construct the node
|
// Construct the node
|
||||||
auto newNode = nodeStore.Create();
|
auto newNode = nodeStore.Create();
|
||||||
|
|
||||||
// Fill the node with data
|
// Fill the node with data
|
||||||
const auto& NODE_DATA = asset.nodeDataCollection.at(sourceNode->idRef);
|
const auto& NODE_DATA = asset.nodeDataCollection.at(sourceNode->idRef);
|
||||||
newNode->Transform = NODE_DATA.transform;
|
newNode->OffsetMatrix = NODE_DATA.transform;
|
||||||
|
|
||||||
// Populate maps
|
// Populate maps
|
||||||
if (!NODE_DATA.name.empty())
|
if (!NODE_DATA.name.empty())
|
||||||
|
|
|
@ -28,23 +28,32 @@ namespace SHADE
|
||||||
/* Forward Declarations */
|
/* Forward Declarations */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
struct SHRigAsset;
|
struct SHRigAsset;
|
||||||
struct SHRigNode;
|
struct SHRigNodeAsset;
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
struct SHRigNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Matrix that performs a transformation from local space to bone (node) space.
|
||||||
|
/// </summary>
|
||||||
|
SHMatrix OffsetMatrix;
|
||||||
|
/// <summary>
|
||||||
|
/// Child nodes of this node.
|
||||||
|
/// </summary>
|
||||||
|
std::vector<Handle<SHRigNode>> Children;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
class SH_API SHRig
|
class SH_API SHRig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*---------------------------------------------------------------------------------*/
|
|
||||||
/* Type Definitions */
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
|
||||||
struct Node
|
|
||||||
{
|
|
||||||
SHMatrix Transform;
|
|
||||||
std::vector<Handle<Node>> Children;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Constructors */
|
/* Constructors */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -65,7 +74,12 @@ namespace SHADE
|
||||||
/// Name of the node. If it does not have a name or is invalid, an empty string will
|
/// Name of the node. If it does not have a name or is invalid, an empty string will
|
||||||
/// be provided.
|
/// be provided.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
const std::string& GetName(Handle<Node> node) const noexcept;
|
const std::string& GetName(Handle<SHRigNode> node) const noexcept;
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the root node of the rig.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Handle to the root node of the rig.</returns>
|
||||||
|
Handle<SHRigNode> GetRootNode() const noexcept { return rootNode; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a node via name.
|
/// Retrieves a node via name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -74,7 +88,7 @@ namespace SHADE
|
||||||
/// Node with the specified name. If it does not have a name or is invalid, an empty
|
/// Node with the specified name. If it does not have a name or is invalid, an empty
|
||||||
/// handle will be provided.
|
/// handle will be provided.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
Handle<Node> GetNode(const std::string& name) const noexcept;
|
Handle<SHRigNode> GetNode(const std::string& name) const noexcept;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the number of nodes in the rig. This matches the number of bone matrices
|
/// Returns the number of nodes in the rig. This matches the number of bone matrices
|
||||||
/// needed.
|
/// needed.
|
||||||
|
@ -83,22 +97,22 @@ namespace SHADE
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the index in the node storage.
|
/// Retrieves the index in the node storage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int GetNodeIndex(Handle<Node> node) const noexcept;
|
int GetNodeIndex(Handle<SHRigNode> node) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Data Members */
|
/* Data Members */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
Handle<Node> rootNode;
|
Handle<SHRigNode> rootNode;
|
||||||
std::unordered_map<Handle<Node>, std::string> nodeNames;
|
std::unordered_map<Handle<SHRigNode>, std::string> nodeNames;
|
||||||
std::unordered_map<std::string, Handle<Node>> nodesByName;
|
std::unordered_map<std::string, Handle<SHRigNode>> nodesByName;
|
||||||
std::vector<Handle<Node>> nodes;
|
std::vector<Handle<SHRigNode>> nodes;
|
||||||
std::unordered_map<Handle<Node>, int> nodeIndexMap;
|
std::unordered_map<Handle<SHRigNode>, int> nodeIndexMap;
|
||||||
SHResourceLibrary<Node> nodeStore;
|
SHResourceLibrary<SHRigNode> nodeStore;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Helper Functions */
|
/* Helper Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
Handle<Node> recurseCreateNode(const SHRigAsset& asset, const SHRigNode* sourceNode);
|
Handle<SHRigNode> recurseCreateNode(const SHRigAsset& asset, const SHRigNodeAsset* sourceNode);
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -29,10 +29,10 @@ namespace SHADE
|
||||||
SHMatrix transform;
|
SHMatrix transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHRigNode
|
struct SHRigNodeAsset
|
||||||
{
|
{
|
||||||
uint32_t idRef;
|
uint32_t idRef;
|
||||||
std::vector<SHRigNode*> children;
|
std::vector<SHRigNodeAsset*> children;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SH_API SHRigAsset : SHAssetData
|
struct SH_API SHRigAsset : SHAssetData
|
||||||
|
@ -41,6 +41,6 @@ namespace SHADE
|
||||||
|
|
||||||
SHRigDataHeader header;
|
SHRigDataHeader header;
|
||||||
std::vector<SHRigNodeData> nodeDataCollection;
|
std::vector<SHRigNodeData> nodeDataCollection;
|
||||||
SHRigNode* root;
|
SHRigNodeAsset* root;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNode*& root)
|
void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNodeAsset*& root)
|
||||||
{
|
{
|
||||||
// Read All nodes into one contiguous data block
|
// Read All nodes into one contiguous data block
|
||||||
struct NodeTemp
|
struct NodeTemp
|
||||||
|
@ -170,13 +170,13 @@ namespace SHADE
|
||||||
);
|
);
|
||||||
|
|
||||||
// Build and populate tree
|
// Build and populate tree
|
||||||
SHRigNode* nodePool = new SHRigNode[header.nodeCount];
|
SHRigNodeAsset* nodePool = new SHRigNodeAsset[header.nodeCount];
|
||||||
root = nodePool;
|
root = nodePool;
|
||||||
|
|
||||||
std::queue<std::pair<SHRigNode*, NodeTemp*>> nodeQueue;
|
std::queue<std::pair<SHRigNodeAsset*, NodeTemp*>> nodeQueue;
|
||||||
nodeQueue.emplace(std::make_pair(nodePool, dst));
|
nodeQueue.emplace(std::make_pair(nodePool, dst));
|
||||||
|
|
||||||
SHRigNode* depthPtr = nodePool + 1;
|
SHRigNodeAsset* depthPtr = nodePool + 1;
|
||||||
NodeTemp* depthTempPtr = dst + 1;
|
NodeTemp* depthTempPtr = dst + 1;
|
||||||
|
|
||||||
while(!nodeQueue.empty())
|
while(!nodeQueue.empty())
|
||||||
|
|
|
@ -24,7 +24,7 @@ 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, SHRigNode*& root);
|
void ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNodeAsset*& root);
|
||||||
|
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue