Warum gibt meine Animation die richtige Matrixpalette nicht aus?C++

Programme in C++. Entwicklerforum
Anonymous
 Warum gibt meine Animation die richtige Matrixpalette nicht aus?

Post by Anonymous »

Warum gibt meine Animation nach der Durchführung von Berechnungen auf meinen gemeinsamen Matrizen die richtige Matrixpalette nicht aus? In den Hauttutorials GLTF 2.0 heißt es, wie man die Gelenkmatrix für das Hautberechnen berechnet: < /p>

Code: Select all

jointMatrix(j) =
globalTransformOfNodeThatTheMeshIsAttachedTo^-1 *
globalTransformOfJointNode(j) *
inverseBindMatrixForJoint(j);
< /code>
Ich mache das für meine Animation Engine: < /p>
void Animation::DoSampleJob(AnimJobSubmitInfo& job, r32 gt)
{
if (!job._output->_currState._bEnabled) { return; }
// This part is just calculating the local time progression, no issue here.
r32 tau = job._output->_currState._tau;
r32 rate = job._output->_currState._fPlaybackRate;
r32 lt = job._output->_currState._fCurrLocalTime + gt * rate;
if (lt > job._pBaseClip->_fDuration) {
lt -= job._pBaseClip->_fDuration;
job._output->_currState._tau = gt;
}
if (lt < 0.0f) {
lt = job._pBaseClip->_fDuration + lt;
if (lt < 0.0f) {
lt += job._pBaseClip->_fDuration;
job._output->_currState._tau = gt;
}
}
job._output->_currState._fCurrLocalTime = lt;
Skeleton* pSkeleton = Skeleton::GetSkeleton(job._pBaseClip->_skeletonId);

u32 currPoseIdx = 0;
u32 nextPoseIdx = 0;

GetCurrentAndNextPoseIdx(&currPoseIdx, &nextPoseIdx, job._pBaseClip, lt);

ApplyMorphTargets(job._output, job._pBaseClip, currPoseIdx, nextPoseIdx, lt);

if (EmptyPoseSamples(job._pBaseClip, currPoseIdx, nextPoseIdx)) { return; }

AnimPose* currAnimPose = &job._pBaseClip->_aAnimPoseSamples[currPoseIdx];
AnimPose* nextAnimPose = &job._pBaseClip->_aAnimPoseSamples[nextPoseIdx];

for (size_t i = 0; i < job._pBaseClip->_aAnimPoseSamples[currPoseIdx]._aLocalPoses.size(); ++i) {
JointPose* currJoint = &currAnimPose->_aLocalPoses[i];
JointPose* nextJoint = &nextAnimPose->_aLocalPoses[i];
Matrix4 localTransform = LinearInterpolate(currJoint, nextJoint, currAnimPose->_time, nextAnimPose->_time, lt);
job._output->_currentPoses[i] = localTransform;
}

ApplySkeletonPose(job._output->_finalPalette, job._output->_currentPoses, pSkeleton);
}

void Animation::ApplySkeletonPose(Matrix4* pOutput, Matrix4* pLocalPoses, Skeleton* pSkeleton)
{
if (!pSkeleton) return;
// This is where the issue is at, somewhere...
for (size_t i = 0; i < pSkeleton->_joints.size(); ++i) {
Matrix4 parentTransform;
Matrix4 currentPose;
u8 parentId = pSkeleton->_joints[i]._iParent;
if (parentId != Joint::kNoParentId) {
parentTransform = pLocalPoses[parentId];
}
// Now become world space joint matrices
currentPose = pLocalPoses[i] * parentTransform;
pLocalPoses[i] = currentPose;
}

for (size_t i = 0; i < pSkeleton->_joints.size(); ++i) {
pOutput[i] = pSkeleton->_joints[i]._InvBindPose * pLocalPoses[i] * pSkeleton->_joints[i]._invGlobalTransform;

}
}
The outcome was not expected:
Image

I removed the calculations of the animation and just calculate the joint matrix as the inverse bind pose along with the global joint Transformation: < /p>

Code: Select all

