OpenGL/Assimp — Как вычислить иерархию преобразований для сетки со шкуройJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 OpenGL/Assimp — Как вычислить иерархию преобразований для сетки со шкурой

Сообщение Anonymous »

Я пытаюсь настроить рендеринг для скелетной/скелетной анимации (преобразований поз пока нет). Модель импортируется с помощью Assimp и отображается с помощью OpenGL.
Где-то в процессе расчета преобразований в иерархии узлов что-то идет не так.
Любая помощь в выявлении проблем с моим кодом или моим пониманием приветствуется.
Соответствующий код и ресурсы
Мой код для вычислений преобразования в иерархии узлов выглядят так это:

Код: Выделить всё

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
Настройки экспорта FBX из blender для тестовой модели (лицом к -Y)
Изображение

Ожидаемое и фактическое
Я ожидал, что все FinalTransforms должен быть идентификационная матрица и чтоbone.offset должен быть обратным родительскомуTransform * nodeTransform.
Когда я заставляю значение быть идентификационной матрицей, с которой работает моя модель

Код: Выделить всё

finalTransforms[bone.index] = new Matrix4f();
он ​​выглядит нормально, и я также вижу, что веса костей совпадают с тем местом, где они должны быть.
При выполнении расчетов по учебному коду

Код: Выделить всё

finalTransforms[bone.index] = globalTransform.mul(bone.offset, new Matrix4f());
Вместо этого я получаю искаженный беспорядок
(

Код: Выделить всё

new Matrix4f();
в recurseBones)
Изображение
< img alt="сетка искажена неверными данными о позе" src="https://i.sstatic.net/4amShCTL.gif" />

Подробнее здесь: https://stackoverflow.com/questions/792 ... inned-mesh
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»