Где-то в процессе расчета преобразований в иерархии узлов что-то идет не так.
Любая помощь в выявлении проблем с моим кодом или моим пониманием приветствуется.
Соответствующий код и ресурсы
Мой код для вычислений преобразования в иерархии узлов выглядят так это:
Код: Выделить всё
private Model model;
private Armature armature;
private final Matrix4f[] finalTransforms;
// ...
public void apply() {
recurseBones(model.scene.mRootNode(), new Matrix4f());
for(int i = 0; i < finalTransforms.length; i++)
armature.setBonePose(i, finalTransforms[i]); //updates byte buffer
//sends pose data to shader storage buffer from byte buffer
armature.updatePose();
}
protected void recurseBones(AINode node, Matrix4f parentTransform) {
var name = node.mName().dataString();
var nodeTransform = convertMatrix(node.mTransformation()); //AIMatrix4x4 to Matrix4f
var globalTransform = parentTransform.mul(nodeTransform, new Matrix4f());
var bone = armature.boneLookup.get(name);
if(bone != null) {
finalTransforms[bone.index] =
// new Matrix4f(); //expected output
globalTransform.mul(bone.offset, new Matrix4f()); //incorrect result
}
for(int childIndex = 0; childIndex < node.mNumChildren(); childIndex++) {
recurseBones(AINode.create(node.mChildren().get(childIndex)), globalTransform);
}
}
В Bone.java
Код: Выделить всё
this.offset = convertMatrix(aiBone.mOffsetMatrix());
Код: Выделить всё
public static Matrix4f convertMatrix(AIMatrix4x4 matrix) {
return new Matrix4f(
matrix.a1(), matrix.a2(), matrix.a3(), matrix.a4(),
matrix.b1(), matrix.b2(), matrix.b3(), matrix.b4(),
matrix.c1(), matrix.c2(), matrix.c3(), matrix.c4(),
matrix.d1(), matrix.d2(), matrix.d3(), matrix.d4()
);
}
Код: Выделить всё
#version 450
layout (location = 0) in vec3 aVertex;
layout (location = 1) in vec2 aTexPosition;
layout (location = 2) in vec3 aNormal;
uniform mat4 uModelMatrix;
uniform mat4 uProjectionMatrix;
uniform mat4 uViewMatrix;
uniform float uTime;
out vec3 vertexPosition;
out vec2 texturePosition;
out vec3 normalPosition;
//DEBUG
out float debugWeight; //changes color in fragment shader
uniform int uDebug; //which bone to check
uniform int uMeshIndex;
struct Weight {
int boneID;
float weight;
};
struct Pose {
mat4 transform;
};
struct SubArray {
int start;
int length;
};
layout(std430, binding = 2) buffer MeshIndexSSBO {
int[] vertexWeightsIndex; //[meshID], start index in VertexIndex::weightsIndex
};
layout(std430, binding = 3) buffer VertexIndexSSBO {
SubArray[] weightsIndex; //[vertexID + meshIndexOffset], start index and length in Weights::weights
};
/**
Given uniform meshIndex, gl_VertexID & boneN
startIndex = weightsIndex[vertexWeightsIndex[meshIndex]].start
#bones = weightsIndex[vertexWeightsIndex[meshIndex]].length
weight = weights[ startIndex + boneN ];
*/
layout(std430, binding = 4) buffer WeightsSSBO {
Weight[] weights;
};
layout(std430, binding = 5) buffer ArmaturePoseSSBO {
Pose[] poses; //[boneID]
};
void main() {
SubArray weightsArray = weightsIndex[vertexWeightsIndex[uMeshIndex] + gl_VertexID];
int vertexStartIndex = weightsArray.start;
int nBones = weightsArray.length;
float w = 0; //debug
mat4 pTransform = mat4(0);
float totalWeight = 0;
for(int b = 0; b < nBones; b++) {
totalWeight += weights[vertexStartIndex + b].weight;
}
vec4 posedPos;
if(totalWeight > 0) {
for(int b = 0; b < nBones; b++) {
Weight weightInfo = weights[vertexStartIndex + b];
int boneID = weightInfo.boneID;
float weight = weightInfo.weight;
Pose pose = poses[boneID];
pTransform += pose.transform * (weight / totalWeight);
//debug coloring
if(boneID != uDebug) continue;
w += weight / totalWeight;
}
posedPos = pTransform * vec4(aVertex, 1.0);
} else {
posedPos = vec4(aVertex.xyz, 1.0);
}
// posedPos = vec4(aVertex.xyz, 1.0); //debug ignore bone transforms
debugWeight = w; //tint mesh
vec4 pos = uProjectionMatrix * uViewMatrix * uModelMatrix * posedPos;
gl_Position = pos;
vertexPosition = aVertex;
texturePosition = vec2(aTexPosition.x, 1-aTexPosition.y);
}
Код: Выделить всё
RootNode
nodeTransform:
-1.000E+0 0.000E+0 0.000E+0 0.000E+0
0.000E+0 0.000E+0 1.000E+0 0.000E+0
0.000E+0 1.000E+0 0.000E+0 0.000E+0
0.000E+0 0.000E+0 0.000E+0 1.000E+0
globalTransform
-1.000E+0 0.000E+0 0.000E+0 0.000E+0
0.000E+0 0.000E+0 1.000E+0 0.000E+0
0.000E+0 1.000E+0 0.000E+0 0.000E+0
0.000E+0 0.000E+0 0.000E+0 1.000E+0
Armature
nodeTransform:
-1.000E+2 -8.742E-6 0.000E+0 0.000E+0
8.742E-6 -1.000E+2 0.000E+0 0.000E+0
0.000E+0 0.000E+0 1.000E+2 0.000E+0
0.000E+0 0.000E+0 1.293E+2 1.000E+0
globalTransform
1.000E+2 8.742E-6 0.000E+0 0.000E+0
0.000E+0 0.000E+0 1.000E+2 0.000E+0
8.742E-6 -1.000E+2 0.000E+0 0.000E+0
0.000E+0 0.000E+0 1.293E+2 1.000E+0
Root
nodeTransform:
1.000E+0 0.000E+0 0.000E+0 0.000E+0
0.000E+0 -1.629E-7 1.000E+0 0.000E+0
0.000E+0 -1.000E+0 -1.629E-7 0.000E+0
0.000E+0 0.000E+0 0.000E+0 1.000E+0
globalTransform
1.000E+2 -1.424E-12 8.742E-6 0.000E+0
0.000E+0 -1.000E+2 -1.629E-5 0.000E+0
8.742E-6 1.629E-5 -1.000E+2 0.000E+0
0.000E+0 -1.293E+2 -2.106E-5 1.000E+0
bone.offset
-1.000E-2 0.000E+0 0.000E+0 0.000E+0
0.000E+0 0.000E+0 1.000E-2 0.000E+0
0.000E+0 1.000E-2 0.000E+0 0.000E+0
0.000E+0 -1.293E+0 0.000E+0 1.000E+0
finalTransforms[0]
-1.000E+0 8.742E-8 -1.424E-14 0.000E+0
0.000E+0 -1.629E-7 -1.000E+0 0.000E+0
-8.742E-8 -1.000E+0 1.629E-7 0.000E+0
0.000E+0 -1.293E+0 -1.293E+0 1.000E+0

Ожидаемое и фактическое
Я ожидал, что все FinalTransforms должен быть идентификационная матрица и чтоbone.offset должен быть обратным родительскомуTransform * nodeTransform.
Когда я заставляю значение быть идентификационной матрицей, с которой работает моя модель
Код: Выделить всё
finalTransforms[bone.index] = new Matrix4f();
При выполнении расчетов по учебному коду
Код: Выделить всё
finalTransforms[bone.index] = globalTransform.mul(bone.offset, new Matrix4f());
(
Код: Выделить всё
new Matrix4f();
< img alt="сетка искажена неверными данными о позе" src="https://i.sstatic.net/4amShCTL.gif" />
Подробнее здесь: https://stackoverflow.com/questions/792 ... inned-mesh
Мобильная версия