4

我想知道如何正确放大OpenGL ES 2.0。我已经成功绘制了一个模型,但它非常小,我无法放大这个模型。我喜欢的是放大“通过”这个模型。

该模型是具有不同楼层的建筑物 - 我想放大到每个楼层的每个房间。但是要么对象因为视锥而消失,要么我无法非常“接近”这个对象。

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

到目前为止我尝试了什么:

更改近平面和远平面距离并更改 Matrix.setLookAtM(....) 中的 eyeZ-Value 但我只实现缩小...它在放大后消失...所以我'无法放大到某些特殊部分(“那”远....)


我怎样才能做到这一点?

所以最大的问题是通过 eyeZ-Value 结合缩放的近平面。它根本行不通。如果我放大,物体会因为近平面而消失。但我看不出这背后有什么逻辑。

目前我正在使用:

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

其中 mZoomLevel 是我通过 onTouch-Zooming 获得的因素。

我的整个矩阵运算都显示在这里:

@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 部分的虚拟项目——以防你想更好地查看源代码

我有的:

我目前的看法

我需要的:

我想要的视图

4

2 回答 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);
}

但这不是最好的方法(请参阅此答案下方的评论)

于 2013-12-12T00:13:27.127 回答
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;
}
于 2014-01-07T08:27:09.287 回答