Xoay vector3 bởi một tứ


25

Tôi đang cố gắng xoay một vectơ 3 theo một bậc bốn cho trước.

Tôi biết rằng đây là sự thật

v=qvq1

Tôi biết rằng là nghịch đảo chỉ , nhưng làm cách nào để ánh xạ phép nhân của vectơ sang bậc bốn để lấy lại vectơ?q1qmagnitude(q)

Tôi đã thấy rằng bạn có thể coi là một ma trận, và chuyển đổi và thành ma trận, sau đó chuyển đổi từ một ma trận thành một vectơ, nhưng điều này có vẻ hơi vượt trội chỉ để có được một vectơ. Có một thực hiện sạch hơn mà tôi có thể sử dụng?vqqv

Câu trả lời:


36

Khi Nathan Reed và teodron tiếp xúc, công thức để quay vectơ v theo một bậc bốn q đơn vị là:

1) Tạo một quernion tinh khiết p ra khỏi v . Điều này chỉ có nghĩa là thêm tọa độ thứ tư bằng 0:

p=(vx,vy,vz,0)p=(v,0)

2) Nhân trước nó với q và nhân nó với liên hợp q * :

p=q×p×q

3) Điều này sẽ dẫn đến một tứ phương thuần túy khác có thể được quay lại thành một vectơ:

v=(px,py,pz)

Đây vector vv xoay bởi q .


Điều này đang làm việc nhưng xa tối ưu . Phép nhân bậc bốn có nghĩa là tấn và tấn hoạt động. Tôi tò mò về các triển khai khác nhau như cái này , và quyết định tìm từ nơi chúng đến. Dưới đây là những phát hiện của tôi.

Chúng ta cũng có thể mô tả q là sự kết hợp của vectơ 3 chiều u và vô hướng s :

q=(ux,uy,uz,s)q=(u,s)

Theo quy tắc nhân tứ phương , và khi liên hợp của một đơn vị độ dài đơn vị đơn giản là nó nghịch đảo, chúng ta nhận được:

p=qpq=(u,s)(v,0)(u,s)=(sv+u×v,uv)(u,s)=((uv)(u)+s(sv+u× v)+(sv+u×v)×(u),)=((uv)u+s2v+s(u×v)+sv×(u)+(u×v)×(u),)

Phần vô hướng (elip) cho kết quả bằng 0, như chi tiết ở đây . Điều thú vị là phần vectơ, AKA vectơ xoay của chúng tôi v ' . Nó có thể được đơn giản hóa bằng cách sử dụng một số định danh vector cơ bản :

v'= =(bạnv)bạn+S2v+S(bạn×v)+S(bạn×v)+bạn×(bạn×v)= =(bạnv)bạn+S2v+2S(bạn×v)+(bạnv)bạn-(bạnbạn)v= =2(bạnv)bạn+(S2-bạnbạn)v+2S(bạn×v)

Điều này bây giờ tối ưu hơn nhiều ; hai sản phẩm chấm, một sản phẩm chéo và một vài tính năng bổ sung: khoảng một nửa hoạt động. Mà sẽ cung cấp một cái gì đó như thế trong mã nguồn (giả sử một số thư viện toán học vectơ chung):

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
          + (s*s - dot(u, u)) * v
          + 2.0f * s * cross(u, v);
}

Ngả mũ trước một phản ứng bằng văn bản tốt hơn . Và xem xét rằng hầu hết các quái vật hiệu suất có xu hướng sử dụng nội tại để thực hiện các hoạt động vectơ, bạn sẽ tăng tốc khá nhanh (ngay cả đối với phép nhân bậc bốn đơn giản, đặc biệt là trên các kiến ​​trúc intel).
teodron

Kết quả cuối cùng trông tương tự như công thức xoay vòng của Coleues - dù sao nó cũng có các vectơ cơ sở tương tự; Tôi phải đào sâu vào một số danh tính trig để xem các hệ số có khớp không.
Nathan Reed

@NathanReed Đây dường như là một cách khác để đi đến kết quả tương tự. Tôi cũng muốn biết nếu điều này phù hợp. Cảm ơn đã chỉ ra rằng!
Laurent Couvidou

