Làm thế nào để xoay một đối tượng xung quanh trục liên kết thế giới?


15

Tôi có một Vector3 có góc euler cho mỗi trục.

Thông thường, khi tôi muốn tạo ma trận xoay, tôi sẽ sử dụng các hàm như D3DXMatrixRotationX chuyển góc tương ứng từ vectơ xoay của tôi ở trên và nhân ma trận (ZXY) để tạo ma trận xoay tổng thể được sử dụng để tạo thành ma trận biến đổi đối tượng hoàn chỉnh.

Tuy nhiên, phương pháp này sẽ tạo ra một tập hợp các phép quay trong không gian đối tượng. Nghĩa là, truyền một vectơ (90, 0, 90) vào phương thức của tôi sẽ tạo ra một vòng quay trong không gian thế giới một cách hiệu quả (90, 90, 0).

Có cách nào để luôn đảm bảo mỗi thành phần của vectơ xoay của tôi dẫn đến một vòng xoay quanh các trục liên kết không gian thế giới tương ứng không?

BIÊN TẬP:

Đây là một hình ảnh động về những gì đang diễn ra - tôi muốn có một cách xoay quanh các trục màu xanh, không phải màu đỏ.

Thiên thần Euler

EDIT 2:

Chỉ cần lưu ý rằng tôi không tìm kiếm một giải pháp liên quan đến các góc Euler, mà chỉ đơn giản là một cách mà tôi có thể đại diện cho một sự biến đổi của nhiều phép quay quanh các trục thế giới.


Có gì sai khi chỉ gọi các hàm differnet ba lần và lọc ra các phần của vectơ bạn không muốn (bằng cách đặt chúng thành 0 trước khi gọi hàm)? Mặt khác, tôi không chắc chắn những gì bạn đang cố gắng để đạt được.
TravisG

Lọc cái gì ra? Tôi gọi 3 hàm riêng biệt và sau đó nhân chúng để tạo ma trận biến đổi. Điều này lưu trữ một vòng quay địa phương mặc dù.
Cú pháp_

Bạn có muốn các góc Euler, hoặc xoay quanh các trục thế giới không? Lưu ý rằng theo định nghĩa của các góc Euler (ví dụ en.wikipedia.org/wiki/Euler_angles ), chỉ có góc alpha là đúng về trục thế giới. Hai góc còn lại liên quan đến trục nghiêng không nhất thiết trùng với trục thế giới.
DMGregory

1
Sử dụng các góc Euler, bạn sẽ nhân tất cả ba ma trận xoay trước khi áp dụng sau đó trên đỉnh. Nếu M, N, O là các ma trận xoay, hoạt động kết quả là MNO v. Điều tôi đã đề xuất là áp dụng riêng từng ma trận: v1 = O v0, sau đó v2 = N v1 và cuối cùng là v3 = M v2. Bằng cách này, mỗi vi sẽ ở tọa độ thế giới và bạn chỉ cần sử dụng ma trận xoay cho trục hiện tại trong tọa độ thế giới.
DSilva.vinicius

3
@ dsilva.vinicius Các phép biến đổi tách biệt của bạn hoàn toàn giống với phép biến đổi kết hợp hoặc nói cách khác: MNO v == M * (N * (O v))
GuyRT 12/12/13

Câu trả lời:


1

Dựa trên các nhận xét của bạn, có vẻ như bạn đang lưu trữ hướng của đối tượng dưới dạng tập hợp các góc Euler và trong / giảm các góc khi người chơi xoay đối tượng. Đó là, bạn có một cái gì đó giống như mã giả này:

// in player input handling:
if (axis == AXIS_X) object.angleX += dir;
else if (axis == AXIS_Y) object.angleY += dir;
else if (axis == AXIS_Z) object.angleZ += dir;

// in physics update and/or draw code:
matrix = eulerAnglesToMatrix(object.angleX, object.angleY, object.angleZ);

Như Charles Beattie lưu ý , vì các phép quay không đi lại, điều này sẽ không hoạt động như mong đợi trừ khi người chơi xoay đối tượng theo cùng thứ tự eulerAnglesToMatrix()áp dụng các phép quay.

