OpenGL ES 2.0 中的放大 - 物体消失

4

我想了解如何在 OpenGL ES 2.0 中正确缩放。我已经成功绘制了一个模型,但它太小了,我无法缩放到这个模型中。我想要的是通过这个模型进行缩放。

该模型是一个带有不同楼层的建筑物-我想缩放到每个楼层的每个房间。但是要么由于视锥体而使对象消失,要么我无法很接近这个对象。

我正在使用缩放触摸手势,并获得值“scale”-现在我应该如何处理这个值?

我迄今为止尝试过的:

改变近平面和远平面距离以及在 Matrix.setLookAtM(...) 中更改 eyeZ 值,但我只能实现缩小... 它在一段时间后消失在缩放中... 因此,我无法缩放到一些特殊部分(“那么远…”)


如何才能实现这个?

最大的问题在于接近平面和通过eyeZ值进行缩放的结合。它根本不起作用。如果我放大,由于接近平面,对象会消失。但我没有看到这背后的逻辑。

目前我正在使用:

/*
 * Set the camera position (View matrix)
 */
Matrix.setLookAtM(mViewMatrix, offset, eyeX, eyeY, eyeZ / mZoomLevel,
                  centerX, centerY, centerZ, upX, upY, upZ);

mZoomLevel是我通过onTouch缩放获得的因子。

这里展示了我的整个矩阵操作:

@Override
public void onDrawFrame(GL10 unused) {

LoggerHelper.calculateFPS();

/*
 * Draw background color
 */
 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

/*
 * scale model down to smaller values
 */
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.scaleM(mModelMatrix, 0, model3d.getRatio() * scaleFactor,
                model3d.getRatio() * scaleFactor, model3d.getRatio()
                                * scaleFactor);

/*
 * rotate and translate model in dependence to the user input
 */
Matrix.translateM(mModelMatrix, 0, translateX, translateY, translateZ);
Helper.rotateModel(mModelMatrix, rotationX, rotationY, rotationZ, true,
                model3d.getWidth(), model3d.getLength(), model3d.getHeight());

/*
 * Set the camera position (View matrix)
 */
Matrix.setLookAtM(mViewMatrix, offset, eyeX, eyeY, eyeZ / mZoomLevel,
                centerX, centerY, centerZ, upX, upY, upZ);

/*
 * combine the model with the view matrix
 */
Matrix.multiplyMM(mMVMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);

/*
 * this projection matrix is applied to object coordinates in the
 * onDrawFrame() method
 */
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, 1, -1,
                nearPlaneDistance, farPlaneDistance);

/*
 * Calculate the projection and view transformation
 */
float[] mMVPMatrix = new float[16];
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVMatrix, 0);

/*
 * all the drawing stuff inside the model-object (otherwise
 * translation/rotation wouldn't affect every object)
 */
model3d.draw(mMVPMatrix);

}

一些重要的变量:

private float nearPlaneDistance = 1f;
private float farPlaneDistance = 200f;
private float eyeZ = -1;

我在Github上上传了一个虚拟项目,仅包含OpenGL部分 - 如果你想更好地查看源代码,可以查看它

我有:

My current view

我需要的是:

My desired view


我仍然不明白为什么我的问题会被踩。我提出了一个清晰的问题,说明了我的需求,只是想知道如何实现它... 对于这个特定的问题,缺乏大量的文档资料... - Frame91
2
没错,我同意你的观点。这里有很多人在不理解问题的情况下进行负面评价。 - nilkash
根据您的图片,您不需要缩放 - 您只需要将相机移近一点。尝试设置一个超级小的近截面。而且从您的模型复杂性来看,我认为您不需要调整/重新调整近截面。只需选择一个超小的值并坚持使用它。我不知道您的模型处于什么比例尺度,但您可以尝试使用建筑物墙高除以1000或10000的值。 - Tenfour04
嘿,谢谢!你说的“将相机靠近”是什么意思?我需要将模型的z值翻译过来吗,还是要改变eyeZ?另外,当我将近平面更改为例如0.0001时,整个模型似乎被“拉伸”了,我看不清任何东西 :/ - Frame91
抱歉,刚看到你的评论。我不确定你正在使用哪个Matrix类来处理相机,但你只需要在z方向上更改相机矩阵的位置(而不是模型位置)。如果通过更改截锥体来拉伸模型,则Matrix类、顶点着色器或模型平移代码(修改其顶点位置)中存在错误。 - Tenfour04
2个回答

1

我的一个解决方案(效果不是很好):

public void setZoom(float zoom) {
    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    float ratio = (float) width / height;
    Matrix.frustumM(mProjectionMatrix, 0, -ratio / zoom, ratio / zoom, -1
            / zoom, 1 / zoom, nearPlaneDistance, farPlaneDistance);
}

但这并不是最好的方法(请参见下面答案中的评论)

