จะหมุนวัตถุรอบแกนโลกได้อย่างไร?


15

ฉันมี Vector3 ซึ่งมีมุมออยเลอร์สำหรับแต่ละแกน

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

อย่างไรก็ตามวิธีนี้จะสร้างชุดการหมุนในพื้นที่วัตถุ นั่นคือการส่งเวกเตอร์ (90, 0, 90) ไปยังวิธีการของฉันจะสร้างการหมุนในอวกาศโลกได้อย่างมีประสิทธิภาพ (90, 90, 0)

มีวิธีใดที่จะทำให้แน่ใจว่าแต่ละองค์ประกอบของเวกเตอร์การหมุนของฉันส่งผลให้เกิดการหมุนรอบแกนโลกตามแนวแกนอวกาศที่เกี่ยวข้องหรือไม่?

แก้ไข:

นี่เป็นอนิเมชั่นของสิ่งที่กำลังเกิดขึ้น - ฉันต้องการวิธีหมุนรอบแกนสีน้ำเงินไม่ใช่สีแดง

มุมออยเลอร์

แก้ไข 2:

เพียงเพื่อทราบว่าฉันไม่ได้มองหาวิธีการแก้ปัญหาที่เกี่ยวข้องกับมุมออยเลอร์ แต่เพียงวิธีที่ฉันสามารถเป็นตัวแทนการเปลี่ยนแปลงของการหมุนรอบหลายแกนทั่วโลก


เกิดอะไรขึ้นกับการเรียกใช้ฟังก์ชัน differnet สามครั้งแล้วกรองส่วนของเวกเตอร์ที่คุณไม่ต้องการ (โดยตั้งให้เป็น 0 ก่อนจะเรียกใช้ฟังก์ชัน) ไม่เช่นนั้นฉันไม่แน่ใจว่าคุณกำลังทำอะไรอยู่
TravisG

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

คุณต้องการมุมออยเลอร์หรือหมุนรอบแกนโลกหรือไม่? โปรดทราบว่าตามคำจำกัดความของมุมออยเลอร์ (เช่นen.wikipedia.org/wiki/Euler_angles ) เฉพาะมุมอัลฟาเท่านั้นที่เกี่ยวกับแกนโลกอย่างเคร่งครัด มุมอีกสองมุมนั้นสัมพันธ์กับแกนเอียงซึ่งไม่จำเป็นต้องตรงกับแกนโลก
DMGregory

1
การใช้มุมออยเลอร์คุณจะคูณเมทริกซ์การหมุนทั้งสามก่อนที่จะนำไปใช้กับจุดสุดยอด ถ้า M, N, O เป็นเมทริกซ์การหมุนการดำเนินการผลลัพธ์คือ MNO v สิ่งที่ฉันเสนอคือใช้แต่ละเมทริกซ์แยกกัน: v1 = O v0 จากนั้น v2 = N v1 และสุดท้าย v3 = M v2 วิธีนี้แต่ละ vi จะอยู่ในพิกัดโลกและคุณเพียงแค่ต้องใช้เมทริกซ์การหมุนสำหรับแกนปัจจุบันในพิกัดโลกเช่นกัน
dsilva.vinicius

3
@ dsilva.vinicius การแปลงที่ถูกแยกของคุณจะเหมือนกับการรวมกันหรือนำไปอีกวิธีหนึ่ง: MNO v == M * (N * (O v))
GuyRT

คำตอบ:


1

จากความคิดเห็นของคุณดูเหมือนว่าคุณกำลังจัดเก็บการวางแนวของวัตถุเป็นชุดของมุมออยเลอร์และใน / ลดมุมเมื่อผู้เล่นหมุนวัตถุ นั่นคือคุณมีบางอย่างเช่นรหัสเทียมนี้:

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

