การหมุนเวกเตอร์ 3 โดยควอเทอเนียน


25

ฉันพยายามหมุนเวกเตอร์ 3 ด้วย quaternion ที่กำหนด

ฉันรู้ว่านี่เป็นเรื่องจริง

โวลต์'=Qโวลต์Q-1

ฉันรู้ว่าเป็นสิ่งที่ตรงกันข้ามที่แต่ฉันจะแมปการคูณเวกเตอร์กับควอเทอเรียนเพื่อกลับเวกเตอร์ได้อย่างไร?Q-1-Qม.aก.nผมเสื้อยูdอี(Q)

ฉันได้พบว่าคุณสามารถปฏิบัติต่อเป็นเมทริกซ์และแปลงและเป็นเมทริกซ์แล้วแปลงจากเมทริกซ์เป็นเวกเตอร์ได้ แต่นี่ดูเหมือนจะน้อยกว่าด้านบนเพื่อรับเวกเตอร์ มีการนำไปใช้ที่สะอาดกว่าที่ฉันสามารถใช้ได้หรือไม่?โวลต์QQ'โวลต์'

คำตอบ:


36

เมื่อ Nathan Reed และ Teodron เปิดเผยสูตรการหมุนเวกเตอร์vโดยหน่วย quaternion ความยาวหน่วยqคือ:

1) การสร้าง quaternion บริสุทธิ์Pออกมาจากโวลต์ นี่หมายถึงการเพิ่มพิกัดที่สี่เป็น 0:

พี=(โวลต์x,โวลต์Y,โวลต์Z,0)พี=(โวลต์,0)

2) pre-multiply ด้วยqและ post-multiply ด้วย conjugate q * :

พี'=Q×พี×Q* * * *

3) สิ่งนี้จะส่งผลให้เกิด quaternion บริสุทธิ์อีกอันซึ่งสามารถกลับไปเป็นเวกเตอร์ได้:

โวลต์'=(พีx',พีY',พีZ')

นี้เวกเตอร์เป็นหมุนโดยQโวลต์'โวลต์Q


นี้คือการทำงาน แต่ไกลจากที่ดีที่สุด การคูณแบบควอเทอเรียนหมายถึงการปฏิบัติงานเป็นตันและตัน ฉันอยากรู้เกี่ยวกับการใช้งานที่หลากหลายเช่นอันนี้และตัดสินใจที่จะหาจากที่มาเหล่านั้น นี่คือสิ่งที่ฉันค้นพบ

นอกจากนี้เรายังสามารถอธิบายqเป็นการรวมกันของเวกเตอร์ 3 มิติuและ scalar s :

Q=(ยูx,ยูY,ยูZ,s)Q=(ยู,s)

ตามกฎของการคูณ quaternionและเมื่อการรวมกันของความยาวหน่วย quaternion เป็นเพียงการผกผันเราจะได้รับ:

พี'=QพีQ* * * *=(ยู,s)(โวลต์,0)(-ยู,s)=(sโวลต์+ยู×โวลต์,-ยูโวลต์)(-ยู,s)=((-ยูโวลต์)(-ยู)+s(sโวลต์+ยู× โวลต์)+(sโวลต์+ยู×โวลต์)×(-ยู),...)=((ยูโวลต์)ยู+s2โวลต์+s(ยู×โวลต์)+sโวลต์×(-ยู)+(ยู×โวลต์)×(-ยู),...)

ส่วนที่สเกลาร์ (วงรี) ผลลัพธ์ในศูนย์ตามรายละเอียดที่นี่ สิ่งที่น่าสนใจเป็นส่วนหนึ่งเวกเตอร์อาคาหมุนเวกเตอร์ของเราV' สามารถทำให้ง่ายขึ้นโดยใช้ข้อมูลเฉพาะตัวของเวกเตอร์พื้นฐาน :