虽然这解决了你的问题,但这是一个糟糕的解决方案。你所做的是减少了视野范围。如果正确使用LookAt应该可以解决问题。如果你的模型在(0,0,0),起始的eyeZ为-1.0,那么将eyeZ设置为-1.0/zoom就可以完成任务。通常情况下,当当前眼睛向量为"eye0",物体位置为"T0"时,你应该将缩放实现为eye = T0 + (eye0-T0)/zoom。 - Matic Oblak
谢谢!我明天早上会试一下 ;) - Frame91
嘿,Look-At因视野的问题而出现了一些麻烦...我无法将物体缩放得很远...它会因为近场平面而消失(我尝试更改平面的值...但效果不是很好)。 - Frame91
1
你的nearPlaneDistance和farPlaneDistance定义了剪裁。最好定义参数“near”,“far”和“angle”。然后,要获取那些“left”,“right”...参数,您可以使用dimension = near * tan(angle) * .5。然后使用Matrix.frustumM(mProjectionMatrix, 0, -ratio / zoom * dimension, ratio / zoom * dimension, -1 / zoom * dimension, 1 / zoom * dimension, nearPlaneDistance, farPlaneDistance); - Matic Oblak
嗨,我最近更改了缩放方式。现在是通过建议的eyeZ?-1.0/zoom来实现的。然而,我仍然无法缩放到我的模型中(它在我“进入”模型之前就停止缩放了)。我尝试将模型放大一点,但没有任何区别。我该如何解决这个问题?我已经上传了一个示例到以下存储库:https://github.com/Dalanie/OpenGL-ES/tree/master/buildingGL/ - Frame91
显示剩余2条评论

0
我对你的“缩放”感到困惑,或者你对它感到困惑。 当您移动视图矩阵(改变eyeZ)时,您不会缩放,只是移动相机。 是的,将相机靠近物体会使其看起来更大(在透视投影的情况下),但这并不是缩放。 您可以通过更改相机的焦距或视角来进行缩放。您可以改变相机的“透视性”。 就像如果您有一个真正的相机,仅向您的摄影主体行进与使用相机的变焦是不同的(假设它具有机械变焦)。
为了真正地对某些东西进行缩放(如果那确实是您想要的),您需要在Matrix.frustumM中更改“比率”。 因此,您可以使对象“在屏幕上变大”,而无需担心对象被近平面剪裁。 但是,它也会改变透视。 您缩放得越多,它看起来就越像正交投影。
我认为您尝试实现的是在建筑模型内飞行。 对于此操作,您不需要动态调整相机的缩放,但需要调整前后平面。

我想我知道你困惑的源头在哪里了。 当你改变视锥体的近平面但保持比例不变时,实际上你改变了缩放和视角。 因为投影矩阵的x和y焦点值是通过近平面除以左/右和上/下计算得出的。 Matrix.frustumM中的左、右、上、下实际上是近平面的尺寸。

这是frustumM的源代码。你可以看到x和y(即焦点)仅使用近平面而不是远平面进行计算。 如果你想保持缩放或视角并改变近平面,你将不得不将左、右(在你的情况下是比率)和上、下(在你的情况下是1)乘以原始近深度与新近深度之间的比率。

public static void frustumM(float[] m, int offset,
        float left, float right, float bottom, float top,
        float near, float far) {
    if (left == right) {
        throw new IllegalArgumentException("left == right");
    }
    if (top == bottom) {
        throw new IllegalArgumentException("top == bottom");
    }
    if (near == far) {
        throw new IllegalArgumentException("near == far");
    }
    if (near <= 0.0f) {
        throw new IllegalArgumentException("near <= 0.0f");
    }
    if (far <= 0.0f) {
        throw new IllegalArgumentException("far <= 0.0f");
    }
    final float r_width  = 1.0f / (right - left);
    final float r_height = 1.0f / (top - bottom);
    final float r_depth  = 1.0f / (near - far);
    final float x = 2.0f * (near * r_width);
    final float y = 2.0f * (near * r_height);
    final float A = 2.0f * ((right + left) * r_width);
    final float B = (top + bottom) * r_height;
    final float C = (far + near) * r_depth;
    final float D = 2.0f * (far * near * r_depth);
    m[offset + 0] = x;
    m[offset + 5] = y;
    m[offset + 8] = A;
    m[offset +  9] = B;
    m[offset + 10] = C;
    m[offset + 14] = D;
    m[offset + 11] = -1.0f;
    m[offset +  1] = 0.0f;
    m[offset +  2] = 0.0f;
    m[offset +  3] = 0.0f;
    m[offset +  4] = 0.0f;
    m[offset +  6] = 0.0f;
    m[offset +  7] = 0.0f;
    m[offset + 12] = 0.0f;
    m[offset + 13] = 0.0f;
    m[offset + 15] = 0.0f;
}

谢谢你的留言!我已经更新了我的问题,向你展示了我的问题。实际上,我不知道我是否需要缩放、比例或移动我的相机以获得所需的结果 :( 祝福! - Frame91
好的,翻译z是没问题的。但是当我旋转我的模型时,轴会交换,所以z不会向我的物体靠近,而是向侧面移动...如果我不旋转它就可以正常工作... - Frame91
我猜这是因为你的模型不再与z轴对齐了?不确定为什么你会旋转模型而不是相机? - user1097185

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接