void Animation::ApplySkeletonPose(Matrix4* pOutput, Matrix4* pLocalPoses, Skeleton* pSkeleton)
{
if (!pSkeleton) return;

for (size_t i = 0; i < pSkeleton->_joints.size(); ++i) {
Matrix4 parentTransform;
Matrix4 currentPose;
u8 parentId = pSkeleton->_joints[i]._iParent;
if (parentId != Joint::kNoParentId) {
parentTransform = pLocalPoses[parentId];
}
// Now become work space joint matrices
currentPose = pLocalPoses[i] * parentTransform;
pLocalPoses[i] = currentPose;
}

for (size_t i = 0; i < pSkeleton->_joints.size();  ++i) {
// Just calculating only the inverse bind pose, and global joint transform, removing the current pose.
pOutput[i] = pSkeleton->_joints[i]._InvBindPose * pSkeleton->_joints[i]._invGlobalTransform.Inverse();

}
}
Und das Ergebnis ist wie erwartet, wenn nicht animieren:

Wie behebe ich dieses Problem mit Berechnungsgelenk? Berechne ich die aktuellen Weltmatrizen nicht korrekt, bevor ich die inverse Bindung und die globale gemeinsame Transformation anwenden? Oder etwas vorher?

Code: Select all

static skeleton_uuid_t LoadSkin(const tinygltf::Node& node, const tinygltf::Model& model, Model* engineModel, const Matrix4& parentMatrix)
{
if (node.skin == -1) return Skeleton::kNoSkeletonId;

Skeleton skeleton;
tinygltf::Skin skin = model.skins[node.skin];
b32 rootInJoints = false;
for (size_t i = 0; i < skin.joints.size(); ++i) {
if (skin.joints[i] == skin.skeleton) {
rootInJoints = true; break;
}
}
skeleton._joints.resize(skin.joints.size());
skeleton._name = skin.name;
skeleton._rootInJoints = rootInJoints;

const tinygltf::Accessor& accessor = model.accessors[skin.inverseBindMatrices];
const tinygltf::BufferView& bufView = model.bufferViews[accessor.bufferView];
const tinygltf::Buffer& buf = model.buffers[bufView.buffer];

struct NodeTag {
i32               _gltfParent;
u8                _parent;
Matrix4           _parentTransform;
};

std::map nodeMap;
for (size_t i = 0; i < skin.joints.size(); ++i) {
size_t idx = i;
Joint& joint = skeleton._joints[idx];
i32 skinJointIdx = skin.joints[i];
const tinygltf::Node& node = model.nodes[skinJointIdx];
NodeTransform localTransform;

auto it = nodeMap.find(skinJointIdx);
if (it != nodeMap.end()) {
NodeTag& tag = it->second;
localTransform = CalculateGlobalTransform(node, tag._parentTransform);
joint._iParent = tag._parent;
joint._invGlobalTransform = localTransform._globalMatrix.Inverse();
} else {
localTransform = CalculateGlobalTransform(node, Matrix4());
joint._iParent = 0xff;
joint._invGlobalTransform = localTransform._globalMatrix.Inverse();
}

DEBUG_OP(joint._id = static_cast(skinJointIdx));
for (size_t child = 0; child < node.children.size(); ++child) {
NodeTag tag = { static_cast(skinJointIdx), i, localTransform._globalMatrix };
nodeMap[node.children[child]] = tag;
}
}

const r32* bindMatrices = reinterpret_cast(&buf.data[bufView.byteOffset + accessor.byteOffset]);

for (size_t i = 0; i < accessor.count; ++i) {
Matrix4 invBindMat(&bindMatrices[i * 16]);
skeleton._joints[i]._InvBindPose = invBindMat;
}

Skeleton::PushSkeleton(skeleton);

engineModel->skeletons.push_back(Skeleton::GetSkeleton(skeleton._uuid));
return skeleton._uuid;
}

static void LoadNode(const tinygltf::Node& node, const tinygltf::Model& model, Model* engineModel, const Matrix4& parentMatrix, const r32 scale)
{
NodeTransform transform = CalculateGlobalTransform(node, parentMatrix);
if (!node.children.empty()) {
for (size_t i = 0; i < node.children.size(); ++i) {
LoadNode(model.nodes[node.children[i]], model, engineModel, transform._globalMatrix, scale);
}
}

if (node.skin != -1) {
skeleton_uuid_t skeleId = LoadSkin(node, model, engineModel, transform._globalMatrix);
Mesh* pMesh = LoadSkinnedMesh(node, model, engineModel, transform._globalMatrix);
pMesh->SetSkeletonReference(skeleId);
}
else {
LoadMesh(node, model, engineModel, transform._globalMatrix);
}
}
Quellcode auf GitHub.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post