Xoay đối tượng quanh trục cố định


12

Tôi đang cố gắng để người dùng ứng dụng của mình xoay một vật thể 3D được vẽ ở giữa màn hình bằng cách kéo ngón tay của họ trên màn hình. Chuyển động ngang trên màn hình có nghĩa là xoay quanh trục Y cố định và chuyển động dọc có nghĩa là xoay quanh trục X. Vấn đề tôi gặp phải là nếu tôi chỉ cho phép xoay quanh một trục thì đối tượng sẽ quay tốt, nhưng ngay khi tôi giới thiệu một vòng quay thứ hai thì đối tượng không quay như mong đợi.

Dưới đây là hình ảnh về những gì đang xảy ra:

nhập mô tả hình ảnh ở đây

Trục màu xanh đại diện cho trục cố định của tôi. Hình ảnh màn hình có trục màu xanh cố định này. Đây là những gì tôi muốn đối tượng xoay liên quan đến. Những gì đang xảy ra là màu đỏ.

Đây là những gì tôi biết:

  1. Vòng xoay đầu tiên quanh Y (0, 1, 0) làm cho mô hình di chuyển từ không gian màu xanh lam (gọi không gian này là A) sang không gian khác (gọi không gian này là B)
  2. Cố gắng xoay một lần nữa bằng vectơ (1, 0, 0) xoay quanh trục x trong không gian B KHÔNG trong không gian A không phải là điều tôi muốn làm.

Đây là những gì tôi đã thử, đưa ra những gì tôi (nghĩ) mà tôi biết (bỏ qua tọa độ W cho ngắn gọn):

  1. Đầu tiên xoay quanh Y (0, 1, 0) bằng cách sử dụng Quancyion.
  2. Chuyển đổi phép quay Y Quancyion thành Ma trận.
  3. Nhân ma trận xoay Y với trục cố định của tôi x Vector (1, 0, 0) để có trục X liên quan đến không gian mới.
  4. Xoay quanh X Vector mới này bằng cách sử dụng Quancyion.

Đây là mã:

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

Điều này không hoạt động như tôi mong đợi. Xoay dường như hoạt động, nhưng tại một số điểm chuyển động ngang không xoay quanh trục Y, nó dường như xoay quanh trục Z.

Tôi không chắc liệu sự hiểu biết của tôi là sai hay nếu điều gì khác gây ra vấn đề. Tôi có một số biến đổi khác mà tôi đang làm với đối tượng ngoài xoay vòng. Tôi di chuyển đối tượng đến trung tâm trước khi áp dụng xoay vòng. Tôi xoay nó bằng cách sử dụng ma trận trả về từ hàm của tôi ở trên, sau đó tôi dịch nó -2 theo hướng Z để tôi có thể nhìn thấy đối tượng. Tôi không nghĩ rằng điều này đang làm rối tung các vòng quay của tôi, nhưng đây là mã cho dù sao đi nữa:

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

Tôi đã bị mắc kẹt trong vài ngày. Giúp đỡ được nhiều đánh giá cao.

================================================== ================

CẬP NHẬT:

Làm cho điều này để làm việc trong Unity là đơn giản. Đây là một số mã xoay một khối lập phương ở giữa:

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

Phần làm cho các phép quay hoạt động như tôi mong đợi là Space.Worldtham số cho Rotatehàm trên biến đổi.

Nếu tôi có thể sử dụng Unity, tôi sẽ không may tự mình viết mã cho hành vi này.


1
Câu trả lời của tôi ở đây gamedev.stackexchange.com/questions/67199/ có thể giúp bạn ..
concept3d

Tôi hiểu khái niệm đằng sau câu trả lời của bạn, nhưng làm thế nào để thực hiện là thoát khỏi tôi.
Christopher Perry

Nếu bạn kiểm tra các câu trả lời khác, câu trả lời cú pháp sẽ thực hiện ý tưởng mà tôi đã giải thích.
Concept3d

Không, không, nó đang thực hiện nhiều vòng quay về các trục khác nhau. Bạn đề nghị thực hiện một vòng quay duy nhất.
Christopher Perry

Câu trả lời:


3

Vấn đề bạn gặp phải được gọi là khóa gimble . Tôi nghĩ những gì bạn muốn làm được gọi là xoay vòng cung . Toán học cho arcball có thể là abit phức tạp.

Một cách đơn giản hơn để làm điều đó là tìm một vectơ 2d vuông góc với thao tác vuốt 2d trên màn hình.

Lấy vector và chiếu nó lên camera gần mặt phẳng để có được vector 3d trong không gian thế giới. Không gian màn hình đến không gian thế giới .

Sau đó tạo một quernion với vector này và nhân nó với gameobject. Có lẽ với một số chuyển tiếp slurp hoặc lerp.

Biên tập:

Ví dụ về sự thống nhất: Trong ví dụ về sự thống nhất, trạng thái bên trong của phép quay trò chơi là một quan điểm không phải là một ma trận. Phương thức biến đổi.rotation tạo ra một bậc bốn dựa trên vectơ và góc được cung cấp và nhân bội số đó với bậc bốn xoay vòng trò chơi. Nó chỉ tạo ra ma trận xoay để kết xuất hoặc vật lý tại một điểm sau đó. Đệ tứ là phụ gia và tránh khóa gimble.

Mã của bạn sẽ trông giống như thế này:

