2016-03-19 22 views
7

Tôi có các đối tượng có mỗi phụ huynh riêng biệt cho mỗi trục quay (1 cho quay X, 1 cho quay vòng Y và 1 cho xoay vòng Z. tất cả liên quan với nhau theo thứ tự đó: đối tượng quay X là một đối tượng con của đối tượng xoay vòng Y. đối tượng xoay Y là một đối tượng con của đối tượng xoay vòng Z).Ba.js setFromRotationMatrix hành vi lạ khi xoay trên 90 độ

Tôi đang cố gắng tạo một tính năng cho phép người dùng xoay tất cả các đối tượng trong cảnh cùng nhau (tất cả chúng đều được chứa trong một Object3D duy nhất). Khi Object3D đó được xoay, chương trình phải tìm tất cả các vị trí tuyệt đối của các đối tượng và phép quay tương đối so với thế giới để chương trình có thể xuất ra các giá trị mới cho từng đối tượng. Để thực hiện điều này, tôi hiện có thiết lập để di chuyển đối tượng sao cho vị trí của nó bên trong "rotator cảnh", là một Object3D, được đặt ở vị trí tuyệt đối tương đối so với thế giới. Bây giờ, tôi đang cố gắng làm cho vòng quay của đối tượng trở thành vòng quay tuyệt đối của đối tượng liên quan đến thế giới, do đó nó thay đổi tương ứng khi xoay vòng "cảnh quay" được thay đổi. Ngoài ra, phương thức setFromRotationMatrix không hoạt động chính xác khi tôi thử chạy nó một lần trên đối tượng con, do đó, thay vào đó, tôi phải chạy nó một lần nữa cho từng đối tượng cha và nhận từng vòng xoay riêng biệt từ chúng cho phù hợp

Đây là mã mà tôi hiện đang có mà là vụ phải được luân chuyển tuyệt đối của các đối tượng liên quan đến thế giới:

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 
}; 

Sau đó, nó phải được áp dụng mà quay tuyệt đối để luân chuyển tương đối của các đối tượng

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; 

này tất cả đều ổn khi Y-quay của cha mẹ thứ hai là trong phạm vi -90 đến 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 

nhưng khi Y-quay của cha mẹ thứ hai là dưới -90 hoặc lớn hơn 90, sau đó nó mang lại giá trị sai cho tuyệt đối vòng quay thế giới X và xoay vòng Y là kết quả

// 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

Tôi đã đọc qua vấn đề dscription của bạn 2 lần và không thể thực sự quấn quanh đầu những gì bạn đang cố gắng đạt được. Nhưng có một thứ đánh tôi là vấn đề xoay quanh mọi thứ xung quanh tất cả các trục với góc độ euler. Khi bạn trải nghiệm hành vi kỳ lạ khi quay với góc độ euler, nó có thể là do [Gimbal Lock] (https://en.wikipedia.org/wiki/Gimbal_lock). Tôi sẽ khuyên bạn nên thử điều này bằng cách sử dụng quaternions để thay thế. Three.js hỗ trợ chúng tốt – micnil

+0

Tôi có thể thấy ý của bạn là tại sao nó có vẻ dư thừa để thực hiện bất kỳ điều này, nhưng để tham khảo, đây là trang mà nó dành cho: https://mrgarretto.com/model/ và nó là một công cụ để mọi người sử dụng phải có khả năng tạo ra nhiều thứ khác nhau sau khi người dùng tạo một dự án với nó. Đây là một album mà tôi đặt cùng nhau có thể giúp hiển thị sự cố trong hành động: http: // imgur.com/a/jkTeo Tôi sẽ thử sử dụng quaternions và xem nó có khắc phục được sự cố không – MrGarretto

Trả lời

0

Bạn đang chạy vào gimbal lock. Khi sử dụng các góc euler, bạn sẽ luôn gặp phải các vấn đề về khóa gimbal và bạn sẽ gặp phải các hành vi không mong muốn khi áp dụng nhiều phép quay.

Ví dụ, trong không gian 2D, xoay 30 ° cũng giống như xoay -330 °. Trong không gian 3D, bạn có thể gặp vấn đề tương tự: xoay đối tượng 180 ° trong trục X giống như xoay 180 ° trục Y + 180 ° Z.

Bạn nên khai báo phép xoay của mình bằng cách sử dụng quaternions và sau đó nhân chúng với nhau để nhận kết quả mong muốn mà không gặp vấn đề về khóa gimbal.

// 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);