1
Tôi đã kiểm tra việc triển khai GLM của việc này và dường như nó được triển khai hơi khác một chút, cụ thể như sau: vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fĐây có phải là một tối ưu hóa tương tự không? Nó trông hơi giống nhau, nhưng không giống nhau - nó chỉ sử dụng các sản phẩm chéo, không có sản phẩm chấm. Mã nguồn ban đầu có thể được tìm thấy trong tệp type_quat.inl của kho lưu trữ GLM chính thức, trong operator*đó có một phần tư và một vectơ ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))
j00hi

7

Trước hết, q ^ (- 1) không phải là -q / độ lớn (q); đó là q * / (độ lớn (q)) ^ 2 (q * là liên hợp; phủ định tất cả các thành phần ngoại trừ thành phần thực). Tất nhiên, bạn có thể rời khỏi sự phân chia theo độ lớn nếu tất cả các bậc bốn của bạn đã được chuẩn hóa, mà chúng thường nằm trong một hệ thống xoay vòng.

Đối với phép nhân với một vectơ, bạn chỉ cần mở rộng vectơ thành một phần tư bằng cách đặt thành phần thực của quat thành 0 và các thành phần ijk của nó thành xyz của vectơ. Sau đó, bạn thực hiện phép nhân bậc bốn để có v ', và sau đó trích xuất các thành phần ijk một lần nữa. (Phần thực của v 'phải luôn luôn bằng 0, cộng hoặc trừ một số lỗi dấu phẩy động.)


5

Quan sát đầu tiên: Nghịch đảo qlà không -q/magnitude(q), điều đó là hoàn toàn sai. Các phép quay với các bậc bốn ngụ ý rằng các số tương đương số phức 4D này có định mức đơn nhất, do đó nằm trên quả cầu đơn vị S3 trong không gian 4D đó. Thực tế là một quat là đơn nhất có nghĩa là chuẩn mực của nó norm(q)^2=q*conjugate(q)=1và điều đó có nghĩa là nghịch đảo của quat là liên hợp của nó.

Nếu một đơn vị bậc bốn được viết là q=(w,x,y,z)= (cos (t), sin (t) v ), thì liên hợp của nó là conjugate(q)=(w,-x,-y,-z)= (cos (t), - sin (t) v ), trong đó t là một nửa góc xoay và v là trục quay (tất nhiên là một vector đơn vị).

Khi anh chàng Hamilton quyết định chơi xung quanh với số lượng tương đương phức tạp ở các chiều cao hơn, anh ta cũng tình cờ phát hiện ra một số tính chất tốt. Ví dụ: nếu bạn sử dụng một bộ tứ hoàn toàn thuần túy q=(0,x,y,z)(không có phần vô hướng w !), Bạn có thể coi crap đó là một vectơ (thực ra nó là một quat trên cái mà mọi người có thể gọi là đường xích đạo của hình cầu S3, là hình cầu S2! ! - công cụ uốn cong tâm trí nếu chúng ta xem xét những người suy yếu về mặt kỹ thuật trong thế kỷ 19 dường như đối với chúng ta như những chàng cao bồi hiện nay). Vì vậy, Hamilton đã lấy vectơ đó ở dạng quat: v=(0,x,y,z)và thực hiện một loạt các thí nghiệm xem xét các tính chất hình học của quats .. Câu chuyện dài ngắn:

INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_

OUTPUT: q*(0,_v_)*conjugate(q)

Ở đâu

 q = (cos(theta/2), sin(theta/2)*u)
 conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
 norm(q)=magnitude(q)=|q|=1

