骨骼蒙皮算法将模型脚下的所有东西聚在一起
Skeletal skinning algorithm bunches up everything at the model's feet
我正在尝试使用存储在 Collada 文件中的骨骼动画来实现蒙皮,虽然我设法加载它并在没有正确蒙皮的情况下渲染模型,但我无法弄清楚为什么当我应用我的蒙皮算法时零件在模特的脚下聚成一团,或者极度变形。整个项目存储在 GitHub 以供参考(皮肤分支)。
我相信顶点着色器是正确的,因为如果我将恒等变换传递给骨骼,我会得到我的默认姿势模型,它会根据 .dae
文件中不知何故损坏的骨骼动画计算骨骼变换。这是我的问题的样子,与模型在默认姿势下的样子:
我认为在应用递归骨骼变换时我的问题出在某个地方:
public void Update(double deltaSec)
{
if (CurrentAnimationName is null) return;
var anim = animations[CurrentAnimationName];
currentAnimationSec = (currentAnimationSec + deltaSec) % anim.Duration.TotalSeconds;
void calculateBoneTransforms(BoneNode boneNode, Matrix4x4 parentTransform)
{
var bone = anim.Bones.FirstOrDefault(b => b.Id == boneNode.Id);
var nodeTransform = bone?[TimeSpan.FromSeconds(currentAnimationSec)] ?? boneNode.Transform;
var globalTransform = parentTransform * nodeTransform;
if (boneNode.Id >= 0)
for (int meshIdx = 0; meshIdx < perMeshData.Length; ++meshIdx)
perMeshData[meshIdx].FinalBoneMatrices[boneNode.Id] = globalTransform * perMeshData[meshIdx].boneOffsetMatrices[boneNode.Id];
foreach (var child in boneNode.Children)
calculateBoneTransforms(child, globalTransform);
}
calculateBoneTransforms(rootBoneNode, Matrix4x4.Identity);
}
或者在使用变换构建骨骼数据的递归结构时:
BoneNode visitTransforms(Node node, Matrix4x4 mat)
{
var boneNode = new BoneNode
{
Children = new BoneNode[node.ChildCount],
Id = boneIds.TryGetValue(node.Name, out var id) ? id : -1,
Transform = Matrix4x4.Transpose(node.Transform.ToNumerics()),
};
mat = node.Transform.ToNumerics() * mat;
foreach (var meshIndex in node.MeshIndices)
transformsDictionary[scene.Meshes[meshIndex]] = mat;
int childIdx = 0;
foreach (var child in node.Children)
boneNode.Children[childIdx++] = visitTransforms(child, mat);
return boneNode;
}
rootBoneNode = visitTransforms(scene.RootNode, Matrix4x4.Identity);
我相信 骨骼到顶点的权重已正确收集并上传到着色器,并且最终的骨骼数组统一已正确上传(但可能计算不正确)。我也不确定矩阵乘法的顺序以及在上传到着色器时是否转置任何内容,尽管我每次尝试都尝试过这两种方法。
如果有人遇到类似问题,我的问题是与其余变换链的计算方式相比,我的关键帧骨骼变换被调换了,所以当我将它们相乘时,一切都变得疯狂了。因此,请跟踪哪些矩阵是左手矩阵,哪些矩阵是右手矩阵!
我正在尝试使用存储在 Collada 文件中的骨骼动画来实现蒙皮,虽然我设法加载它并在没有正确蒙皮的情况下渲染模型,但我无法弄清楚为什么当我应用我的蒙皮算法时零件在模特的脚下聚成一团,或者极度变形。整个项目存储在 GitHub 以供参考(皮肤分支)。
我相信顶点着色器是正确的,因为如果我将恒等变换传递给骨骼,我会得到我的默认姿势模型,它会根据 .dae
文件中不知何故损坏的骨骼动画计算骨骼变换。这是我的问题的样子,与模型在默认姿势下的样子:
我认为在应用递归骨骼变换时我的问题出在某个地方:
public void Update(double deltaSec)
{
if (CurrentAnimationName is null) return;
var anim = animations[CurrentAnimationName];
currentAnimationSec = (currentAnimationSec + deltaSec) % anim.Duration.TotalSeconds;
void calculateBoneTransforms(BoneNode boneNode, Matrix4x4 parentTransform)
{
var bone = anim.Bones.FirstOrDefault(b => b.Id == boneNode.Id);
var nodeTransform = bone?[TimeSpan.FromSeconds(currentAnimationSec)] ?? boneNode.Transform;
var globalTransform = parentTransform * nodeTransform;
if (boneNode.Id >= 0)
for (int meshIdx = 0; meshIdx < perMeshData.Length; ++meshIdx)
perMeshData[meshIdx].FinalBoneMatrices[boneNode.Id] = globalTransform * perMeshData[meshIdx].boneOffsetMatrices[boneNode.Id];
foreach (var child in boneNode.Children)
calculateBoneTransforms(child, globalTransform);
}
calculateBoneTransforms(rootBoneNode, Matrix4x4.Identity);
}
或者在使用变换构建骨骼数据的递归结构时:
BoneNode visitTransforms(Node node, Matrix4x4 mat)
{
var boneNode = new BoneNode
{
Children = new BoneNode[node.ChildCount],
Id = boneIds.TryGetValue(node.Name, out var id) ? id : -1,
Transform = Matrix4x4.Transpose(node.Transform.ToNumerics()),
};
mat = node.Transform.ToNumerics() * mat;
foreach (var meshIndex in node.MeshIndices)
transformsDictionary[scene.Meshes[meshIndex]] = mat;
int childIdx = 0;
foreach (var child in node.Children)
boneNode.Children[childIdx++] = visitTransforms(child, mat);
return boneNode;
}
rootBoneNode = visitTransforms(scene.RootNode, Matrix4x4.Identity);
我相信 骨骼到顶点的权重已正确收集并上传到着色器,并且最终的骨骼数组统一已正确上传(但可能计算不正确)。我也不确定矩阵乘法的顺序以及在上传到着色器时是否转置任何内容,尽管我每次尝试都尝试过这两种方法。
如果有人遇到类似问题,我的问题是与其余变换链的计算方式相比,我的关键帧骨骼变换被调换了,所以当我将它们相乘时,一切都变得疯狂了。因此,请跟踪哪些矩阵是左手矩阵,哪些矩阵是右手矩阵!