我正在学习适用于 iOS 的 OpenGL ES 2.0,在一些教程的帮助下,我可以使用四元数旋转和缩放一个简单的球体对象。当用户在完成滑动后将手指从屏幕上抬起时,我希望地球继续以递减的速度旋转 - 所以我想给球体一些动力。我用这个博客来学习旋转:http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl .任何人都可以提供一些阅读或动量的例子吗?如何用四元数实现动量?谢谢!
// Set up the frustrum and projection matrix
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
self.effect.transform.projectionMatrix = projectionMatrix;
// Now perform the interpolation step
//[self slerpToNewLocation];
// Move the globe back so we can see it
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, GLOBAL_EARTH_Z_LOCATION);
// In update, we convert the quaternion into a rotation matrix, and apply it to the model view matrix as usual.
GLKMatrix4 rotation = GLKMatrix4MakeWithQuaternion(_quat);
GLKMatrix4 rotateMatrix = GLKMatrix4RotateWithVector3(rotation,momentumVar/200,GLKQuaternionAxis(_quat));
_quat = GLKQuaternionMakeWithMatrix4(rotateMatrix);
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, rotateMatrix);
// Cap the zoom scale factor max and mins
// only if slerping so that the auto-zoom out and back
// in still works during auto-rotation
if ( !_slerping ) {
if ( scale > 2.0 ) {
scale = 2.0;
}
if ( scale < 1.15 ) {
scale = 1.15;
}
}
// Apply the zoom factors
if ( _slerping ) {
//NSLog(@"final scale %f",scale);
}
modelViewMatrix = GLKMatrix4Scale(modelViewMatrix, scale, scale, scale);
// Assign the drawer modelViewMatrix
self.effect.transform.modelviewMatrix = modelViewMatrix;
我看到了以下问题:Obtaining momentum quaternion from two quaternions and timestep - 但不明白答案。我非常感谢这里的一些提示 - 谢谢。
// Called when touches are ended
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
// The momentum var is initialized to a value
momentumVar = 0.025;
// Now since we stopped touching, decay the rotation to simulate momentum
momentumTimer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(decayGLKQuaternion)
userInfo:nil
repeats:YES];
}
// Slerp about the current axis after touches ended but for a greater angle ( radians )
- (void)decayGLKQuaternion {
if ( momentumVar < 0.001 ) {
// Stop the momentum and timer
momentumVar = 1.0;
[momentumTimer invalidate];
}
else {
// What is the current angle for the quaternion?
float currentQuatAngle = GLKQuaternionAngle(_quat);
// Decay the value each time
momentumVar = currentQuatAngle * 0.95;
}
}
更新:我仍在尝试解决这个问题,我尝试将更新方法中的当前四元数转换为 Matrix4 并围绕四元数轴旋转该矩阵以获得从开始触发的计时器更新和递减的值一旦 TouchesEnded 在我的应用程序中。结果进行了旋转,但轴看起来不太正确(看起来很接近)并且角度产生了与我预期相反的旋转方向 - 因此如果我向下滑动并抬起手指,地球仪会以较低的速度向上旋转。更改角度值的符号没有帮助。如何从四元数中正确提取旋转轴,以适当的角度旋转它,并以递减的速度旋转?谢谢-
// In update, we convert the quaternion into a rotation matrix, and apply it to the model view matrix as usual.
GLKMatrix4 rotation = GLKMatrix4MakeWithQuaternion(_quat);
GLKMatrix4 rotateMatrix = GLKMatrix4RotateWithVector3(rotation,momentumVar/200,GLKQuaternionAxis(_quat));
_quat = GLKQuaternionMakeWithMatrix4(rotateMatrix);
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, rotateMatrix);
最佳答案
通过使用 UIKit 中的 UIScrollView 类,您可以完全避免必须实现动量物理。您可以放置一个实际上不在 OpenGL View 上绘制任何内容的 UIScrollView,并将其配置为具有您想要的 contentSize(可滚动区域)和滚动属性。然后你可以让你的一个类符合 UIScrollViewDelegate并使该类的实例成为您的 UIScrollView 的委托(delegate)。然后,当用户与您的不可见 ScrollView (在您的 OpenGL View 之上)交互时,您的 ScrollView 委托(delegate)类将收到用户交互的通知。以下委托(delegate)方法可能对实现特别有用。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
在那里,您可以获得最新更新的contentOffset并使用它来更新您的 3D 模型,然后您可以使用 OpenGL 将其渲染到您的 OpenGL View 中。因此,您仅将 ScrollView 用作检测用户交互的机制,它将处理 iOS 用户熟悉的所有流畅更新和动量物理。
我强烈推荐观看 WWDC 2012 Session 223, "Enhancing User Experience with Scroll Views"与乔希谢弗。在那次演讲中,他通过示例非常详细地讨论了如何使用这种技术。
关于iphone - 滑动后 iOS OpenGL ES 2.0 四元数旋转与动量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16136360/