Quan sát: q * (0, v) * const (q) phải là một quat khác có dạng (0, v '). Tôi sẽ không xem qua tất cả những lời giải thích có vẻ phức tạp về lý do tại sao điều này xảy ra, nhưng nếu bạn xoay một phần tư tưởng tượng thuần túy (hoặc một vectơ trong trường hợp của chúng tôi!) Thông qua phương pháp này, bạn phải có được một loại đối tượng tương tự: quat tưởng tượng thuần túy. và bạn lấy phần tưởng tượng của nó làm kết quả của bạn. Ở đó bạn có nó, thế giới tuyệt vời của các vòng quay với các bậc bốn trong một vỏ hạt (ty).

LƯU Ý : để bất kỳ ai nhảy vào với cụm từ được sử dụng quá mức đó: quats là tốt bởi vì họ tránh được khóa gimbal .. nên mở khóa trí tưởng tượng của họ trước !! Quats là một bộ máy toán học "thanh lịch" đơn thuần và có thể tránh được hoàn toàn bằng cách sử dụng các phương pháp khác, phương pháp tôi thấy hoàn toàn tương đương về mặt hình học là cách tiếp cận góc trục.

: thư viện C ++ mà tôi ưa thích khá đơn giản, nhưng có tất cả các hoạt động ma trận, vectơ và quat mà một nhà thử nghiệm đồ họa 3D cần mà không phải lãng phí hơn 15 phút để tìm hiểu .. Bạn có thể kiểm tra những điều tôi đã viết ở đây bằng cách sử dụng trong 15 phút nếu bạn không phải là người mới làm quen với C ++. Chúc may mắn!


+1 cho ghi chú của bạn. Tôi cá là hầu hết mọi người không thể đạt được khóa gimbal thực sự nếu họ đã cố gắng. Nó đã trở thành một cụm từ bắt tất cả các hành vi bất ngờ khi thực hiện các phép quay.
Steve H

Hầu hết mọi người không thể xây dựng một cơ chế gimbal thích hợp và nghĩ rằng nếu họ kết hợp 3 ma trận xoay, họ sẽ tự động kết thúc với biểu diễn "Góc Euler" .. Gimbal thingie chỉ là một trong những kiểu xoay cánh tay robot đơn giản nhất các khớp có thể gặp phải sự dư thừa khi cố gắng thực hiện động học nghịch đảo (nó có nhiều mức độ tự do hơn so với thực tế cần thiết để tạo ra hướng mong muốn). Ồ, đó là một chủ đề khác, nhưng tôi nghĩ thật tốt khi tránh xa sự cường điệu mà vấn đề "huyền thoại" này đã tạo ra trong số các lập trình viên CG ..
teodron

Nitopperery: trong khi góc trục tương đương ở chỗ cả hai biểu diễn có thể đại diện cho tất cả các phép quay trong SO (3) duy nhất (được, modulo nắp kép thông thường) và tất nhiên có sự biến đổi gần như tầm thường giữa chúng, các bậc bốn có lợi thế của việc soạn thảo dễ dàng hơn nhiều so với tất cả các biểu diễn phi ma trận khác.
Steven Stadnicki

Chúng có ưu điểm là dễ soạn thảo hơn do hành vi đẹp của chúng trong bất kỳ ngôn ngữ lập trình hướng đối tượng nào, đặc biệt là khi sử dụng quá tải toán tử. Tôi không chắc, nhưng có lẽ ngay cả các thuộc tính nội suy hình cầu của chúng cũng bảo toàn cho góc trục (ngoại trừ SQUAD có thể?!).
teodron


-1

Tôi đã cố gắng thực hiện điều này bằng tay, và đưa ra phương trình / phương pháp sau:

// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
    Vector3 vec();   // any constructor will do
    vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
    vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
    vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
    return vec;
}

Tôi sẽ đánh giá cao nếu ai đó sẽ xem qua dẫn xuất mt mà tôi đã sử dụng http://pastebin.com/8QHQqGbv Tôi sẽ đề nghị sao chép vào trình chỉnh sửa văn bản hỗ trợ cuộn bên

trong ký hiệu của tôi, tôi đã sử dụng q ^ (- 1) có nghĩa là liên hợp, và không nghịch đảo và các định danh khác nhau, nhưng tôi hy vọng rằng nó có thể theo dõi được. Tôi nghĩ rằng đa số là đúng, đặc biệt là khi chứng minh phần thực của vectơ sẽ biến mất.

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.