ดังที่ Charles Beattie บันทึกเนื่องจากการหมุนไม่ได้ผลสิ่งนี้จะไม่ทำงานอย่างที่คาดไว้เว้นแต่ผู้เล่นจะหมุนวัตถุตามลำดับเดียวeulerAnglesToMatrix()กับที่การหมุนใช้

โดยเฉพาะอย่างยิ่งพิจารณาลำดับการหมุนต่อไปนี้:

  1. หมุนวัตถุด้วยxองศารอบแกน X
  2. หมุนวัตถุด้วยองศาyรอบแกน Y;
  3. หมุนวัตถุโดย - xองศารอบแกน X;
  4. หมุนวัตถุโดย - yองศารอบแกน Y

ในการแสดงมุม na angleve Euler ดังที่มีการใช้งานในรหัสเทียมข้างต้นการหมุนเหล่านี้จะยกเลิกและวัตถุจะกลับสู่การวางแนวดั้งเดิม ในโลกแห่งความเป็นจริงสิ่งนี้ไม่ได้เกิดขึ้น - ถ้าคุณไม่เชื่อฉันคว้าตัวหกเหลี่ยมหรือลูกบาศก์ของรูบิคให้x = y = 90 °แล้วลองด้วยตัวคุณเอง!

วิธีการแก้ปัญหาดังที่คุณจดบันทึกไว้ในคำตอบของคุณเองคือการเก็บการวางแนวของวัตถุเป็นเมทริกซ์การหมุน (หรือ quaternion) และอัพเดตเมทริกซ์นั้นตามการป้อนข้อมูลของผู้ใช้ นั่นคือแทนที่จะเป็น pseudocode ด้านบนคุณจะทำสิ่งนี้:

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

(ในทางเทคนิคเนื่องจากเมทริกซ์การหมุนหรือ quaternion ใด ๆ สามารถแสดงเป็นชุดของมุมออยเลอร์ได้มันเป็นไปได้ที่จะใช้มันเพื่อจัดเก็บการวางแนวของวัตถุ แต่กฎที่ถูกต้องทางร่างกายสำหรับการรวมการหมุนรอบสองครั้ง เป็นการหมุนครั้งเดียวค่อนข้างซับซ้อนและเป็นจำนวนมากโดยการแปลงการหมุนเป็นเมทริกซ์ / quaternions คูณพวกมันแล้วแปลงผลลัพธ์กลับเป็นมุมออยเลอร์)


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

15

ปัญหาเกี่ยวกับการหมุนคือคนส่วนใหญ่คิดในแง่ของมุมออยเลอร์เนื่องจากพวกเขาเข้าใจง่าย

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

นี่แปลโดยตรงเป็นเมทริกซ์เมื่อคุณคูณเมทริกซ์สองตัวคุณสามารถคิดถึงการคูณนี้เป็นการแปลงเมทริกซ์หนึ่งไปเป็นอวกาศของเมทริกซ์อื่น

สิ่งนี้มีขึ้นเพื่อให้เกิดขึ้นกับการหมุน 3 ครั้งตามลำดับแม้ในขณะที่ใช้ quaternions

ป้อนคำอธิบายรูปภาพที่นี่

ฉันต้องการที่จะเน้นความจริงที่ว่า quaternions ไม่ได้เป็นทางออกสำหรับล็อค gimble จริง ๆ แล้วล็อค gimble จะเกิดขึ้นถ้าคุณแสดงมุมออยเลอร์โดยใช้ quaternions ปัญหาไม่ได้เป็นตัวแทนที่เป็นปัญหา3 ขั้นตอนตามลำดับ

การแก้ไขปัญหา?

วิธีแก้ปัญหาสำหรับการหมุนเวกเตอร์รอบ 3 แกนอย่างอิสระคือการรวมกันเป็นแกนเดี่ยวและมุมเดียวด้วยวิธีนี้คุณสามารถกำจัดขั้นตอนที่คุณต้องทำการคูณตามลำดับ สิ่งนี้จะแปลเป็น:

