5

Tôi đã dành một vài tuần cho vấn đề này và dường như không tìm được giải pháp phù hợp và cần một số lời khuyên.LWJGL - Các sự cố khi triển khai 'cuộn' trong Máy ảnh 6DOF sử dụng quaternions và ma trận dịch

Tôi đang làm việc để tạo lớp Máy ảnh bằng LWJGL/Java và đang sử dụng Quaternions để xử lý vòng bi (yaw), xoay vòng và xoay. Tôi muốn máy ảnh này xử lý tất cả 6 độ chuyển động trong không gian 3D và cuộn. Bearing, Pitch and Roll là tất cả các quaternions. Tôi nhân chúng thành một quaternion 'thay đổi', và tạo ra một ma trận dịch từ đó. Tôi đặt nó trong một bộ đệm float, và nhân ma trận modelview bởi bộ đệm của tôi chứa ma trận xoay.

Tôi có thể có vòng bi và vòng quay để hoạt động bình thường, nhưng khi tôi triển khai cuộn, tôi đang gặp sự cố. Chủ yếu, xoay quanh trục Z (cán) dường như không hoạt động. Khi bao giờ tôi "cuộn" máy ảnh, nó dường như cuộn quanh trục Z toàn cầu thay vì trục hướng máy ảnh cục bộ. Tôi thường có thể nhận được 2 trong số 3 để làm việc tùy thuộc vào thứ tự tôi nhân các quaternions, nhưng tôi không thể làm cho họ làm việc cùng nhau.

Vì tất cả đều hoạt động độc lập, tôi giả định có điều gì đó sai với phương pháp định hướng của tôi, nơi tôi kết hợp chúng và tạo ma trận xoay vòng. Tôi đang gặp vấn đề dán toàn bộ lớp trong, vì vậy đây là những phương pháp và tuyên bố liên quan đến luân chuyển:

private final static float DEGTORAD = (float)(Math.PI/180);  

//Eye - position of the camera in the 3D world. 
private Vector3f eye; 

//Camera axis vectors, calculated each time reorient() is called. 
//Initialized to global x, y, and z axis initially. 
private Vector3f up; 
private Vector3f right; 
private Vector3f direction; 

//Angles of rotation (in degrees)  
private float pitchAngle; 
private float bearingAngle; 
private float rollAngle; 

private Quaternion pitch; 
private Quaternion bearing; 
private Quaternion roll; 

private FloatBuffer viewMatrixBuffer = BufferUtils.createFloatBuffer(16); 
private Quaternion currentOrientation; 

...

/** 
* Change the bearing (yaw) 
* @param bearing delta in degrees 
*/ 
public void bearing(float bearingDelta){ 
    bearingAngle += bearingDelta; 
    if(bearingAngle > 360){ 
     bearingAngle -= 360; 
    }else if(bearingAngle < 0){ 
     bearingAngle += 360; 
    } 
    bearing.setFromAxisAngle(new Vector4f(0f, 1f, 0f, bearingAngle * DEGTORAD)); 
    bearing.normalise(); 
} 

/** 
* Change the pitch 
* @param pitch delta in degrees 
*/ 
public void pitch(float pitchDelta){ 
    pitchAngle += pitchDelta; 
    if(pitchAngle > 360){ 
     pitchAngle -= 360; 
    }else if(pitchAngle < 0){ 
     pitchAngle += 360; 
    } 
    pitch.setFromAxisAngle(new Vector4f(1f, 0f, 0f, pitchAngle * DEGTORAD)); 
    pitch.normalise(); 
} 

/** 
* @param initialRoll 
*/ 
public void roll(float initialRoll) { 
    rollAngle += initialRoll; 
    if(rollAngle > 360){ 
     rollAngle -= 360; 
    }else if(rollAngle < 0){ 
     rollAngle += 360; 
    } 
    roll.setFromAxisAngle(new Vector4f(0, 0, 1, rollAngle * DEGTORAD)); 
    roll.normalise(); 
} 

/** 
* Change direction to focus on a certain point in the world 
* @param eye 
*/ 
public void lookThrough(){ 
    reorient(); 
    GL11.glMultMatrix(viewMatrixBuffer); 
}  

public void reorient(){ 
    //Multiply in order: bearing, pitch, roll. Non-commutative! 
    Quaternion change = new Quaternion(); 
    Quaternion.mul(bearing, pitch, change); 
    Quaternion.mul(roll, change, change); 
    // orient the camera... 
    Matrix4f rotationMatrix = getRotationMatrix(change); 

    //Get the looking direction 
    direction.x = rotationMatrix.m20; 
    direction.y = rotationMatrix.m21; 
    direction.z = rotationMatrix.m22; 

    //Set the position 
    rotationMatrix.m30 = eye.x; 
    rotationMatrix.m31 = eye.y; 
    rotationMatrix.m32 = eye.z; 
    rotationMatrix.m33 = 1; 

    rotationMatrix.invert(); 
    rotationMatrix.store(viewMatrixBuffer); 

    viewMatrixBuffer.rewind(); 

    Vector3f.cross(new Vector3f(0,1,0), direction, null).normalise(right); 
    Vector3f.cross(right, direction, null).normalise(up);    
} 

Vector3f, tec non, và Matrix4f là mọi tầng lớp LWJGL, không được tùy chỉnh. Vì vậy, câu hỏi của tôi là, cho 3 Quaternions đại diện cho Bearing, Pitch và Roll, làm thế nào để tôi sửa đổi ma trận ModelView để biểu diễn chính xác những phép quay này?

