2012-12-28 34 views
5

Tôi đang tìm cách triển khai đơn giản cho xoay vòng cung trên mô hình 3D với quaternions, sử dụng GLKit trên iOS. Cho đến nay, tôi đã xem xét các nguồn sau:Xoay vòng Arcball với Quaternions (sử dụng iOS GLKit)

Tôi cũng đã cố gắng để hiểu mã nguồn và toán học từ herehere. Tôi có thể xoay đối tượng của tôi nhưng nó vẫn nhảy xung quanh ở các góc độ nhất định, vì vậy tôi sợ khóa gimbal đang chơi. Tôi đang sử dụng công cụ nhận dạng cử chỉ để kiểm soát vòng quay (cử chỉ pan ảnh hưởng đến cuộn và ngáp, cử chỉ xoay ảnh hưởng đến độ cao). Tôi đang gắn mã của tôi để xử lý quaternion cũng như chuyển đổi ma trận modelview.

biến:

  • GLKQuaternion rotationE;

tec non Xử lý:

- (void)rotateWithXY:(float)x and:(float)y 
{ 
    const float rate = M_PI/360.0f; 
    GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f); 
    GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f); 

    up = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), up); 
    self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up)); 

    right = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), right); 
    self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(y*rate, right)); 
} 

- (void)rotateWithZ:(float)z 
{ 
    GLKVector3 front = GLKVector3Make(0.0f, 0.0f, -1.0f); 

    front = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), front); 
    self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(z, front)); 
} 

modelview Matrix Transformation (Bên Vẽ Loop):

// Get Quaternion Rotation 
GLKVector3 rAxis = GLKQuaternionAxis(self.transformations.rotationE); 
float rAngle = GLKQuaternionAngle(self.transformations.rotationE); 

// Set Modelview Matrix 
GLKMatrix4 modelviewMatrix = GLKMatrix4Identity; 
modelviewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f); 
modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, rAngle, rAxis.x, rAxis.y, rAxis.z); 
modelviewMatrix = GLKMatrix4Scale(modelviewMatrix, 0.5f, 0.5f, 0.5f); 
glUniformMatrix4fv(self.sunShader.uModelviewMatrix, 1, 0, modelviewMatrix.m); 

Bất kỳ trợ giúp nào được đánh giá rất cao, nhưng tôi muốn giữ nó càng đơn giản càng tốt và dính vào GLKit.

Trả lời

5

Dường như có một vài các vấn đề xảy ra ở đây.

  1. Bạn nói rằng bạn đang sử dụng [x, y] để pan, nhưng nó trông giống như bạn đang sử dụng chúng để pitch và yaw. Đối với tôi, ít nhất, panning là dịch, không phải xoay vòng.

  2. Trừ tôi là thiếu cái gì đó, nó cũng giống như thay thế của bạn toàn bộ mọi xoay bạn cố gắng để cập nhật nó. Bạn xoay một vector bằng nghịch đảo của vòng quay hiện tại và sau đó tạo một quaternion từ vectơ đó và một số góc. Tôi tin rằng điều này tương đương với việc tạo ra quaternion từ vectơ ban đầu và sau đó xoay nó bằng nghịch đảo quay hiện tại. Vì vậy, bạn có q_e'*q_up. Sau đó, bạn nhân với vòng quay hiện tại, cho phép q_e*q_e'*q_up = q_up. Xoay vòng hiện tại bị hủy. Điều này không có vẻ giống như những gì bạn muốn.

    Tất cả các bạn thực sự cần phải làm là tạo ra một quaternion mới từ trục và góc và sau đó nhân nó với các quaternion hiện hành. Nếu quaternion mới ở bên trái, sự thay đổi định hướng sẽ sử dụng khung mắt nội bộ. Nếu quaternion mới ở bên phải, thay đổi định hướng sẽ nằm trong khung toàn cục. Tôi nghĩ rằng bạn muốn:

    self.rotationE = 
        GLKQuaternionMultiply( 
        GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up),self.rotationE); 
    

    Thực hiện việc này mà không cần quay vòng trước bằng nghịch đảo cho cả ba trường hợp.

  3. Tôi chưa bao giờ sử dụng GLKit, nhưng không có gì lạ khi trích xuất góc trục khi chuyển đổi từ Quaternion thành Ma trận. Nếu góc bằng 0 thì trục không xác định. Khi nó gần bằng không, bạn sẽ có sự bất ổn định số.Dường như bạn nên sử dụng GLKMatrix4MakeWithQuaternion và sau đó nhân ma trận kết quả với ma trận dịch của bạn và ma trận quy mô:

    GLKMatrix4 modelviewMatrix = 
        GLKMatrix4Multiply(GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f), 
             GLKMatrix4MakeWithQuaternion(self.rotationE)); 
    modelviewMatrix = GLKMatrix4Scale(modelviewMatrix, 0.5f, 0.5f, 0.5f); 
    
+0

câu trả lời Brilliant, nó làm việc một cách hoàn hảo. Đây là lần đầu tiên tôi tham gia vào quaternions, vì vậy lời giải thích rõ ràng được đánh giá rất cao - cảm ơn! Tôi đã chỉnh sửa câu hỏi của tôi để làm rõ điểm của bạn nêu ra trong (1), mặc dù cử chỉ được đặt tên là "pan" (quy ước iOS) nó thực sự kiểm soát vòng quay của mô hình của tôi. –

3

Gần đây tôi đã được hỏi thêm một chút về thực hiện kết quả của tôi về vấn đề này, vì vậy ở đây nó Là!

- (void)rotate:(GLKVector3)r 
{ 
    // Convert degrees to radians for maths calculations 
    r.x = GLKMathDegreesToRadians(r.x); 
    r.y = GLKMathDegreesToRadians(r.y); 
    r.z = GLKMathDegreesToRadians(r.z); 

    // Axis Vectors w/ Direction (x=right, y=up, z=front) 
    // In OpenGL, negative z values go "into" the screen. In GLKit, positive z values go "into" the screen. 
    GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f); 
    GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f); 
    GLKVector3 front = GLKVector3Make(0.0f, 0.0f, 1.0f); 

    // Quaternion w/ Angle and Vector 
    // Positive angles are counter-clockwise, so convert to negative for a clockwise rotation 
    GLKQuaternion q = GLKQuaternionIdentity; 
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.x, right), q); 
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.y, up), q); 
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.z, front), q); 

    // ModelView Matrix 
    GLKMatrix4 modelViewMatrix = GLKMatrix4Identity; 
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeWithQuaternion(q)); 
} 

Hy vọng bạn đặt nó để sử dụng tốt :)

Các vấn đề liên quan