我正在寻找具有四元数的3D模型的圆球旋转的简单实现,特别是在iOS上使用GLKit 。到目前为止,我已经检查了以下来源:
- Arcball旋转与GLKit
- 如何使用OpenGL旋转带有触摸的3D对象
我也一直试图理解源代码和数学从这里和这里。我可以旋转我的对象,但它总是以特定的角度跳跃,所以我担心万向节锁定起作用了。我使用手势识别器来控制旋转(平移手势影响滚动和偏航,旋转手势影响俯仰)。我附加了四元数处理以及模型视图矩阵变换的代码。
变量:
-
GLKQuaternion rotationE;
四元数处理:
- (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 (Inside Draw 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);
非常感谢任何帮助,但我确实想保持它尽可能简单,并坚持使用GLKit。
这里似乎有一些问题。
-
你说你正在使用[x,y]来平移,但它看起来更像是你在使用它们来俯仰和偏航。至少对我来说,平移是平移,而不是旋转。
-
除非我错过了什么,它看起来也像你每次尝试更新它时替换整个旋转。你以当前旋转的逆方向旋转一个向量,然后从这个向量和某个角度创建一个四元数。我相信这相当于从原始向量创建四元数,然后通过当前的旋转逆旋转它。这是
q_e'*q_up
。然后乘以当前的旋转,得到q_e*q_e'*q_up = q_up
。当前的旋转被抵消了。这似乎不是你想要的。你真正需要做的就是从轴和角创建一个新的四元数,然后将它与当前的四元数相乘。如果新的四元数在左边,方向改变将使用眼局部帧。如果新的四元数在右边,则方向变化将在全局框架中。我想你需要:
self.rotationE = GLKQuaternionMultiply( GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up),self.rotationE);
这样做,在所有三种情况下都不需要反向旋转。
-
我从未使用过GLKit,但在从四元数转换为矩阵时提取轴角是不常见的。如果角度为零,则轴未定义。当它接近零时,就会出现数值不稳定。看起来您应该使用
GLKMatrix4MakeWithQuaternion
,然后将得到的矩阵与转换矩阵和比例矩阵相乘:GLKMatrix4 modelviewMatrix = GLKMatrix4Multiply( GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f), GLKMatrix4MakeWithQuaternion( self.rotationE ) ); modelviewMatrix = GLKMatrix4Scale( modelviewMatrix, 0.5f, 0.5f, 0.5f );
最近有人问我更多关于这个问题的最终实现,所以在这里!
- (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));
}
希望你好好利用它