โวลต์'=(ยูโวลต์)ยู+s2โวลต์+s(ยู×โวลต์)+s(ยู×โวลต์)+ยู×(ยู×โวลต์)=(ยูโวลต์)ยู+s2โวลต์+2s(ยู×โวลต์)+(ยูโวลต์)ยู-(ยูยู)โวลต์=2(ยูโวลต์)ยู+(s2-ยูยู)โวลต์+2s(ยู×โวลต์)

นี่เป็นสิ่งที่ดีที่สุดแล้ว สองผลิตภัณฑ์ดอทผลิตภัณฑ์แบบไขว้และความพิเศษอื่น ๆ : ประมาณครึ่งหนึ่งของการปฏิบัติการ ซึ่งจะให้อะไรเช่นนั้นในซอร์สโค้ด (สมมติว่ามีห้องสมุดคณิตศาสตร์เวกเตอร์ทั่วไป):

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

คัดค้านคำตอบที่เป็นลายลักษณ์อักษรที่ดีกว่า และเมื่อพิจารณาว่า freaks ด้านประสิทธิภาพส่วนใหญ่มักใช้ intrinsics ในการปฏิบัติการเวกเตอร์คุณจะได้รับความเร็วมากขึ้น (แม้สำหรับการคูณ quaternion แบบธรรมดาโดยเฉพาะในสถาปัตยกรรม Intel)
teodron

ผลสุดท้ายมีลักษณะคล้ายกับสูตรการหมุน Rodrigues' - มันมีพาหะพื้นฐานเดียวกันอยู่แล้ว ฉันต้องขุดลงไปในอัตลักษณ์ตรีโกณฯ เพื่อดูว่าสัมประสิทธิ์ตรงกันหรือไม่
นาธานรีด

@NathanReed นี่ดูเหมือนจะเป็นอีกวิธีหนึ่งที่จะได้ผลลัพธ์เช่นเดียวกัน ฉันต้องการทราบว่าการจับคู่นี้หรือไม่ ขอบคุณสำหรับการชี้ให้เห็น!
Laurent Couvidou

1
ฉันกำลังตรวจสอบการดำเนินการของ GLM และดูเหมือนว่าจะมีการใช้งานที่แตกต่างกันเล็กน้อยดังนี้: vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fนี่เป็นการเพิ่มประสิทธิภาพที่คล้ายกันหรือไม่ มันดูค่อนข้างคล้ายกัน แต่ไม่เหมือนกัน - ใช้เฉพาะผลิตภัณฑ์ Cross เท่านั้นไม่มีผลิตภัณฑ์ dot รหัสต้นฉบับสามารถพบได้ในไฟล์ type_quat.inl พื้นที่เก็บข้อมูล GLM อย่างเป็นทางการในoperator*ซึ่งจะนำ quaternion และเวกเตอร์ ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))
j00hi

7

ก่อนอื่น q ^ (- 1) ไม่ใช่ -q / magnitude (q); มันคือ q * / (ขนาด (q)) ^ 2 (q * คือคอนจูเกตซึ่งทำให้ส่วนต่าง ๆ ทั้งหมดยกเว้นของจริง) แน่นอนคุณสามารถละทิ้งการแบ่งตามขนาดถ้า quaternions ทั้งหมดของคุณเป็นปกติแล้วซึ่งพวกเขามักจะอยู่ในระบบการหมุน

สำหรับการคูณด้วยเวกเตอร์คุณแค่ขยายเวกเตอร์ไปเป็นควอเทอเนียนด้วยการตั้งค่าองค์ประกอบที่แท้จริงของ quat ให้เป็นศูนย์และส่วนประกอบ ijk เป็น xyz ของเวกเตอร์ จากนั้นคุณทำการคูณควอเทอเนียนชันเพื่อหา v 'แล้วแยกส่วนประกอบ ijk อีกครั้ง (ส่วนที่แท้จริงของ v 'ควรออกมาเป็นศูนย์เสมอบวกหรือลบข้อผิดพลาดบางจุดลอยตัว)


5