private float[] rotationMatrix() {

    final float[] xAxis = {1f, 0f, 0f, 1f};
    final float[] yAxis = {0f, 1f, 0f, 1f};

    Quaternion qY = Quaternion.fromAxisAngle(yAxis, angleX);
    Quaternion qX = Quaternion.fromAxisAngle(xAxis, -angleY);

    return (qX * qY).getMatrix(); // should probably represent the gameobjects rotation as a quaternion(not a matrix) and multiply all 3 quaternions before generating the matrix. 
  }

Hướng dẫn Opengl ArcBall Rotation


Tôi không nhận được khóa gimbal, vòng quay thứ nhất di chuyển trục nên vòng quay thứ hai dựa trên trục đã di chuyển. Xin vui lòng có một cái nhìn thứ hai vào hình ảnh tôi cung cấp.
Christopher Perry

Tôi hy vọng bạn tìm ra nó. Nói ngắn gọn. Đệ tứ có thể được nhân với nhau để áp dụng xoay vòng. Bạn chỉ nên tạo ma trận ở cuối tất cả các tính toán xoay vòng. Ngoài ra xQ * yQ không bằng yQ * xQ. Đệ tứ không giao hoán như Christopher Perry nói.
Anthony Raimondo

Tôi đặt TẤT CẢ mã của tôi ở đây . Tôi cảm thấy như tôi đã thử mọi thứ. Có lẽ đôi mắt của người khác về điều này sẽ bắt lỗi của tôi.
Christopher Perry

Tôi đã không chấp nhận nó, thuật toán trao đổi ngăn xếp tự động gán điểm cho bạn. : /
Christopher Perry

Tôi xin lỗi vì sự bất công này.
Anthony Raimondo

3

Tôi đã có thể có được các phép quay dự kiến ​​bằng cách xoay một ma trận xoay tích lũy.

setIdentityM(currentRotation, 0);
rotateM(currentRotation, 0, angleY, 0, 1, 0);
rotateM(currentRotation, 0, angleX, 1, 0, 0);

// Multiply the current rotation by the accumulated rotation,
// and then set the accumulated rotation to the result.
multiplyMM(temporaryMatrix, 0, currentRotation, 0, accumulatedRotation, 0);
arraycopy(temporaryMatrix, 0, accumulatedRotation, 0, 16);

1

Hình ảnh của bạn tương ứng với mã rotationMatrix của bạn, bằng cách xoay trục x với vòng xoay y trước đó, bạn nhận được trục x cục bộ, khi đó bạn xoay đối tượng xung quanh mà bạn sẽ nhận được kết quả mà bạn hiển thị trong hình ảnh của mình. Để có góc quay hợp lý theo quan điểm của người dùng, bạn sẽ muốn xoay đối tượng bằng trục tọa độ thế giới thay thế.

Nếu bạn muốn người dùng của mình có thể quay đối tượng của bạn nhiều lần, thì việc lưu trữ vòng quay của bạn trong một nhóm thay vì ma trận, theo thời gian, nhiều vòng quay (và không chính xác của dấu phẩy động) sẽ khiến ma trận trông ngày càng ít đi một ma trận xoay, điều tương tự xảy ra trong một tứ phương tất nhiên, nhưng chỉ cần bình thường hóa tứ phương sẽ đưa nó trở lại một vòng quay tốt.

Đơn giản chỉ cần sử dụng phần tư danh tính làm giá trị ban đầu và mỗi lần người dùng vuốt màn hình bạn xoay phần tư của bạn bằng Quaternion.fromAxisAngle(yAxis, -angleX)mã. Luôn sử dụng (1,0,0,1) cho các phép quay x và (0,1,0,1) cho các phép quay y.

static final float[] xAxis = {1f, 0f, 0f, 1f};
static final float[] yAxis = {0f, 1f, 0f, 1f};

private void rotateObject(float angleX, float angleY) {
  Quaternion rotationY = Quaternion.fromAxisAngle(yAxis, -angleX);
  Quaternion rotationX = Quaternion.fromAxisAngle(xAxis, -angleY);

  myRotation = myRotation.rotate(rotationY).rotate(rotationX).normalize();
}
private float[] rotationMatrix() {
  return myRotation.toMatrix();
}

Vì bạn không đề cập đến ngôn ngữ hoặc bất kỳ khuôn khổ cụ thể nào, các phương thức trên Quancyion có thể được gọi là một thứ gì đó khác biệt, và bình thường hóa không cần thiết phải gọi nó thường xuyên, nhưng vì xoay vòng đến từ người dùng vuốt màn hình nên họ sẽ không làm mọi thứ chậm lại nhiều và theo cách đó, không có cơ hội Đệ tứ tuột khỏi một đơn vị tứ phương.


Tôi đang nhận được chính xác hành vi tương tự làm điều này.
Christopher Perry

1
@ChristopherPerry Hãy thử đảo ngược thứ tự xoay vòng: myRotation = rotationX.rotate(rotationY).rotate(myRotation).normalize()Chúng không giao hoán nên thứ tự bạn làm chúng được tính. Thêm một nhận xét khác với khung / ngôn ngữ của bạn nếu điều đó không hiệu quả và Ill đào sâu vào nó thêm một chút.
Daniel Carlsson

Điều đó cũng không hiệu quả, tôi cũng có hành vi tương tự.
Christopher Perry

Tôi đặt TẤT CẢ mã của mình ở đây
Christopher Perry
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.