เมทริกซ์การหมุนของฉันแสดงผลลัพธ์ของการหมุนรอบ X และ Y และ Z

มากกว่าการตีความของออยเลอร์

เมทริกซ์การหมุนของฉันแทนการหมุนรอบ X จากนั้น Y จากนั้น Z

เพื่อชี้แจงนี้ฉันจะอ้างอิงจากทฤษฎีบทการหมุนของวิกิพีเดียออยเลอร์:

ตามทฤษฎีการหมุนของออยเลอร์การหมุนหรือลำดับการหมุนของวัตถุแข็งหรือระบบพิกัดเกี่ยวกับจุดคงที่นั้นเทียบเท่ากับการหมุนเดี่ยวโดยมุมที่กำหนดθเกี่ยวกับแกนคงที่ (เรียกว่าแกนออยเลอร์) ที่ไหลผ่านจุดคงที่ โดยปกติแล้วแกนออยเลอร์จะถูกแทนด้วยเวกเตอร์หน่วย u → ดังนั้นการหมุนใด ๆ ในสามมิติสามารถแสดงเป็นการรวมกันของเวกเตอร์ u →และสเกลาร์θ Quaternions ให้วิธีง่าย ๆ ในการเข้ารหัสการแทนค่าแกน - มุมนี้ในตัวเลขสี่ตัวและใช้การหมุนที่สอดคล้องกันกับเวกเตอร์ตำแหน่งแทนจุดที่สัมพันธ์กับจุดกำเนิดใน R3

ขอให้สังเกตว่าคูณ 3 เมทริกซ์จะเสมอแทน 3 หมุนเวียนตามลำดับ

ตอนนี้เพื่อรวมการหมุนรอบ 3 แกนคุณต้องได้รับแกนเดี่ยวและมุมเดียวที่แสดงถึงการหมุนรอบ X, Y, Z กล่าวอีกนัยหนึ่งคุณต้องใช้การแสดง Axis / Angle หรือ quaternion เพื่อกำจัดการหมุนตามลำดับ

สิ่งนี้มักจะทำโดยเริ่มต้นด้วยการวางแนวเริ่มต้น (การวางแนวสามารถคิดว่าเป็นมุมแกน) โดยปกติจะแสดงเป็นมุมสี่ส่วนหรือมุมแกน ตัวอย่างเช่นคุณเริ่มต้นด้วยการสอบถามข้อมูลประจำตัวแล้วหมุนตามความแตกต่างเพื่อไปยังทิศทางปฐมนิเทศ ด้วยวิธีนี้คุณจะไม่สูญเสียอิสรภาพใด ๆ


ทำเครื่องหมายว่าเป็นคำตอบตามที่เห็นได้ชัด
Syntac_

ฉันมีปัญหาในการหาสิ่งที่คุณพยายามจะพูดด้วยคำตอบนี้ มันเป็นเพียง "ไม่เก็บการวางแนวของวัตถุเป็นมุมออยเลอร์"? และถ้าเป็นเช่นนั้นทำไมไม่เพียงแค่พูดอย่างนั้น?
Ilmari Karonen

@IlmariKaronen มันอาจจะระบุไว้อย่างชัดเจนมากขึ้น แต่ฉันคิดว่า concept3d กำลังส่งเสริมการเป็นตัวแทนมุมแกน ดูหัวข้อ 1.2.2 ของเอกสารนี้สำหรับความสัมพันธ์ระหว่างมุมของแกนและควอเทอร์เนียน การเป็นตัวแทนมุมแกนนั้นง่ายต่อการติดตั้งด้วยเหตุผลข้างต้นมันไม่ได้เกิดจาก gimbal-lock และ (สำหรับฉันอย่างน้อย) มันเป็นเรื่องง่ายที่จะเข้าใจเช่นเดียวกับมุมของออยเลอร์
NauticalMile

