Я пытаюсь загрузить сцену из файла в пользовательский формат Three.js (, а не в тот, который поддерживает Three.js ). Этот конкретный формат описывает граф сцены, в котором каждый узел дерева имеет преобразование, указанное в виде матрицы 4x4. Процесс добавления его в Three.js выглядит примерно так:
// Yeah, this is javascript-like psuedocode
function processNodes(srcNode, parentThreeObj) {
for(child in srcNode.children) {
var threeObj = new THREE.Object3D();
// This line is the problem
threeObj.applyMatrix(threeMatrixFromSrcMatrix(child.matrix));
for(mesh in child.meshes) {
var threeMesh = threeMeshFromSrcMesh(mesh);
threeObj.add(threeMesh);
}
parentThreeObj.add(threeObj);
processNodes(child, threeObj); // And recurse!
}
}
Или, по крайней мере, это то, что я хотел бы, чтобы это было. Как я уже говорил, строка applyMatrix
работает не так, как я ожидал. Большая часть сцены выглядит нормально, но некоторые элементы, которые были повернуты, не выровнены должным образом (, а другие — это странно ).
Просматривая загрузчик COLLADA (, который делает примерно то же самое, что и я ), оказывается, что они разлагают матрицу на перемещение/поворот/масштабирование и применяют каждое по отдельности. Я попробовал это вместо applyMatrix, показанного выше:
var props = threeMatrixFromSrcMatrix(child.matrix).decompose();
threeObj.useQuaternion = true;
threeObj.position = props[ 0 ];
threeObj.quaternion = props[ 1 ];
threeObj.scale = props[ 2 ];
Это, опять же, дает сцену, в которой большинство элементов находятся в правильном месте, но сетки, которые раньше были смещены, теперь где-то превращены в забвение и больше не появляются вообще. Так что в итоге это не лучше, чем applyMatrix
сверху.
Просматривая несколько онлайн-дискуссий на эту тему, я понял, что рекомендуемый способ использования матриц для ваших преобразований — применять их непосредственно к геометрии, а не к узлам, поэтому я попытался сделать это, вручную построив матрицу преобразования:
function processNodes(srcNode, parentThreeObj, parentMatrix) {
for(child in srcNode.children) {
var threeObj = new THREE.Object3D();
var childMatrix = threeMatrixFromSrcMatrix(child.matrix);
var objMatrix = THREE.Matrix4();
objMatrix.multiply(parentMatrix, childMatrix);
for(mesh in child.meshes) {
var threeMesh = threeMeshFromSrcMesh(mesh);
threeMesh.geometry.applyMatrix(objMatrix);
threeObj.add(threeMesh);
}
parentThreeObj.add(threeObj);
processNodes(child, threeObj, objMatrix); // And recurse!
}
}
Это на самом деле дает правильные результаты! (минус некоторые причуды с нормалями, но я могу понять это )Это здорово, но проблема в том, что мы теперь эффективно сгладили иерархию сцены :Изменение преобразования родителя приведет к неожиданным результатам на дочерних элементах, потому что полный стек преобразований теперь «запечен» в сетках. В данном случае это неприемлемая потеря информации о сцене.
Итак, как можно заставить Three.js выполнять ту же логику, но в соответствующей точке графа сцены?
(Извините, я бы очень хотел опубликовать несколько примеров живого кода, но, к сожалению, в данном случае это не вариант.)