Cụ thể, hãy xem xét trình tự xoay sau đây:

  1. xoay đối tượng theo x độ quanh trục X;
  2. xoay đối tượng theo độ y quanh trục Y;
  3. xoay đối tượng theo - x độ quanh trục X;
  4. xoay đối tượng theo - y độ quanh trục Y.

Trong biểu diễn góc Euler ngây thơ, như được thực hiện trong mã giả ở trên, các phép quay này sẽ hủy bỏ và đối tượng sẽ trở về hướng ban đầu. Trong thế giới thực, điều này không xảy ra - nếu bạn không tin tôi, hãy lấy một cái chết sáu mặt hoặc khối Rubik, hãy x = y = 90 ° và tự mình thử!

Giải pháp, như bạn lưu ý trong câu trả lời của riêng bạn , là lưu trữ hướng của đối tượng dưới dạng ma trận xoay (hoặc bậc bốn) và cập nhật ma trận đó dựa trên đầu vào của người dùng. Đó là, thay vì mã giả ở trên, bạn sẽ làm một cái gì đó như thế này:

// in player input handling:
if (axis == AXIS_X) object.orientation *= eulerAnglesToMatrix(dir, 0, 0);
else if (axis == AXIS_Y) object.orientation *= eulerAnglesToMatrix(0, dir, 0);
else if (axis == AXIS_Z) object.orientation *= eulerAnglesToMatrix(0, 0, dir);

// in physics update and/or draw code:
matrix = object.orientation;  // already in matrix form!

(Về mặt kỹ thuật, vì bất kỳ ma trận xoay hoặc quaternion có thể được biểu diễn dưới dạng một tập hợp các góc Euler, nó có thể sử dụng chúng để lưu trữ các định hướng của đối tượng. Tuy nhiên, quy tắc vật lý chính xác cho việc kết hợp hai phép quay liên tục, mỗi đại diện như Góc Euler, thành một vòng quay duy nhất khá phức tạp và về cơ bản là chuyển đổi các phép quay thành ma trận / bậc bốn, nhân chúng và sau đó chuyển đổi kết quả trở lại thành các góc Euler.)


Có bạn đúng đây là giải pháp. Tôi cảm thấy điều này tốt hơn một chút so với câu trả lời của Concept3d khi anh ta đưa ra ấn tượng rằng cần có một bộ tứ nhưng điều đó không đúng. Miễn là tôi lưu trữ vòng quay hiện tại dưới dạng ma trận và không phải là ba góc Euler thì nó vẫn ổn.
Cú pháp

14

Vấn đề với các phép quay, là, hầu hết mọi người nghĩ về nó theo góc độ Euler, vì chúng dễ hiểu.

Tuy nhiên, hầu hết mọi người quên mất rằng các góc Euler là ba góc liên tiếp . Có nghĩa là xoay quanh trục đầu tiên, sẽ làm cho lần xoay tiếp theo tương đối với xoay ban đầu, do đó bạn không thể xoay độc lập một vectơ quanh mỗi trục 3 bằng các góc Euler.

Điều này trực tiếp chuyển thành ma trận khi bạn nhân hai ma trận, bạn có thể nghĩ phép nhân này là biến đổi một ma trận thành không gian của ma trận khác.

Điều này có nghĩa là xảy ra với bất kỳ 3 lần quay liên tiếp nào ngay cả khi sử dụng tứ phương.

nhập mô tả hình ảnh ở đây

Tôi muốn nhấn mạnh một thực tế rằng tứ phương không phải là một giải pháp cho khóa gimble. Trên thực tế, khóa gimble sẽ luôn xảy ra nếu bạn biểu diễn các góc Euler bằng cách sử dụng tứ phương. Vấn đề không phải là đại diện, vấn đề là các 3 bước tuần tự.

Giải pháp?

