4

I like to know about how to correctly zoom in OpenGL ES 2.0. I've successfully drawn a model but it's pretty small and I'm not able to zoom into this model. What I like to have is to zoom "through" this model.

The model is a building with different floors - I'd like to zoom to every room of every floor. But either the object disappears because of the view frustum or I'm not able to get very "near" to this object.

I'm using the zoom-touch gesture and get a value "scale" - what should I now do with this value?

What I tried so far:

Changing the near-plane and far-plane distance and changing the eyeZ-Value within Matrix.setLookAtM(....) but what I only achieve is zooming out... It disappears in zooming in after a bit... So I'm not able to zoom in to some special parts ("THAT" far....)


How I can I achieve this?

So the biggest problem is the near-plane combined with zooming via the eyeZ-Value. It simply doesn't work. If I zoom in, the object disappears because of the nearplane. But I don't see any logic behind this.

Currently I'm using:

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

where mZoomLevel is the factor I get through the onTouch-Zooming.

My whole Matrix-Operations are shown here:

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

}

Any some important variables:

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

I uploaded a dummy-project with only the OpenGL-part on Github - in case you want to have a better look into the sourcecode

What I have:

My current view

What I need:

My desired view

4

2 に答える 2

1

私の解決策の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

私はあなたの「ズーム」について混乱しているか、あなたはそれについて混乱しています。View マトリックスを移動する (eyeZ を変更する) 場合、ズームインまたはズームアウトはせず、カメラを移動するだけです。はい、カメラをオブジェクトに近づけると大きく見えますが (透視投影の場合)、ズームではありません。カメラの焦点距離または視野角を変更してズームします。カメラの「遠近感」を変更します。実際のカメラを持っている場合と同じように、写真の被写体に向かって単純に歩くことは、カメラのズームを使用することとは異なります (機械的なズームがあると仮定します)。

何かを実際にズームするには (それが実際に必要な場合)、Matrix.frustumM の「比率」を変更する必要があります。そのため、オブジェクトがニア プレーンによってクリッピングされることを心配することなく、画面上でオブジェクトを「大きく」することができます。ただし、見方も変わります。ズームすればするほど、正投影のように見えます。

あなたが達成しようとしているのは、建物のモデル内を飛行していると思います。そのために、カメラのズームを動的に調整する必要はありません。ただし、フロント プレーンとエンド プレーンを調整する必要があります。

私はあなたの混乱の原因が何かを知っていると思います. フラスタムのニア プレーンを変更し、比率を固定したままにすると、実際にはズームとビュー アングルが変更されます。射影行列の x および y 焦点値は、左/右および上/下で割った近平面によって計算されるためです。Matrix.frustumM の左、右、上、下は、実際には近平面の寸法です。

frustumM のソースコードはこちらです。焦点である x と y が、ファー プレーンではなくニア プレーンのみを使用して計算されていることがわかります。ズームまたは視野角を維持し、近面を変更したい場合は、元の近距離と新しい近深度。

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 に答える