การสังเกตครั้งแรก: การผกผันของqไม่ใช่ความ-q/magnitude(q)ผิดทั้งหมด การหมุนที่มีควอเทอร์นอสบ่งบอกว่าจำนวนเชิงซ้อนจำนวน 4D ที่ซับซ้อนเหล่านี้มีบรรทัดฐานรวมกันดังนั้นจึงอยู่ในทรงกลมของหน่วย S3 ในพื้นที่ 4D นั้น ความจริงที่ว่า quat นั้นเป็นแบบรวมหมายความว่าบรรทัดฐานของมันคือnorm(q)^2=q*conjugate(q)=1และนั่นหมายความว่าสิ่งที่ตรงกันข้ามของ quat นั้นคือการผันคำกริยา

หากหน่วย quaternion เขียนเป็นq=(w,x,y,z)= (cos (t), sin (t) v ) ดังนั้นคอนจูเกตของมันคือconjugate(q)=(w,-x,-y,-z)= (cos (t), - sin (t) v ) โดยที่tคือครึ่งหนึ่งของมุมการหมุนและvคือแกนหมุน (แน่นอนว่าเป็นเวกเตอร์หน่วย)

เมื่อแฮมิลตันเพื่อนคนนั้นตัดสินใจที่จะเล่นด้วยจำนวนที่ซับซ้อนเทียบเท่าในมิติที่สูงขึ้นเขาก็สะดุดกับคุณสมบัติที่ดีบางอย่าง ตัวอย่างเช่นถ้าคุณจ้างควอเทอเนียนที่บริสุทธิ์q=(0,x,y,z)(ไม่มีสเกลาร์ส่วนที่w !) คุณสามารถพิจารณาอึนั้นว่าเป็นเวกเตอร์ (อันที่จริงแล้วมันคือสิ่งที่ผู้คนอาจเรียกว่าเส้นศูนย์สูตรของทรงกลม S3) ! - ใจงอสิ่งต่าง ๆ ถ้าเราพิจารณาว่าผู้คนที่มีความบกพร่องทางเทคนิคในศตวรรษที่ 19 ดูเหมือนจะมองดูว่าเรามีการเลี้ยงวัวด้วยตาแล้วในปัจจุบัน) แฮมิลตันจึงเอาเวกเตอร์นั้นมาในรูปแบบ quat: v=(0,x,y,z)และทำการทดลองหลายครั้งโดยพิจารณาคุณสมบัติทางเรขาคณิตของ quats .. เรื่องสั้นสั้น ๆ :

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)

ที่ไหน

 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