Giải pháp cho việc xoay một vectơ độc lập quanh 3 trục là kết hợp thành một trục đơn và một góc duy nhất, bằng cách này bạn có thể thoát khỏi bước mà bạn phải thực hiện phép nhân liên tiếp. Điều này sẽ chuyển thành hiệu quả:

Ma trận xoay của tôi biểu thị kết quả của phép quay quanh X và Y và Z.

thay vì giải thích Euler của

Ma trận xoay của tôi đại diện cho phép quay quanh X rồi Y rồi Z.

Để làm rõ điều này, tôi sẽ trích dẫn từ định lý xoay vòng của wikipedia Euler:

Theo định lý xoay của Euler, mọi phép quay hoặc chuỗi xoay của vật cứng hoặc hệ tọa độ về một điểm cố định đều tương đương với một góc quay bởi một góc cho trước về một trục cố định (gọi là trục Euler) chạy qua điểm cố định. Trục Euler thường được biểu thị bằng một vectơ đơn vị u →. Do đó, bất kỳ phép quay nào trong ba chiều có thể được biểu diễn dưới dạng kết hợp của vectơ u → và vô hướng. Đệ tứ đưa ra một cách đơn giản để mã hóa biểu diễn góc trục này theo bốn số và áp dụng phép xoay tương ứng cho một vectơ vị trí biểu thị một điểm liên quan đến điểm gốc trong R3.

Lưu ý rằng nhân 3 ma trận sẽ luôn đại diện cho 3 phép quay liên tiếp.

Bây giờ sắp xếp thứ tự để kết hợp các phép quay quanh 3 trục, bạn cần lấy một trục đơn và các góc đơn đại diện cho phép quay quanh X, Y, Z. Nói cách khác, bạn cần sử dụng biểu diễn Trục / Góc hoặc bậc bốn để thoát khỏi các phép quay liên tiếp.

Điều này thường được thực hiện, bằng cách bắt đầu với một định hướng ban đầu (định hướng có thể được coi là một góc trục), thường được biểu diễn dưới dạng góc thứ tư hoặc góc trục, sau đó sửa đổi định hướng đó để thể hiện hướng đích của bạn. Ví dụ: bạn bắt đầu với phần định danh và sau đó xoay theo sự khác biệt để đạt được hướng đích. Bằng cách này, bạn không mất bất kỳ mức độ tự do.


Đánh dấu là câu trả lời vì nó có vẻ sâu sắc.
Cú pháp

Tôi đang gặp một số khó khăn để tìm ra những gì bạn đang cố gắng nói với câu trả lời này. Có phải chỉ đơn giản là "không lưu trữ hướng của một đối tượng dưới dạng góc Euler"? Và nếu vậy, tại sao không chỉ nói như vậy?
Ilmari Karonen

@IlmariKaronen Có thể nói rõ hơn, nhưng tôi nghĩ khái niệm 3d đang thúc đẩy biểu diễn góc trục; xem phần 1.2.2 của tài liệu này để biết mối quan hệ giữa góc trục và bậc bốn. Biểu diễn góc trục dễ thực hiện hơn vì những lý do trên, nó không bị khóa gimbal và (đối với tôi ít nhất) nó cũng dễ hiểu như góc Euler.
Hải lý

@ concept3d, điều đó rất thú vị, và tôi thực sự thích câu trả lời của bạn. Có một điều còn thiếu đối với tôi, đó là mọi người tương tác với máy tính bằng bàn phím và chuột, nếu chúng ta nghĩ về chuột thì chúng ta đang nói về deltas chuột x và y. Làm thế nào để biểu diễn các x, y deltas này với một bậc bốn mà chúng ta có thể sử dụng để tạo ma trận xoay, chẳng hạn để thay đổi hướng đối tượng?
gmagno

@gmagno cách tiếp cận thường là chiếu chuyển động của chuột lên các vật thể hoặc cảnh và tính toán vùng đồng bằng trong không gian đó, bạn thực hiện điều này bằng cách chiếu một tia và tính toán giao điểm. Tìm kiếm phương pháp truyền tia, dự án và dự án, tôi không hiểu chi tiết vì tôi đã không làm việc trong CG trong nhiều năm nay. Hy vọng rằng sẽ giúp.
concept3d