@ concept3d มันน่าสนใจมากและฉันชอบคำตอบของคุณ มีสิ่งหนึ่งที่ขาดหายไปสำหรับฉัน แต่ผู้คนมีปฏิสัมพันธ์กับคอมพิวเตอร์โดยใช้แป้นพิมพ์และเมาส์ถ้าเรานึกถึงเมาส์เราจะพูดถึง x และ y deltas ของเมาส์ วิธีแสดง x, y deltas เหล่านี้ด้วยควอเทเรียนเดียวที่เราสามารถใช้ในการสร้างเมทริกซ์การหมุนตัวอย่างเช่นเปลี่ยนการวางแนววัตถุ
gmagno

@ gmagno วิธีการมักจะฉายการเคลื่อนที่ของเมาส์บนวัตถุหรือฉากและคำนวณ deltas ในพื้นที่นั้นคุณทำได้โดยการฉายรังสีและคำนวณจุดตัด ค้นหาการคัดเลือกเรย์โปรเจคและการโปรเจ็กต์ฉันหยาบในรายละเอียดเพราะฉันไม่ได้ทำงานกับ CG มาหลายปีแล้ว หวังว่าจะช่วย
concept3d

2

การสลับการหมุนของการหมุนจากพื้นที่วัตถุไปสู่อวกาศโลกนั้นไม่สำคัญ: คุณเพียงแค่ย้อนกลับลำดับที่การหมุนจะถูกนำไปใช้

ในกรณีของคุณแทนการคูณเมทริกซ์Z × X × Y, Y × X × Zคุณเพียงแค่ต้องคำนวณ

เหตุผลสำหรับการนี้สามารถพบได้ในวิกิพีเดีย: การแปลงระหว่างหมุนเวียนภายในและภายนอก


หากเป็นจริงแล้วข้อความต่อไปนี้จากแหล่งที่มาของคุณจะไม่เป็นจริงเนื่องจากการหมุนจะแตกต่างกัน: "การหมุนภายนอกใด ๆ จะเทียบเท่ากับการหมุนที่แท้จริงภายในมุมเดียวกัน แต่มีลำดับการหมุนขององค์ประกอบแบบกลับด้าน ."
Syntac_

1
ฉันไม่เห็นความขัดแย้งที่นี่ ทั้งคำตอบของฉันและข้อความนั้นเป็นจริง และใช่การหมุนเวียนในพื้นที่วัตถุและในพื้นที่โลกให้ผลัดที่แตกต่างกัน นั่นเป็นประเด็นที่ถูกต้องใช่ไหม
sam hocevar

ข้อความนั้นบอกว่าการเปลี่ยนคำสั่งจะส่งผลให้เกิดการหมุนเดียวกัน หากคำสั่งซื้อหนึ่งก่อให้เกิดการหมุนที่ไม่ถูกต้องคำสั่งอื่น ๆ ก็จะหมายถึงมันไม่ใช่วิธีแก้ปัญหา
Syntac_

1
คุณกำลังอ่านผิด การเปลี่ยนคำสั่งไม่ส่งผลให้เกิดการหมุนเดียวกัน การเปลี่ยนลำดับและการสลับจากการหมุนภายในเพื่อการหมุนรอบนอกจะส่งผลในการหมุนเดียวกัน
sam hocevar

1
ฉันไม่คิดว่าฉันเข้าใจคำถามของคุณ GIF ของคุณแสดงการหมุนประมาณ 50 องศารอบ ๆZ(พื้นที่วัตถุ), 50 องศารอบX(พื้นที่วัตถุ) และ 45 องศารอบY(พื้นที่วัตถุ) สิ่งนี้เหมือนกับการหมุน 45 องศารอบ ๆY( พื้นที่โลก ) และ 50 องศารอบX( อวกาศโลก ) และ 50 องศารอบZ( อวกาศโลก )
sam hocevar

1

ฉันจะให้คำตอบเพื่อเป็นคำตอบจนกว่าจะมีใครสามารถอธิบายได้ว่าทำไมงานนี้

