我正在 iPad 上制作 2d OpenGL 应用程序。我需要实现捏合/缩放。
我想在 (x,y)
平面内移动相机,并用捏合手势控制相机的 x,y
和 z
值。
update
方法中的每一帧我都像这样制作 View 矩阵(相机)
lookAt = GLKMatrix4MakeLookAt(view_x, view_y, view_z, view_x, view_y, 0.0f, 0.0f, 1.0f, 0.0f);
其中 view_x、view_y 和 view_z 在程序启动时定义如下:
view_x = view_y = 0.0f; view_z = kStartZoom;
kStartZoom 为 3000。
所以相机在 (0,0,3000) 并且看向 (0,0,0)
处理夹点事件的几乎可行的解决方案是
- (IBAction) handlePinch:(UIPinchGestureRecognizer*) recognizer {
switch (recognizer.state)
{
case UIGestureRecognizerStateBegan:
{
if (recognizer.numberOfTouches == 2)
{
prevTouchOrigin1 = [recognizer locationOfTouch:0 inView:self.view];
prevTouchOrigin2 = [recognizer locationOfTouch:1 inView:self.view];
}
} break;
case UIGestureRecognizerStateChanged:
{
if (recognizer.numberOfTouches == 2)
{
CGFloat newDistance, oldDistance;
oldDistance = distanceBetweenTwoCGPoints(&prevTouchOrigin1, &prevTouchOrigin2);
currTouchOrigin1 = [recognizer locationOfTouch:0 inView:self.view];
currTouchOrigin2 = [recognizer locationOfTouch:1 inView:self.view];
newDistance = distanceBetweenTwoCGPoints(&currTouchOrigin1, &currTouchOrigin2);
if (newDistance == 0 || oldDistance == 0)
{
scaleFactor = 1;
} else {
scaleFactor = oldDistance / newDistance;
}
GLfloat check = view_z * scaleFactor;
if (check < kMinZoom || check > kMaxZoom)
return;
view_z *= scaleFactor;
// translate
// formula: newPos = currTouchOrigin + (objectOrigin - prevTouchOrigin) * scaleFactor
static CGPoint translationDelta;
GLfloat z_ratio = view_z_old / view_z;
newPos1.x = currTouchOrigin1.x - ((prevTouchOrigin1.x - view_x) * scaleFactor);
newPos1.y = currTouchOrigin1.y - ((prevTouchOrigin1.y - view_y) * scaleFactor);
newPos2.x = currTouchOrigin2.x - ((prevTouchOrigin2.x - view_x) * scaleFactor);
newPos2.y = currTouchOrigin2.y - ((prevTouchOrigin2.y - view_y) * scaleFactor);
midpoint = CGPointMidpoint(&newPos1, &newPos2);
translationDelta = CGPointMake(midpoint.x - view_x, midpoint.y - view_y);
view_x += translationDelta.x;
view_y -= translationDelta.y;
prevTouchOrigin1 = currTouchOrigin1;
prevTouchOrigin2 = currTouchOrigin2;
}
} break;
case UIGestureRecognizerStateEnded:
{
} break;
default :
{
}
}}
一切正常。
我在 x,y 上有更多的运动,然后我需要这样相机在周围摆动。
问题是我没有应用一些从屏幕坐标到世界坐标的转换吗?
可能是什么问题?我正在研究的其他示例仅根据前一个手指位置和最后一个手指位置之间的距离修改相机位置,这就是我正在做的。
最佳答案
这是我的解决方案:
我有两个类,一个负责处理所有 OpenGL 内容 (RenderViewController),另一个负责处理所有手势识别器以及 OpenGL 部分与应用程序其他部分之间的通信 (EditViewController)。
这是关于手势的代码:
EdtorViewController
它捕获手势并将有关它们的信息发送到 RenderViewController。由于坐标系不同,您必须小心。
- (void) generateGestureRecognizers {
//Setup gesture recognizers
UIRotationGestureRecognizer *twoFingersRotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersRotate:)];
[self.hitView addGestureRecognizer:twoFingersRotate];
UIPinchGestureRecognizer *twoFingersScale = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersScale:)];
[self.hitView addGestureRecognizer:twoFingersScale];
UIPanGestureRecognizer *oneFingerPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(oneFingerPan:)];
[self.hitView addGestureRecognizer:oneFingerPan];
[twoFingersRotate setDelegate:self];
[twoFingersScale setDelegate:self];
[oneFingerPan setDelegate:self];
}
- (void) oneFingerPan:(UIPanGestureRecognizer *) recognizer {
//Handle pan gesture
CGPoint translation = [recognizer translationInView:self.hitView];
CGPoint location = [recognizer locationInView:self.hitView];
//Send info to renderViewController
[self.renderViewController translate:traslation];
//Reset recognizer so change doesn't accumulate
[recognizer setTranslation:CGPointZero inView:self.hitView];
}
- (void) twoFingersRotate:(UIRotationGestureRecognizer *) recognizer {
//Handle rotation gesture
CGPoint locationInView = [recognizer locationInView:self.hitView];
locationInView = CGPointMake(locationInView.x - self.hitView.bounds.size.width/2, locationInView.y - self.hitView.bounds.size.height/2);
if ([recognizer state] == UIGestureRecognizerStateBegan || [recognizer state] == UIGestureRecognizerStateChanged) {
//Send info to renderViewController
[self.renderViewController rotate:locationInView degrees:recognizer.rotation];
//Reset recognizer
[recognizer setRotation:0.0];
}
}
- (void) twoFingersScale:(UIPinchGestureRecognizer *) recognizer {
//Handle scale gesture
CGPoint locationInView = [recognizer locationInView:self.hitView];
locationInView = CGPointMake(locationInView.x - self.hitView.bounds.size.width/2, locationInView.y - self.hitView.bounds.size.height/2);
if ([recognizer state] == UIGestureRecognizerStateBegan || [recognizer state] == UIGestureRecognizerStateChanged) {
//Send info to renderViewController
[self.renderViewController scale:locationInView ammount:recognizer.scale];
//reset recognizer
[recognizer setScale:1.0];
}
}
//This allows gestures recognizers to happen simultaniously
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (gestureRecognizer.view != otherGestureRecognizer.view)
return NO;
if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
return NO;
return YES;
}
渲染 View Controller
对于每一帧,modelViewMatrix 是根据其他三个临时矩阵(平移、缩放和旋转)计算的
- (void) setup {
//Creates the modelViewMatrix from the initial position, rotation and scale
translatemt = GLKMatrix4Translate(GLKMatrix4Identity, initialPosition.x, initialPosition.y, 0.0);
scalemt = GLKMatrix4Scale(GLKMatrix4Identity, initialScale, initialScale, 1.0);
rotatemt = GLKMatrix4Rotate(GLKMatrix4Identity, initialRotation, 0.0, 0.0, 1.0);
self.modelViewMatrix = GLKMatrix4Multiply(GLKMatrix4Multiply(GLKMatrix4Multiply(translatemt, rotatemt), scalemt), GLKMatrix4Identity);
//set these back to identities to take further modifications (they'll update the modelViewMatrix)
scalemt = GLKMatrix4Identity;
rotatemt = GLKMatrix4Identity;
translatemt = GLKMatrix4Identity;
//rest of the OpenGL setup
[self setupOpengGL];
}
//public interface
- (void) translate:(CGPoint) location {
//Update the translation temporary matrix
translatemt = GLKMatrix4Translate(translatemt, location.x, -location.y, 0.0);
}
//public interface
- (void) rotate:(CGPoint) location degrees:(CGFloat) degrees {
//Update the rotation temporary matrix
rotatemt = GLKMatrix4Translate(GLKMatrix4Identity, location.x, -location.y, 0.0);
rotatemt = GLKMatrix4Rotate(rotatemt, -degrees, 0.0, 0.0, 1.0);
rotatemt = GLKMatrix4Translate(rotatemt, -location.x, location.y, 0.0);
}
//public interface
- (void) scale:(CGPoint) location ammount:(CGFloat) ammount {
//Update the scale temporary matrix
scalemt = GLKMatrix4Translate(GLKMatrix4Identity, location.x, -location.y, 0.0);
scalemt = GLKMatrix4Scale(scalemt, ammount, ammount, 1.0);
scalemt = GLKMatrix4Translate(scalemt, -location.x, location.y, 0.0);
}
- (void)update {
//this is done before every render update. It generates the modelViewMatrix from the temporary matrices
self.modelViewMatrix = GLKMatrix4Multiply(GLKMatrix4Multiply(GLKMatrix4Multiply(rotatemt, translatemt), scalemt), self.modelViewMatrix);
//And then set them back to identities
translatemt = GLKMatrix4Identity;
rotatemt = GLKMatrix4Identity;
scalemt = GLKMatrix4Identity;
//set the modelViewMatrix for the effect (this is assuming you are using OpenGL es 2.0, but it would be similar for previous versions
self.effect.transform.modelviewMatrix = self.modelViewMatrix;
}
关于iOS OpenGL ES 在 2d 世界中执行缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15929368/