5

ファイルから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に同じロジックを実行するように、ただしシーングラフの適切なポイントで実行するように指示するにはどうすればよいでしょうか。

(申し訳ありませんが、ライブコードの例をいくつか投稿したいと思いますが、残念ながら、この場合はオプションではありません。)

4

2 に答える 2

5

はぁ...

Altered Qualiaは、私がこれを投稿してから数分以内にTwitterで解決策を指摘しました。

これは単純な1行の修正ですmatrixAutoUpdate。Object3Dインスタンスでfalseに設定するだけで、最初のコードサンプルが意図したとおりに機能します。

threeObj.matrixAutoUpdate = false; // This fixes it
threeObj.applyMatrix(threeMatrixFromSrcMatrix(child.matrix));

それはいつもあなたを得る愚かな小さなものです...

于 2012-07-04T00:32:43.237 に答える
5

matrixAutoUpdate = falseを使用して、Three.jsシーングラフの位置/スケール/回転をスキップできます。次に、object.matrixを必要なマトリックスに設定すると、すべてがダンディになります(それでも、親ノードマトリックスが乗算されるため、絶対モデルビューマトリックスを使用している場合は、Object3DでupdateMatrixWorldメソッドをハックする必要があります)。

object.matrixAutoUpdate = false;
object.matrix = myMatrix;

ここで、Three.jsの位置/スケール/回転にカスタム変換行列を適用する場合は、Object3D#updateMatrixを次のように編集する必要があります。

THREE.Object3D.prototype._updateMatrix = THREE.Object3D.prototype.updateMatrix;
THREE.Object3D.prototype.updateMatrix = function() {
  this._updateMatrix();
  if (this.customMatrix != null)
    this.matrix.multiply(this.customMatrix);
};

https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L209を参照してください

于 2012-07-04T00:33:54.210 に答える