ทุกการเรนเดอร์ฉันกำลังสร้าง quaternion ขึ้นใหม่โดยใช้มุมที่เก็บไว้ในเวคเตอร์การหมุนของฉัน

อย่างไรก็ตามเพื่อที่จะเก็บไว้รอบแกนโลกฉันต้องรักษา quaternion ในทุกเฟรมและหมุนวัตถุโดยใช้ความแตกต่างในมุมเช่น ..

// 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 สำหรับความพร้อม)

ฉันคิดว่า dsilva.vinicius พยายามไปถึงจุดนี้


1

คุณจะต้องเก็บคำสั่งของการหมุน

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

เก็บเมทริกซ์การหมุนปัจจุบันของคุณและหมุนแต่ละรอบก่อนการหมุนทุกครั้ง


0

นอกจากคำตอบ @ concept3d คุณสามารถใช้เมทริกซ์การหมุนภายนอก 3 ตัวเพื่อหมุนรอบแกนในพิกัดโลก ข้อความจากWikipedia :

Extrinsic rotations คือการหมุนแบบองค์ประกอบที่เกิดขึ้นเกี่ยวกับแกนของระบบพิกัดคงที่ xyz ระบบ XYZ หมุนขณะที่ xyz ได้รับการแก้ไข เริ่มต้นด้วย XYZ ที่ทับซ้อนกัน xyz องค์ประกอบของการหมุนภายนอกที่สามสามารถใช้เพื่อเข้าถึงการวางแนวเป้าหมายใด ๆ สำหรับ XYZ มุมออยเลอร์หรือ Tait Bryan (α, β, γ) คือแอมพลิจูดของการหมุนขององค์ประกอบเหล่านี้ ตัวอย่างเช่นการวางแนวเป้าหมายสามารถเข้าถึงได้ดังนี้:

ระบบ XYZ หมุนรอบแกน z ด้วยα ตอนนี้แกน X อยู่ที่มุมαเทียบกับแกน x

ระบบ XYZ หมุนอีกครั้งเกี่ยวกับแกน x ด้วยβ ตอนนี้แกน Z อยู่ในมุมβเทียบกับแกน z

ระบบ XYZ หมุนครั้งที่สามเกี่ยวกับแกน z ด้วยγ

เมทริกซ์การหมุนสามารถใช้เพื่อแสดงลำดับการหมุนภายนอก ตัวอย่างเช่น

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

แสดงให้เห็นถึงองค์ประกอบของการหมุนภายนอกเกี่ยวกับแกน xyz ถ้าใช้ในการคูณเวกเตอร์คอลัมน์ก่อนในขณะที่

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

แสดงถึงองค์ประกอบเดียวกันทุกประการเมื่อใช้กับเวกเตอร์แถวหลังคูณ

ดังนั้นสิ่งที่คุณต้องการคือการกลับลำดับของการหมุนที่สัมพันธ์กับสิ่งที่คุณจะทำโดยใช้การหมุนที่แท้จริง @Syntac ขอการหมุน zxy ดังนั้นเราควรทำการหมุน yxz extrinsic เพื่อให้ได้ผลลัพธ์เดียวกัน รหัสด้านล่าง:

เมทริกซ์ค่าคำอธิบายที่นี่

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

รหัสนี้เป็นแบบสอนไม่เหมาะเพราะคุณสามารถใช้เมทริกซ์ D3DXMATRIX หลายซ้ำได้


1
ขออภัยที่คนนี้ไม่ถูกต้อง การคูณเมทริกซ์ / เวกเตอร์เป็นความสัมพันธ์ นี่เหมือนกับการคูณเมทริกซ์รวมกัน
concept3d

คุณพูดถูก ฉันได้ผสมผสานแนวคิดของการหมุนภายนอกและภายใน
dsilva.vinicius

ฉันจะแก้ไขคำตอบนี้
dsilva.vinicius

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