如何在OpenGL ES 2中缩小缩放到某个位置?

时间:2019-03-11 00:05:19

标签: opengl-es-2.0 pinchzoom

有关堆栈缩放的其他文章,也没有找到有关OpenGL的有用信息,它们可以满足我的需求。我目前正在使用orthoM函数来更改相机位置并在OpenGL中进行缩放。我已经使相机可以移动,并且可以进行捏缩放,但是缩放始终会缩放到OpenGL表面视图坐标系0,0的中心。在尝试了不同的操作之后,我还没有找到一种方法来允许相机移动,同时还可以捏缩放用户的触摸点(例如,《部落冲突》中的触摸控件与我尝试的类似制作。)

(我目前用于获取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);

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

1 个答案:

答案 0 :(得分:0)

当我在另一个项目上工作时,我终于找到了解决方案,所以我将发布(以最简单的形式)对我有用的东西,以防万一可以帮助任何人。

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);