2

Chuyển đổi một sự kết hợp của các phép quay từ không gian đối tượng sang không gian thế giới là chuyện nhỏ: bạn chỉ cần đảo ngược thứ tự áp dụng phép quay.

Trong trường hợp của bạn, thay vì nhân ma trận Z × X × Y, bạn chỉ cần tính toán Y × X × Z.

Một lý do cho điều này có thể được tìm thấy trên Wikipedia: chuyển đổi giữa các vòng quay bên trong và bên ngoài .


Nếu đó là sự thật thì tuyên bố sau từ nguồn của bạn sẽ không đúng, bởi vì các phép quay sẽ khác nhau: "Bất kỳ phép quay bên ngoài nào cũng tương đương với một phép quay nội tại theo cùng một góc nhưng với thứ tự đảo ngược của các phần tử xoay ngược lại và ngược lại . "
Cú pháp

1
Tôi thấy không có mâu thuẫn ở đây. Cả câu trả lời của tôi và câu nói đó đều đúng. Và đúng vậy, thực hiện các phép quay trong không gian đối tượng và trong không gian thế giới mang lại các phép quay khác nhau; Đó chính xác là vấn đề, phải không?
sam hocevar

Tuyên bố đó nói rằng việc thay đổi thứ tự sẽ luôn dẫn đến cùng một vòng quay. Nếu một đơn hàng đang tạo ra vòng quay sai thì đơn hàng khác cũng sẽ có nghĩa là đó không phải là một giải pháp.
Cú pháp_

1
Bạn đang đọc sai. Thay đổi thứ tự không dẫn đến cùng một vòng quay. Thay đổi thứ tự chuyển đổi từ các vòng quay nội tại sang các vòng quay bên ngoài dẫn đến cùng một vòng quay.
sam hocevar

1
Tôi không nghĩ rằng tôi hiểu câu hỏi của bạn. GIF của bạn hiển thị góc xoay khoảng 50 độ Z(không gian đối tượng), sau đó 50 độ xung quanh X(không gian đối tượng), sau đó 45 độ xung quanh Y(không gian đối tượng). Điều này giống hệt như xoay 45 độ xung quanh Y( không gian thế giới ), sau đó 50 độ X( không gian thế giới ), sau đó 50 độ xung quanh Z( không gian thế giới ).
sam hocevar

1

Tôi sẽ cung cấp giải pháp của mình như một câu trả lời cho đến khi ai đó có thể giải thích lý do tại sao điều này hoạt động.

Mỗi kết xuất tôi đang xây dựng lại bộ tứ của mình bằng cách sử dụng các góc được lưu trữ trong vectơ xoay của tôi và sau đó áp dụng bộ tứ cho biến đổi cuối cùng của tôi.

Tuy nhiên, để giữ nó ở khắp các trục thế giới, tôi phải giữ lại tứ phân vị trên tất cả các khung và chỉ xoay các đối tượng bằng cách sử dụng một sự khác biệt về góc, tức là ..

// To rotate an angle around X - note this is an additional rotation.
// If currently rotated 90, apply this function with angle of 90, total rotation = 180.
D3DXQUATERNION q;
D3DXQuaternionRotation(&q, D3DXVECTOR3(1.0f, 0.0f, 0.0f), fAngle);
m_qRotation *= q; 

//...

// When rendering rebuild world matrix
D3DXMATRIX mTemp;
D3DXMatrixIdentity(&m_mWorld);

// Scale
D3DXMatrixScaling(&mTemp, m_vScale.x, m_vScale.y, m_vScale.z);
m_mWorld *= mTemp;

// Rotate
D3DXMatrixRotationQuaternion(&mTemp, m_qRotation);
m_mWorld *= mTemp;

// Translation
D3DXMatrixTranslation(&mTemp, m_vPosition.x, m_vPosition.y, m_vPosition.z);
m_mWorld *= mTemp;