การสังเกต: q * (0, v) * conj (q) จะต้องเป็นอีก quat ของแบบฟอร์ม (0, v ') ฉันจะไม่อธิบายทุกอย่างที่ซับซ้อนว่าทำไมสิ่งนี้ถึงเกิดขึ้น แต่ถ้าคุณหมุน quaternion จินตภาพบริสุทธิ์ (หรือเวกเตอร์ในกรณีของเรา!) ด้วยวิธีนี้คุณต้องได้วัตถุที่คล้ายกัน: quat จินตภาพบริสุทธิ์ และคุณใช้ส่วนจินตภาพเป็นผลลัพธ์ของคุณ ที่นั่นคุณมีแล้วโลกแห่งการหมุนรอบที่ยอดเยี่ยมพร้อมกับควอเทอร์เนียนในเปลือกหอย (ty)

หมายเหตุ : ใครก็ตามที่กระโดดด้วยวลีที่ใช้มากเกินไป: quats นั้นดีเพราะพวกเขาหลีกเลี่ยง 'em gimbal lock .. ควรปลดล็อคจินตนาการของพวกเขาก่อน !! Quats เป็นเพียงเครื่องมือทางคณิตศาสตร์ที่ "สวยงาม" และสามารถหลีกเลี่ยงได้ทั้งหมดโดยใช้วิธีการอื่น ๆ อย่างใดอย่างหนึ่งที่ฉันพบว่ามีความเท่าเทียมกันทางเรขาคณิตอย่างสมบูรณ์เป็นแนวทางมุมของแกน

CODE : ไลบรารี่C ++ ที่ฉันนึกฝันง่าย แต่มีเมทริกซ์เวคเตอร์และการดำเนินการ quat ที่ผู้ทดลองใช้กราฟิก 3 มิติควรใช้โดยไม่ต้องเสียเวลาเรียนมากกว่า 15 นาที .. คุณสามารถทดสอบสิ่งที่ฉันเขียนที่นี่โดยใช้สิ่งนั้น ใน 15 นาทีถ้าคุณไม่ใช่มือใหม่ C ++ โชคดี!


+1 สำหรับบันทึกย่อของคุณ ฉันพนันได้เลยว่าคนส่วนใหญ่ไม่สามารถบรรลุล็อค gimbal จริง ๆ ถ้าพวกเขาพยายามมันกลายเป็นวลีทั้งหมดสำหรับพฤติกรรมที่ไม่คาดคิดเมื่อทำการหมุน
Steve H

คนส่วนใหญ่ไม่สามารถสร้างกลไก gimbal ที่เหมาะสมและคิดว่าถ้าพวกเขารวมกัน 3 เมทริกซ์ผลัดเปลี่ยนพวกเขาจะจบลงด้วยการเป็นตัวแทน "มุมออยเลอร์" โดยอัตโนมัติ .. สิ่ง gimbal เป็นเพียงหนึ่งในประเภทแขนหมุนที่ง่ายที่สุดของหุ่นยนต์ ข้อต่อที่สามารถสัมผัสกับความซ้ำซ้อนเมื่อพยายามทำจลศาสตร์แบบผกผัน (มีองศาอิสระมากกว่าที่จริงแล้วต้องสร้างแนวที่ต้องการ) โอ้ดีที่หัวข้ออื่น แต่ฉันคิดว่ามันเป็นเรื่องดีที่จะอยู่ห่างจาก hype นี้ปัญหา "ตำนาน" ได้สร้างขึ้นในหมู่โปรแกรมเมอร์ CG ..
teodron

Nitpickery: ในขณะที่มุมของแกนเทียบเท่ากับที่ทั้งสองสามารถเป็นตัวแทนการหมุนทั้งหมดใน SO (3) ไม่ซ้ำกัน (โอเคโมดูโลปกคู่ปกติ) และแน่นอนว่ามีการเปลี่ยนแปลงเล็กน้อยไปมาระหว่างพวกเขา quaternions มี ข้อดีของการเขียนได้ง่ายกว่าการเป็นตัวแทนที่ไม่ใช่เมทริกซ์อื่น ๆ ทั้งหมด
Steven Stadnicki

พวกเขามีข้อได้เปรียบในการเขียนได้ง่ายขึ้นเนื่องจากมีพฤติกรรมที่ดีในภาษาโปรแกรมเชิงวัตถุใด ๆ โดยเฉพาะอย่างยิ่งเมื่อใช้ตัวดำเนินการโอเวอร์โหลด ฉันไม่แน่ใจ แต่บางทีอาจจะมีคุณสมบัติการแก้ไขทรงกลมของพวกเขาสำหรับมุมแกน (ยกเว้น SQUAD อาจ?!)
teodron


-1

ฉันพยายามทำสิ่งนี้ด้วยมือและเกิดขึ้นกับสมการ / วิธีการต่อไปนี้:

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

ฉันจะขอบคุณถ้ามีใครบางคนจะมองไปที่ mt derivatiion ฉันใช้http://pastebin.com/8QHQqGbvฉันขอแนะนำให้คัดลอกไปยังโปรแกรมแก้ไขข้อความที่รองรับการเลื่อนด้านข้าง

ในสัญกรณ์ของฉันฉันใช้ q ^ (- 1) เพื่อหมายถึงคอนจูเกตและไม่ผกผันและตัวระบุที่แตกต่างกัน แต่ฉันหวังว่ามันจะสามารถติดตามได้ ฉันคิดว่าส่วนใหญ่ถูกต้องโดยเฉพาะที่การพิสูจน์ส่วนที่แท้จริงของเวกเตอร์จะหายไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.