ฉันพยายามให้ผู้ใช้แอปหมุนวัตถุ 3 มิติที่กึ่งกลางหน้าจอโดยลากนิ้วบนหน้าจอ การเคลื่อนไหวในแนวนอนบนหน้าจอหมายถึงการหมุนรอบแกน Y ที่คงที่และการเคลื่อนที่ในแนวตั้งหมายถึงการหมุนรอบแกน X ปัญหาที่ฉันมีคือถ้าฉันอนุญาตให้หมุนรอบหนึ่งแกนวัตถุจะหมุนได้ดี แต่ทันทีที่ฉันแนะนำการหมุนครั้งที่สองวัตถุจะไม่หมุนตามที่คาดไว้
นี่คือภาพของสิ่งที่เกิดขึ้น:

แกนสีน้ำเงินแสดงถึงแกนคงที่ของฉัน รูปภาพหน้าจอที่มีแกนสีน้ำเงินคงที่นี้ นี่คือสิ่งที่ฉันต้องการให้วัตถุหมุนในความสัมพันธ์กับ สิ่งที่เกิดขึ้นคือสีแดง
นี่คือสิ่งที่ฉันรู้:
- การหมุนรอบแรกรอบ Y (0, 1, 0) ทำให้โมเดลย้ายจากพื้นที่สีน้ำเงิน (เรียกพื้นที่นี้ A) ไปยังพื้นที่อื่น (เรียกพื้นที่นี้ B)
 - พยายามหมุนอีกครั้งโดยใช้เวกเตอร์ (1, 0, 0) หมุนรอบแกน x ในอวกาศ B ไม่ได้อยู่ในอวกาศ A ซึ่งไม่ใช่สิ่งที่ฉันตั้งใจจะทำ
 
นี่คือสิ่งที่ฉันพยายามให้ในสิ่งที่ฉัน (คิด) ฉันรู้ (ออกจาก coord W เพราะความกะทัดรัด):
- หมุนไปรอบ ๆ Y (0, 1, 0) โดยใช้ Quaternion
 - แปลงการหมุน Y Quaternion เป็นเมทริกซ์
 - คูณเมทริกซ์การหมุน Y ด้วยแกนคงที่ x เวกเตอร์ (1, 0, 0) เพื่อให้ได้แกน X สัมพันธ์กับพื้นที่ใหม่
 - หมุน X เวกเตอร์ใหม่โดยใช้ Quaternion
 
นี่คือรหัส:
private float[] rotationMatrix() {
    final float[] xAxis = {1f, 0f, 0f, 1f};
    final float[] yAxis = {0f, 1f, 0f, 1f};
    float[] rotationY = Quaternion.fromAxisAngle(yAxis, -angleX).toMatrix();
    // multiply x axis by rotationY to put it in object space
    float[] xAxisObjectSpace = new float[4];
    multiplyMV(xAxisObjectSpace, 0, rotationY, 0, xAxis, 0);
    float[] rotationX = Quaternion.fromAxisAngle(xAxisObjectSpace, -angleY).toMatrix();
    float[] rotationMatrix = new float[16];
    multiplyMM(rotationMatrix, 0, rotationY, 0, rotationX, 0);
    return rotationMatrix;
  }
นี่ไม่ทำงานอย่างที่ฉันคาดไว้ การหมุนดูเหมือนจะทำงานได้ แต่ในบางจุดการเคลื่อนที่ในแนวนอนไม่ได้หมุนรอบแกน Y มันจะหมุนรอบแกน Z
ฉันไม่แน่ใจว่าความเข้าใจของฉันผิดหรืออย่างอื่นทำให้เกิดปัญหาหรือไม่ ฉันมีการแปลงอื่น ๆ ที่ฉันทำกับวัตถุนอกเหนือจากการหมุน ฉันย้ายวัตถุไปที่กึ่งกลางก่อนที่จะใช้การหมุน ฉันหมุนมันโดยใช้เมทริกซ์ที่คืนมาจากฟังก์ชั่นด้านบนของฉันจากนั้นฉันก็แปลมัน -2 ในทิศทาง Z เพื่อให้ฉันเห็นวัตถุ ฉันไม่คิดว่านี่จะทำให้การหมุนเวียนของฉันยุ่ง แต่นี่คือรหัสสำหรับสิ่งนั้น:
private float[] getMvpMatrix() {
    // translates the object to where we can see it
    final float[] translationMatrix = new float[16];
    setIdentityM(translationMatrix, 0);
    translateM(translationMatrix, 0, translationMatrix, 0, 0f, 0f, -2);
    float[] rotationMatrix = rotationMatrix();
    // centers the object
    final float[] centeringMatrix = new float[16];
    setIdentityM(centeringMatrix, 0);
    float moveX = (extents.max[0] + extents.min[0]) / 2f;
    float moveY = (extents.max[1] + extents.min[1]) / 2f;
    float moveZ = (extents.max[2] + extents.min[2]) / 2f;
    translateM(centeringMatrix, 0, //
      -moveX, //
      -moveY, //
      -moveZ //
    );
    // apply the translations/rotations
    final float[] modelMatrix = new float[16];
    multiplyMM(modelMatrix, 0, translationMatrix, 0, rotationMatrix, 0);
    multiplyMM(modelMatrix, 0, modelMatrix, 0, centeringMatrix, 0);
    final float[] mvpMatrix = new float[16];
    multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelMatrix, 0);
    return mvpMatrix;
  }
ฉันติดอยู่กับเรื่องนี้สองสามวัน ช่วยชื่นชมมาก
================================================== ================
UPDATE:
การทำให้สิ่งนี้ทำงานใน Unity นั้นตรงไปตรงมา นี่คือรหัสบางส่วนที่หมุนลูกบาศก์เป็นศูนย์กลางที่จุดกำเนิด:
public class CubeController : MonoBehaviour {
    Vector3 xAxis = new Vector3 (1f, 0f, 0f);
    Vector3 yAxis = new Vector3 (0f, 1f, 0f);
    // Update is called once per frame
    void FixedUpdate () {
        float horizontal = Input.GetAxis ("Horizontal");
        float vertical = Input.GetAxis ("Vertical");
        transform.Rotate (xAxis, vertical, Space.World);
        transform.Rotate (yAxis, -horizontal, Space.World);
    }
}
ส่วนที่ทำให้การหมุนทำงานตามที่ฉันคาดไว้คือSpace.Worldพารามิเตอร์ของRotateฟังก์ชันในการแปลง
ถ้าฉันสามารถใช้ Unity ได้ฉันก็ต้องใช้รหัสพฤติกรรมนี้ด้วยตัวเอง