ไม่มีสิ่งนี้ไม่ใช่ข้อผิดพลาดของเครื่องยนต์หรือสิ่งประดิษฐ์ที่แสดงถึงการหมุนเฉพาะ (สิ่งเหล่านั้นสามารถเกิดขึ้นได้เช่นกัน แต่เอฟเฟกต์นี้ใช้ได้กับทุกระบบที่แสดงถึงการหมุน
คุณได้ค้นพบข้อเท็จจริงที่แท้จริงเกี่ยวกับการหมุนในพื้นที่สามมิติและมันออกจากสัญชาตญาณของเราเกี่ยวกับการเปลี่ยนแปลงอื่น ๆ เช่นการแปล:
เมื่อเราเขียนการหมุนบนแกนมากกว่าหนึ่งแกนผลลัพธ์ที่เราได้รับไม่ได้เป็นเพียงมูลค่ารวม / สุทธิที่เราใช้กับแต่ละแกน (ตามที่เราคาดหวังสำหรับการแปล) ลำดับที่เราใช้การหมุนจะเปลี่ยนผลลัพธ์เมื่อการหมุนแต่ละครั้งเคลื่อนที่แกนที่การหมุนครั้งถัดไปใช้ (ถ้าหมุนรอบแกนท้องถิ่นของวัตถุ) หรือความสัมพันธ์ระหว่างวัตถุกับแกน (ถ้าหมุนรอบโลก แกน)
การเปลี่ยนความสัมพันธ์ของแกนในช่วงเวลาหนึ่งอาจทำให้สัญชาตญาณของเราสับสนเกี่ยวกับสิ่งที่แต่ละ "แกน" ควรทำ โดยเฉพาะอย่างยิ่งการรวมกันของการหันเหและหันเหระดับเสียงให้ผลเช่นเดียวกับการหมุนม้วน!
คุณสามารถตรวจสอบได้ว่าแต่ละขั้นตอนมีการหมุนอย่างถูกต้องเกี่ยวกับแกนที่เราร้องขอ - ไม่มีความผิดพลาดของเครื่องยนต์หรือสิ่งประดิษฐ์ในสัญกรณ์ของเรารบกวนหรือคาดเดาอินพุตของเรา - ลักษณะการหมุนของทรงกลม (หรือ hyperspherical รอบ "สู่กัน พวกเขาอาจจะตั้งฉากในพื้นที่สำหรับการหมุนเล็ก ๆ แต่เมื่อพวกเขาซ้อนเราพบว่าพวกเขาไม่ได้เป็นมุมฉากทั่วโลก
นี่เป็นสิ่งที่น่าทึ่งและชัดเจนสำหรับการหมุน 90 องศาเช่นเดียวกับที่กล่าวมาข้างต้น แต่แกนที่หลงทางนั้นคืบคลานไปในการหมุนเล็ก ๆ หลายครั้งเช่นกันตามที่แสดงในคำถาม
แล้วเราจะทำอย่างไรกับมัน
หากคุณมีระบบการหมุนระยะพิทซ์แล้ววิธีที่เร็วที่สุดวิธีหนึ่งในการกำจัดการม้วนที่ไม่ต้องการคือการเปลี่ยนการหมุนแบบใดแบบหนึ่งเพื่อให้ทำงานบนแกนการเปลี่ยนแปลงทั่วโลกหรือแกนหลักแทนแกนท้องถิ่นของวัตถุ ด้วยวิธีนี้คุณจะไม่ได้รับการปนเปื้อนข้ามระหว่างสองแกน - แกนเดียวยังคงถูกควบคุมอย่างสมบูรณ์
นี่คือลำดับเดียวกันของ pitch-yaw-pitch ที่กลายเป็นม้วนในตัวอย่างข้างต้น แต่ตอนนี้เราใช้การหันเหของเรารอบแกน Y ทั่วโลกแทนวัตถุ
ดังนั้นเราจึงสามารถแก้ไขกล้องคนแรกด้วยมนต์ "Pitch Locally, Yaw Globally":
void Update() {
float speed = lookSpeed * Time.deltaTime;
transform.Rotate(0f, Input.GetAxis("Horizontal") * speed, 0f, Space.World);
transform.Rotate(-Input.GetAxis("Vertical") * speed, 0f, 0f, Space.Self);
}
หากคุณกำลังรวมการหมุนของคุณโดยใช้การคูณคุณจะต้องสลับลำดับซ้าย / ขวาของการคูณอย่างใดอย่างหนึ่งเพื่อให้ได้เอฟเฟกต์เดียวกัน:
// Yaw happens "over" the current rotation, in global coordinates.
Quaternion yaw = Quaternion.Euler(0f, Input.GetAxis("Horizontal") * speed, 0f);
transform.rotation = yaw * transform.rotation; // yaw on the left.
// Pitch happens "under" the current rotation, in local coordinates.
Quaternion pitch = Quaternion.Euler(-Input.GetAxis("Vertical") * speed, 0f, 0f);
transform.rotation = transform.rotation * pitch; // pitch on the right.
(คำสั่งซื้อที่เฉพาะเจาะจงจะขึ้นอยู่กับอนุสัญญาการคูณในสภาพแวดล้อมของคุณ แต่เหลือ = มากขึ้นทั่วโลก / ขวา = มากขึ้นในท้องถิ่นเป็นตัวเลือกที่พบบ่อย)
สิ่งนี้เทียบเท่ากับการจัดเก็บ yaw สุทธิทั้งหมดและ pitch ทั้งหมดที่คุณต้องการเป็นตัวแปร float จากนั้นใช้ผลลัพธ์สุทธิทั้งหมดในครั้งเดียวสร้าง quaternion ปฐมนิเทศหรือเมทริกซ์ใหม่จากมุมเหล่านี้เพียงอย่างเดียว (ให้คุณtotalPitch
ยึดไว้):
// Construct a new orientation quaternion or matrix from Euler/Tait-Bryan angles.
var newRotation = Quaternion.Euler(totalPitch, totalYaw, 0f);
// Apply it to our object.
transform.rotation = newRotation;
หรือเทียบเท่า ...
// Form a view vector using total pitch & yaw as spherical coordinates.
Vector3 forward = new Vector3(
Mathf.cos(totalPitch) * Mathf.sin(totalYaw),
Mathf.sin(totalPitch),
Mathf.cos(totalPitch) * Mathf.cos(totalYaw));
// Construct an orientation or view matrix pointing in that direction.
var newRotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0));
// Apply it to our object.
transform.rotation = newRotation;
การใช้การแยกแบบโกลบอล / โลคอลนี้การหมุนจะไม่มีโอกาสประสมและมีอิทธิพลต่อกันและกันเพราะมันถูกใช้กับแกนอิสระ
แนวคิดเดียวกันสามารถช่วยได้หากเป็นวัตถุในโลกที่เราต้องการหมุน สำหรับตัวอย่างเช่นโลกเรามักจะต้องการที่จะกลับด้านและใช้การหันเหของเราในพื้นที่ (ดังนั้นมันหมุนรอบเสาของมันเสมอ) และขว้างไปทั่วโลก (เพื่อให้มันเคล็ดลับไป / ออกจากมุมมองของเรามากกว่าไป / ออกจากออสเตรเลีย ทุกที่ที่มันชี้ ... )
ข้อ จำกัด
กลยุทธ์ไฮบริดทั่วโลก / ท้องถิ่นนี้ไม่ได้แก้ไขที่ถูกต้องเสมอไป ตัวอย่างเช่นในเกมที่มีเที่ยวบิน 3 มิติ / ว่ายน้ำคุณอาจต้องการชี้ตรงขึ้น / ลงและยังคงควบคุมได้เต็มที่ แต่ด้วยการตั้งค่านี้คุณจะได้รับการล็อคด้วย gimbalแกน yaw ของคุณ (ทั่วโลกขึ้นไป) จะขนานกับแกนม้วนของคุณ (ไปข้างหน้าในพื้นที่) และคุณไม่มีทางที่จะมองไปทางซ้ายหรือขวาโดยไม่ต้องบิด
สิ่งที่คุณสามารถทำได้แทนในกรณีเช่นนี้คือใช้การหมุนรอบตัวแบบบริสุทธิ์อย่างที่เราเริ่มต้นด้วยคำถามข้างต้น (ดังนั้นการควบคุมของคุณจะรู้สึกเหมือนกันไม่ว่าคุณจะมองที่ไหน) ซึ่งในขั้นต้นจะทำให้ม้วนเข้ามา - เราแก้ไขให้ถูกต้อง
ตัวอย่างเช่นเราสามารถใช้การหมุนเฉพาะที่เพื่ออัปเดตเวกเตอร์ "ไปข้างหน้า" ของเราจากนั้นใช้เวกเตอร์ไปข้างหน้าพร้อมกับการอ้างอิง "up" เวกเตอร์เพื่อสร้างการวางแนวสุดท้ายของเรา (ตัวอย่างเช่นการใช้วิธีQuaternion.LookRotationของ Unity หรือสร้างเมทริกซ์ orthonormal จากเวกเตอร์เหล่านี้ด้วยตนเอง) โดยการควบคุมเวกเตอร์อัพเราควบคุมม้วนหรือบิด
สำหรับตัวอย่างเที่ยวบิน / ว่ายน้ำคุณจะต้องใช้การแก้ไขเหล่านี้อย่างค่อยเป็นค่อยไปเมื่อเวลาผ่านไป ถ้ามันฉับพลันเกินไปมุมมองสามารถเย้ยหยันในทางที่เบี่ยงเบน แต่คุณสามารถใช้เวกเตอร์อัพปัจจุบันของผู้เล่นและบอกใบ้ไปทางแนวตั้งทีละเฟรมจนกระทั่งมุมมองของพวกเขาออกมา การใช้สิ่งนี้ในบางครั้งอาจทำให้เกิดความรำคาญน้อยกว่าการบิดกล้องในขณะที่การควบคุมของผู้เล่นไม่ได้ทำงาน