EDIT: Tôi cảm thấy điều này rất gần. Xem liên kết Gist trong bình luận của RiverC. Sau khi xoay quá nhiều độ, chế độ xem nhảy xung quanh rất nhiều trước khi trở lại bình thường khi lăn. Ý chính của nó là ở đó, nhưng nó vẫn hơi tắt.

Trả lời

3

Bạn đang thực hiện phép nhân theo thứ tự sai.

Đối với hai phép quay q1 và q2, nếu q2 theo sau q1 (vì các phép quay thường không phải là cộng sản), bạn nhân q2 * q1.

Trong hệ thống kiểu gimbal chẳng hạn như điều khiển cho FPS, thứ tự ưu tiên luôn là yaw, pitch, roll. Đây sẽ đề nghị toán học sau:

roll * pitch * yaw 

Là một điểm java, tôi sẽ đề nghị không tạo Quaternions mới cho mỗi bản cập nhật nhưng dù sao

change = Quaternion.mul(Quaternion.mul(roll, pitch, change), yaw, change); 

Nếu bạn nhìn vào mã, tec non thứ ba sẽ chỉ được ghi đè với kết quả, do đó không cần phải đặt lại hoặc tạo lại mỗi khung hình/cập nhật.

Thứ tự quay này khó hiểu, nhưng nếu bạn nhìn vào trang Wiki trên Quaternions, đó là quy tắc chung.

+0

Cảm ơn bạn đã cập nhật. Đã không chạm vào mã này trong một thời gian, vì vậy tôi đang trở lại với tốc độ với LWJGl. Tôi nghĩ rằng tôi gần gũi. Sau khi thực hiện các thay đổi và thay đổi do gsimard đề xuất, tôi đang tiến gần hơn. Tuy nhiên, khi ngáp (mang trong câu hỏi) là 0, sân là tốt. Khi ngáp ở 180, độ dốc được đảo ngược (thay vào đó, độ cao sẽ di chuyển máy ảnh xuống). Ngoài ra, quay trở nên rời rạc sau khi quay khoảng 20 độ. Nếu tôi tiếp tục xoay nó ra. Vì vậy, một cái gì đó vẫn không hoàn toàn đúng. Tôi sẽ đặt mã trên github và cập nhật câu hỏi này vào tối nay. Tôi nghĩ nó gần như ở đó. Cảm ơn một lần nữa. – framauro13

+0

Tại sao bạn làm công cụ cho ma trận xoay sau khi tạo nó? Bạn sẽ có thể gửi một Mat4 trực tiếp đến Shader và sử dụng nó để nhân các đỉnh của cảnh mà không sửa đổi nó. Ý tôi là, '// đặt hướng' một phần của mã. Nó có vẻ như bạn đang cố gắng sử dụng để bù đắp cho máy ảnh thông qua phép nhân, nhưng trong kinh nghiệm của tôi, điều này đã bị đánh và bỏ lỡ. Hãy thử bỏ điều đó. –

+0

Tôi * nghĩ * lý do tôi đã làm điều đó ban đầu là để tôi có thể tổng hợp véc tơ hướng với vectơ mắt để tạo ra một vectơ tương tác với các vật thể trên thế giới. Một 'chọn' véc tơ nhiều hơn hoặc ít hơn. Ngoài ra, tôi đã khắc phục vấn đề với lật sân. Tôi đổi thứ tự của mang và pitch, do đó, dòng đọc 'Quaternion.mul (Quaternion.mul (cuộn, mang, thay đổi), pitch, thay đổi);' Vẫn đang cố gắng tìm ra lý do tại sao cuộn được wonky sau khi lăn một số số tiền. – framauro13

3

Tôi biết điều này là cũ, nhưng cho phép tôi đoán anyway. Vấn đề chính xác là những gì bạn đã nói:

Khi nào tôi "cuộn" máy ảnh, dường như cuộn quanh trục Z toàn cục thay vì trục hướng camera của máy ảnh.

Nó làm như vậy bởi vì bạn đã yêu cầu nó cuộn quanh vectơ (0,0,1), tức là trục Z toàn cầu.

Đây là những quaternion đơn vị làm: chúng xoay một vector (ở đây một tập hợp các vectơ, ma trận xoay của bạn) xung quanh trục được chỉ định bởi phần vectơ tưởng tượng của chúng (x, y, z). (w = cos (góc/2)).

Nếu tôi hiểu những gì bạn đang cố gắng làm, đó là cán máy ảnh của bạn như khi nghiêng đầu của bạn từ trái sang phải, sau đó bạn nên xây dựng một quaternion cuộn xung quanh vector hướng của bạn:

roll.setFromAxisAngle(new Vector4f(direction.x, direction.y, direction.z, rollAngle * DEGTORAD)); 

tôi m giả sử vectơ hướng của bạn được chuẩn hóa hoặc LWJGL biết phải làm gì với vectơ trục không đơn nhất khi gọi setFromAxisAngle.

+0

Cảm ơn bạn đã cập nhật. Tôi đã thực hiện thay đổi này và nó gần, tuy nhiên tôi vẫn nhận được một số hành vi kỳ lạ. Tôi đã thực hiện thay đổi này với sự thay đổi do RiverC đề xuất và giải thích các vấn đề mới trong nhận xét ở đó. Tôi sẽ cập nhật khi tôi về nhà tối nay với nhiều chi tiết hơn. Cảm ơn một lần nữa, tôi đánh giá cao sự giúp đỡ. – framauro13