2016-03-19 10 views
7

各回転軸に個別の親を持つオブジェクトがあります(X回転の場合は1、Y回転の場合は1、Z回転の場合は1)。 X回転オブジェクトはY回転オブジェクトの子です.Y回転オブジェクトはZ回転オブジェクトの子です)。Rotationが90度を超える場合、Three.js setFromRotationMatrixの異常な動作

私は、シーン内のすべてのオブジェクトを一緒に回転させることができる機能を作成しようとしています(これらはすべて1つのObject3Dに含まれています)。そのObject3Dを回転させると、プログラムは各オブジェクトの新しい値を出力できるように、ワールドに対する絶対位置と回転のすべてを見つける必要があります。

これを行うために、私は現在、Object3Dである "scene-rotator"内の位置が世界に対して絶対的な位置になるようにオブジェクトを移動するように設定しています。今、私はオブジェクトの回転を世界に対するオブジェクトの絶対回転にするようにしています。そのため、 "シーン回転子"の回転が変更されたときにそれに応じて変更されます。また、setFromRotationMatrixメソッドが正常に動作しませんでした。子オブジェクトに対して1回だけ実行してみました。代わりに、それぞれの親オブジェクトに対して再度実行し、それに応じて個別に回転させる必要がありました。

これはコードですその後

var beforeRotForX = new THREE.Euler(); 
beforeRotForX.setFromRotationMatrix(objects[i].parent.matrixWorld, "ZYX"); 

var beforeRotForY = new THREE.Euler(); // Had to be a separate one for some reason... 
beforeRotForY.setFromRotationMatrix(objects[i].parent.parent.matrixWorld, "ZYX"); 

var beforeRotForZ = new THREE.Euler(); // And apparently this one has to be separate too 
beforeRotForZ.setFromRotationMatrix(objects[i].parent.parent.parent.matrixWorld, "ZYX"); 

// Absolute before rotation 
objects[i].userData.sceneBeforeRotAbs = { 
    x: beforeRotForX.x, 
    y: beforeRotForY.y, 
    z: beforeRotForZ.z 
}; 

、それは対象物の相対回転に

objects[i].parent.rotation.x = objects[i].userData.sceneBeforeRotAbs.x; 
objects[i].parent.parent.rotation.y = objects[i].userData.sceneBeforeRotAbs.y; 
objects[i].parent.parent.parent.rotation.z = objects[i].userData.sceneBeforeRotAbs.z; 

これをその絶対的な回転を適用する必要があります。私は現在、世界に物体の絶対的な回転を得ることになっている持っていますすべて正常に動作します第二の親のY-回転が90

// Results of absolute world rotation when the Y-rotation of the 
// second parent is set to 90 degrees (1.5707... as euler) 
objects[i].userData.sceneBeforeRotAbs.x === 0 
objects[i].userData.sceneBeforeRotAbs.y === 1.5707963267948966 
objects[i].userData.sceneBeforeRotAbs.z === 0 

しかしを通して-90内にあるときに第二の親のY-回転が-90以上90未満である場合、それは絶対に間違った値を与えます結果としての世界のX旋回とY旋回

// Results of absolute world rotation when the Y-rotation of the 
// second parent is set to 91 degrees (1.5882... as euler) 
objects[i].userData.sceneBeforeRotAbs.x === 3.141592653589793 
objects[i].userData.sceneBeforeRotAbs.y === 1.5533438924131038 
objects[i].userData.sceneBeforeRotAbs.z === 0 
+2

私はあなたの問題dscriptionを2回読んだことがあり、達成しようとしていることを本当に頭で覆すことはできません。しかし、私に当たる一つの事は、オイラー角を使ってすべての軸の周りを回転させる問題です。オイラー角で回転することで奇妙な動作が起こると、[Gimbal Lock](https://en.wikipedia.org/wiki/Gimbal_lock)が原因である可能性があります。代わりに四元数を使用してこれを試してみることをお勧めします。 Three.jsもそれらをサポートしています – micnil

+0

これを実行するのはなぜ冗長に見えるのかということがわかりますが、参考のため、これはhttps://mrgarretto.com/model/のページですユーザーがプロジェクトを作った後、さまざまなことを生み出すことができなければならない人々のためのツールです。ここに私がまとめたアルバムがあります。これは実際の問題を示すのに役立ちます:http:// imgur。com/a/jkTeoクォータニオンを使用して問題を解決するかどうか試します – MrGarretto

答えて

0

あなたはgimbal lockに似ています。オイラー角を使用するときは常にジンバルロックの問題にぶつかり、複数の回転を適用すると予期しない動作が発生します。

たとえば、2D空間では、30°回転は-330°回転と同じです。 3D空間では、同じ問題が発生します。オブジェクトをX軸で180°回転させることは、180°Y軸+ 180°Z軸回転と同じです。

quaternionsを使用して回転を宣言し、それらを掛け合わせて、ジンバルロックの問題なしに望みの結果を得る必要があります。

// Declare angles 
var angleX = 45; 
var angleY = 120; 
var angleZ = 78; 

// Declare X and Y axes 
var axisX = new THREE.Vector3(1, 0, 0); 
var axisY = new THREE.Vector3(0, 1, 0); 
var axisY = new THREE.Vector3(0, 0, 1); 

// Init quaternions that will rotate along each axis 
var quatX = new THREE.Quaternion(); 
var quatY = new THREE.Quaternion(); 
var quatZ = new THREE.Quaternion(); 

// Set quaternions from each axis (in radians)... 
quatX.setFromAxisAngle(axisX, THREE.Math.degToRad(angleX)); 
quatY.setFromAxisAngle(axisY, THREE.Math.degToRad(angleY)); 
quatZ.setFromAxisAngle(axisZ, THREE.Math.degToRad(angleZ)); 

// ...then multiply them to get final rotation 
quatY.multiply(quatX); 
quatZ.multiply(quatY); 

// Apply multiplied rotation to your mesh 
mesh.quaternion.copy(quatZ); 
関連する問題