(Verbose cho sự sẵn sàng)

Tôi nghĩ rằng DSilva.vinicius đã cố gắng để đi đến điểm này.


1

Bạn sẽ cần lưu trữ thứ tự của các phép quay.

Rotating around x 90 then rotate around z 90 !=
Rotating around z 90 then rotate around x 90.

Lưu trữ ma trận xoay vòng hiện tại của bạn và ngay lập tức mỗi vòng quay khi chúng đến.


0

Ngoài câu trả lời @ concept3d, bạn có thể sử dụng 3 ma trận xoay ngoài để xoay quanh trục theo tọa độ thế giới. Trích dẫn từ Wikipedia :

Xoay ngoài là các phép quay nguyên tố xảy ra về các trục của hệ tọa độ cố định xyz. Hệ thống XYZ quay, trong khi xyz được cố định. Bắt đầu với XYZ chồng chéo xyz, một thành phần của ba phép quay ngoài có thể được sử dụng để đạt được bất kỳ hướng mục tiêu nào cho XYZ. Các góc Euler hoặc Tait Bryan (α,, γ) là biên độ của các phép quay nguyên tố này. Chẳng hạn, hướng đích có thể đạt được như sau:

Hệ thống XYZ quay quanh trục z bằng α. Trục X bây giờ nằm ​​ở góc α so với trục x.

Hệ thống XYZ quay lại trục x bằng β. Trục Z bây giờ nằm ​​ở góc so với trục z.

Hệ thống XYZ quay lần thứ ba về trục z bằng γ.

Ma trận quay có thể được sử dụng để biểu diễn một chuỗi các phép quay ngoài. Ví dụ,

R = Z (γ) Y () X (α)

đại diện cho một thành phần của các phép quay ngoại lai về các trục xyz, nếu được sử dụng để nhân các vectơ cột trước, trong khi

R = X (α) Y () Z ()

thể hiện chính xác cùng một thành phần khi được sử dụng cho các vectơ hàng nhân.

Vì vậy, những gì bạn cần là đảo ngược thứ tự của các phép quay liên quan đến những gì bạn sẽ làm bằng cách sử dụng các phép quay nội tại (hoặc không gian cục bộ). @Syntac yêu cầu xoay zxy, vì vậy chúng ta nên thực hiện xoay ngoài yxz để đạt được kết quả tương tự. Mã dưới đây:

Ma trận giá trị giải thích ở đây .

// Init things.
D3DXMATRIX *rotationMatrixX = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixY = new D3DXMATRIX();
D3DXMATRIX *rotationMatrixZ = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix0 = new D3DXMATRIX();
D3DXMATRIX *resultRotationMatrix1 = new D3DXMATRIX();

D3DXMatrixRotationX(rotationMatrixX, angleX);
D3DXMatrixRotationY(rotationMatrixY, angleY);
D3DXMatrixRotationZ(rotationMatrixZ, angleZ);

// yx extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix0, rotationMatrixY, rotationMatrixX);
// yxz extrinsic rotation matrix
D3DXMatrixMultiply(resultRotationMatrix1, resultRotationMatrix0, rotationMatrixZ);

D3DXVECTOR4* originalVector = // Original value to be transformed;
D3DXVECTOR4* transformedVector = new D3DXVECTOR4();

// Applying matrix to the vector.
D3DXVec4Transform(transformedVector, originalVector, resultRotationMatrix1);

// Don't forget to clean memory!

Mã này là mô phạm, không tối ưu, vì Bạn có thể sử dụng lại một số ma trận D3DXMATRIX.


1
xin lỗi người đàn ông này là không chính xác. phép nhân ma trận / vectơ là kết hợp. điều này hoàn toàn giống với phép nhân ma trận kết hợp.
khái niệm3d

Bạn đúng rồi. Tôi đã trộn lẫn các khái niệm về xoay ngoài và nội tại.
DSilva.vinicius

Tôi sẽ sửa câu trả lời này.
DSilva.vinicius

Câu trả lời đã được sửa.
DSilva.vinicius
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.