มีมากกว่าหนึ่งวิธีที่จะทำ คุณสามารถคำนวณการวางแนวสัมบูรณ์หรือการหมุนสัมพัทธ์กับอวาตาร์ของคุณซึ่งหมายถึงการวางแนวใหม่ของคุณ = avatarOrientation * q นี่คือหนึ่งหลัง:
คำนวณแกนการหมุนโดยการใช้ครอสโปรดัคของเวกเตอร์ไปข้างหน้าของอวาตาร์ของคุณและเวกเตอร์ของหน่วยจากอวาตาร์ไปยังเป้าหมาย
vector newForwardUnit = vector::normalize(target - avatarPosition);
vector rotAxis = vector::cross(avatarForwardUnit, newForwardUnit);
คำนวณมุมการหมุนโดยใช้ดอทโปรดัค
float rotAngle = acos(vector::dot(avatarForwardUnit, newForwardUnit));
สร้าง quaternion โดยใช้ rotAxis และ rotAngle แล้วคูณด้วยการวางแนวปัจจุบันของอวตาร
quaternion q(rotAxis, rotAngle);
quaternion newRot = avatarRot * q;
หากคุณต้องการความช่วยเหลือในการค้นหาเวกเตอร์ไปข้างหน้าปัจจุบันของอวตารอินพุตสำหรับ 1 เพียงแค่ยิง :)
แก้ไข:การคำนวณการวางแนวแบบสัมบูรณ์นั้นง่ายกว่าจริง ๆ ให้ใช้เวกเตอร์ไปข้างหน้าของ identity-matrix แทนที่จะเป็นเวกเตอร์ไปข้างหน้ารูปแทนตัวสำหรับ 1) และ 2) และอย่าคูณใน 3) แทนที่จะใช้โดยตรงเป็นทิศทางใหม่:newRot = q
สิ่งสำคัญที่ควรทราบ:วิธีการแก้ปัญหามี 2 ความผิดปกติที่เกิดจากธรรมชาติของผลิตภัณฑ์ข้าม:
ถ้าเวกเตอร์ไปข้างหน้าเท่ากัน วิธีแก้ปัญหาที่นี่ก็แค่ส่งคืนควอเทอร์เนชันเฉพาะตัว
หากเวกเตอร์ชี้ไปในทิศทางตรงกันข้าม วิธีแก้ปัญหาที่นี่คือการสร้างควอเทอเนียนโดยใช้อวตารขึ้นแกนเป็นแกนหมุนและมุม 180.0 องศา
นี่คือการดำเนินการใน C ++ ที่ดูแลกรณีขอบเหล่านั้น การแปลงเป็น C # ควรเป็นเรื่องง่าย
// returns a quaternion that rotates vector a to vector b
quaternion get_rotation(const vector &a, const vector &b, const vector &up)
{
ASSERT_VECTOR_NORMALIZED(a);
ASSERT_VECTOR_NORMALIZED(b);
float dot = vector::dot(a, b);
// test for dot -1
if(nearly_equal_eps_f(dot, -1.0f, 0.000001f))
{
// vector a and b point exactly in the opposite direction,
// so it is a 180 degrees turn around the up-axis
return quaternion(up, gdeg2rad(180.0f));
}
// test for dot 1
else if(nearly_equal_eps_f(dot, 1.0f, 0.000001f))
{
// vector a and b point exactly in the same direction
// so we return the identity quaternion
return quaternion(0.0f, 0.0f, 0.0f, 1.0f);
}
float rotAngle = acos(dot);
vector rotAxis = vector::cross(a, b);
rotAxis = vector::normalize(rotAxis);
return quaternion(rotAxis, rotAngle);
}
แก้ไข:แก้ไขรหัส XNA ของ Marc
// the new forward vector, so the avatar faces the target
Vector3 newForward = Vector3.Normalize(Position - GameState.Avatar.Position);
// calc the rotation so the avatar faces the target
Rotation = Helpers.GetRotation(Vector3.Forward, newForward, Vector3.Up);
Cannon.Shoot(Position, Rotation, this);
public static Quaternion GetRotation(Vector3 source, Vector3 dest, Vector3 up)
{
float dot = Vector3.Dot(source, dest);
if (Math.Abs(dot - (-1.0f)) < 0.000001f)
{
// vector a and b point exactly in the opposite direction,
// so it is a 180 degrees turn around the up-axis
return new Quaternion(up, MathHelper.ToRadians(180.0f));
}
if (Math.Abs(dot - (1.0f)) < 0.000001f)
{
// vector a and b point exactly in the same direction
// so we return the identity quaternion
return Quaternion.Identity;
}
float rotAngle = (float)Math.Acos(dot);
Vector3 rotAxis = Vector3.Cross(source, dest);
rotAxis = Vector3.Normalize(rotAxis);
return Quaternion.CreateFromAxisAngle(rotAxis, rotAngle);
}
0*(rotation A) + 1*(rotation B)
- ในคำอื่น ๆ คุณกำลังตั้งค่าการหมุนเป็นการหมุน B ทางยาว Slerp มีไว้สำหรับพิจารณาว่าการหมุนควรมีลักษณะอย่างไร (0% <x <100%) ของวิธีการในระหว่างนั้น