Использование матриц для преобразования графа сцены Three.js

Я пытаюсь загрузить сцену из файла в пользовательский формат 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 выполнять ту же логику, но в соответствующей точке графа сцены?

(Извините, я бы очень хотел опубликовать несколько примеров живого кода, но, к сожалению, в данном случае это не вариант.)

5
задан Toji 4 July 2012 в 00:04
поделиться