iOS OpenGL ES 在 2d 世界中执行缩放

标签 ios ipad opengl-es pinchzoom

我正在 iPad 上制作 2d OpenGL 应用程序。我需要实现捏合/缩放。

我想在 (x,y) 平面内移动相机,并用捏合手势控制相机的 x,yz 值。

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/

相关文章:

iphone - 纵向应用程序 - 横向模态视图 - 无自动旋转

iphone - 如何设置popOverController的宽高

android - 如何用手指移动 OpenGL 正方形?

iphone - 多采样渲染到 ios 中的纹理

iphone - iPhone:将NSString(unicode字符串)转换为char数组并反转

iphone - presentViewController 不支持 iOS 6 中的方向

ios - Carthage 不构建主框架

c# - 如何在unity中请求Camera的运行时权限?

iphone - 文件缓存问题

java - 创建可滚动区域有哪些技术?