【问题标题】:How to pinch zoom into a certain location in OpenGL ES 2?如何在 OpenGL ES 2 中捏缩放到某个位置?
【发布时间】:2019-10-09 00:05:30
【问题描述】:

Stack Overflow 上还有其他关于捏缩放的帖子,但我没有找到任何对 OpenGL 有用的帖子,这些帖子可以满足我的需求。我目前正在使用orthoM 函数来更改相机位置并在OpenGL 中进行缩放。我已经让相机四处移动,并且已经让捏缩放工作,但缩放总是放大到0,0的OpenGL表面视图坐标系的中心。在尝试了不同的事情之后,我还没有找到一种方法可以让相机四处移动,同时还允许捏缩放到用户的触摸点(例如,Clash of Clans 中的触摸控件与我正在尝试的类似制作)。

(我目前用来获取scale值的方法是基于this post。)

我的第一次尝试:

// mX and mY are the movement offsets based on the user's touch movements,
// and can be positive or negative
Matrix.orthoM(mProjectionMatrix, 0, ((-WIDTH/2f)+mX)*scale, ((WIDTH/2f)+mX)*scale,
                                    ((-HEIGHT/2f)+mY)*scale, ((HEIGHT/2f)+mY)*scale, 1f, 2f);

在上面的代码中,我意识到相机向坐标0,0 移动,因为随着scale 变得越来越小,相机边缘的值向0 减小。因此,尽管变焦朝向坐标系中心,但相机的移动在任何比例级别上都以正确的速度移动。

所以,我随后将代码编辑为:

Matrix.orthoM(mProjectionMatrix, 0, (-WIDTH/2f)*scale+mX, (WIDTH/2f)*scale+mX,
                                    (-HEIGHT/2f)*scale+mY, (HEIGHT/2f)*scale+mY, 1f, 2f);

编辑后的代码现在使缩放朝向屏幕中心,无论相机在表面视图坐标系中的哪个位置(尽管这不是全部目标),但相机移动已关闭,因为偏移量未针对不同的规模级别进行调整。

我自己仍在努力寻找解决方案,但如果有人对如何实施此方案有任何建议或想法,我将很高兴听到。

请注意,我认为这并不重要,但我在 Android 中使用 Java 进行此操作。

编辑:

自从我第一次发布这个问题以来,我已经对我的代码进行了一些更改。我找到了this post,它解释了如何根据比例将相机平移到正确位置的逻辑,从而使缩放点保持在同一位置。

我的更新尝试:

// Only do the following if-block if two fingers are on the screen
if (zooming) {
    // midPoint is a PointF object that stores the coordinate of the midpoint between
    //two fingers
    float scaleChange = scale - prevScale;  // scale is the same as in my previous code
    float offsetX = -(midPoint.x*scaleChange);
    float offsetY = -(midPoint.y*scaleChange);
    cameraPos.x += offsetX;
    cameraPos.y += offsetY;
}

// cameraPos is a PointF object that stores the coordinate at the center of the screen, 
// and replaces the previous values mX and mY
left = cameraPos.x-(WIDTH/2f)*scale;
right = cameraPos.x+(WIDTH/2f)*scale;
bottom = cameraPos.y-(HEIGHT/2f)*scale;
top = cameraPos.y+(HEIGHT/2f)*scale;

Matrix.orthoM(mProjectionMatrix, 0, left, right, bottom, top, 1f, 2f);

代码现在确实工作得更好了,但仍然不完全准确。我测试了禁用平移时代码的工作方式,并且缩放效果更好。但是,启用平移后,缩放根本不会集中在缩放点上。

【问题讨论】:

    标签: opengl-es-2.0 pinchzoom


    【解决方案1】:

    我在处理另一个项目时终于找到了解决方案,因此我将发布(尽可能以最简单的形式)对我有用的方法,以防万一这可能对任何人有所帮助。

    final float currentPointersDistance = this.calculateDistance(pointer1CurrentX, pointer1CurrentY, pointer2CurrentX, pointer2CurrentY);
    final float zoomFactorMultiplier = currentPointersDistance/initialPointerDistance; //> Get an initial distance between two pointers before calling this
    
    final float newZoomFactor = previousZoomFactor*zoomFactorMultiplier;
    final float zoomFactorChange = newZoomFactor-previousZoomFactor; //> previousZoomFactor is the current value of the zoom
    
    //> The x and y values of the variables are in scene coordinate form (not surface)
    final float distanceFromCenterToMidpointX = camera.getCenterX()-currentPointersMidpointX;
    final float distanceFromCenterToMidpointY = camera.getCenterY()-currentPointersMidpointY;
    
    final float offsetX = -(distanceFromCenterToMidpointX*zoomFactorChange/newZoomFactor);
    final float offsetY = -(distanceFromCenterToMidpointY*zoomFactorChange/newZoomFactor);
    
    camera.setZoomFactor(newZoomFactor);
    camera.translate(offsetX, offsetY);
    
    initialPointerDistance = currentPointersDistance; //> Make sure to do this
    

    用于计算两个指针之间距离的方法:

    public float calculateDistance(float pX1, float pY1, float pX2, float pY2) {
        float x = pX2-pX1;
        float y = pY2-pY1;
        return (float)Math.sqrt((x*x)+(y*y));
    }
    

    上面用到的相机类方法:

    public float getXMin() {
        return centerX-((centerX-xMin)/zoomFactor);
    }
    
    public float getYMin() {
        return centerY-((centerY-yMin)/zoomFactor);
    }
    
    public float getXMax() {
        return centerX+((xMax-centerX)/zoomFactor);
    }
    
    public float getYMax() {
        return centerY+((yMax-centerY)/zoomFactor);
    }
    
    public void setZoomFactor(float pZoomFactor) {
        zoomFactor = pZoomFactor;
    }
    
    public void translate(float pX, float pY) {
        xMin += pX;
        yMin += pY;
        xMax += pX;
        yMax += pY;
    }
    

    orthoM() 函数调用如下:

    Matrix.orthoM(projectionMatrix, 0, camera.getXMin(), camera.getXMax(), camera.getYMin(), camera.getYMax(), near, far);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      相关资源
      最近更新 更多