2016-03-19 36 views
7

我有每個對象,每個旋轉軸都有一個獨立的父對象(1代表X旋轉,1代表Y旋轉,1代表Z旋轉)它們之間的順序依次爲:X旋轉對象是Y旋轉對象的子對象,Y旋轉對象是Z旋轉對象的子對象)。Three.js setFromRotationMatrix當旋轉超過90度時奇怪的行爲

我試圖做一個功能,允許用戶旋轉場景中的所有對象(它們都包含在一個Object3D中)。當Object3D旋轉時,程序必須找到所有對象相對於世界的絕對位置和旋轉,以便程序可以輸出每個對象的新值。

要做到這一點,我目前已經設置好移動對象,以便它在Object3D的「場景旋轉器」內的位置被設置爲相對於世界的絕對位置。現在,我試圖讓對象的旋轉成爲對象相對於世界的絕對旋轉,以便在「場景旋轉器」的旋轉改變時它相應地改變。此外,當我試圖在子對象上運行一次時,setFromRotationMatrix方法不能正常工作,所以相反,我不得不爲每個父對象再次運行它,並相應地從它們分別獲取各自的旋轉值。

這是代碼我現在有這應該獲得相對於世界物體的絕對旋轉:

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

我已經通讀了你的問題描述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);