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

Frame91
  • 3,670
  • 8
  • 45
  • 89
  • Still don't get why I was downvoted for this. I have a clear question, provide my requirements and just want to know, how I can achieve this... There is a huge lack of documentations for this specific problem... – Frame91 Dec 12 '13 at 00:00
  • 2
    Yeah frame agree on your point. Lot of people here down-vote without understanding questions. – nilkash Dec 17 '13 at 05:45
  • Based on your pictures, you don't need to zoom--you just need to move the camera closer. Try setting a super tiny near frustrum. And judging from your model complexity, I don't think you need to be adjusting/readjusting the near frustrum. Just pick a super small value and stick with it. I don't know what scale your model is at, but you can try whatever your building's wall height is divided by 1000 or 10,000. – Tenfour04 Jan 07 '14 at 19:01
  • Hey, thanks! What do you mean by "moving the camera closer" ? Shall I translate the z-value of the model or do I have to change eyeZ ? In addition to this, when I change my near frustum to 0.0001 for example, the whole model is somehow "stretched" and I cant see anything clear :/ – Frame91 Jan 08 '14 at 00:11
  • Sorry, just saw your comment. I'm not sure about the specifics of the Matrix class you're using for the camera, but you just have to change the camera matrix's position in the z direction (not the model position). If your model is getting stretched by changing the frustrum, there is a bug in either the Matrix class, your vertex shader, or your model's translation code (that modifies its vertex positions). – Tenfour04 Jan 13 '14 at 13:55

2 Answers2

1

One of my solutions (not working very good):

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

But this is not the best approach (see coments below this answer)

Frame91
  • 3,670
  • 8
  • 45
  • 89
  • Although this solves your issue it is a bad solution. What you did there is decreased the field of view. LookAt should do the trick if used correctly. If your model is at (0,0,0) and your starting eyeZ is -1.0 then putting eyeZ to -1.0/zoom should do the job. Generally having current eye vector "eye0" and object position at "T0" you should implement zoom as eye = T0 + (eye0-T0)/zoom. – Matic Oblak Dec 12 '13 at 12:05
  • Thanks! I'll try it out tmw morning ;) – Frame91 Dec 12 '13 at 12:21
  • Hey, Look-At makes some troubles because of the field of view... I can't zoom very far into my object... it disappears because of the near-field plane (i tried to change the value of the plane... but it's not working very well) – Frame91 Dec 13 '13 at 00:20
  • 1
    Your nearPlaneDistance and farPlaneDistance define the clipping. It is best to define parameters "near", "far and "angle". Then to get those "left", "right".. parameters you use dimension = near * tan(angle) * .5. Then use Matrix.frustumM(mProjectionMatrix, 0, -ratio / zoom * dimension, ratio / zoom * dimension, -1 / zoom * dimension, 1 / zoom * dimension, nearPlaneDistance, farPlaneDistance); – Matic Oblak Dec 13 '13 at 07:32
  • Hi, I recently changed the zooming. It's now via the suggested eyeZ ? -1.0/zoom. However I'm still not able to zoom into my model (it just stops zooming right before I would "enter" the model. I tried to scale the model a bit bigger but with no difference. How can I solve this?... I've uploaded an example to the following repository: https://github.com/Dalanie/OpenGL-ES/tree/master/buildingGL/ – Frame91 Dec 15 '13 at 13:56
  • You are not suppose to zoom. On the contrary, you are suppose to not change the zoom. Just move your camera closer and adapt the near plane but maintain the zoom(by dividing the new and old near plane ratio). – user1097185 Jan 07 '14 at 18:31
  • Hey, could you describe what you mean by adapt the near plane? Shall I change the near plane? And where do I have to "maintain the zoom" - where do I should add the ratio? – Frame91 Jan 08 '14 at 00:17
0

I am confused about your "zooming" or you are confused about it. When you move the View matrix(changing eyeZ) you don't zoom in or out, you just move the camera. Yes, moving the camera closer to an object will make it look bigger(in case of perspective projection) but it's not zooming. You zoom by changing the focal length or view angle of the camera. You change the "persepectiveness" of your camera. Just like if you have a real camera simply walking toward your subject of photography is different than using the camera's zoom(Assuming it has a mechanical zoom).

In order to really zoom on something(if that is actually what you want) you will have to change the "ratio" in Matrix.frustumM. So you can make objects "become bigger" on the screen without having to worry about the object being clipped by the near plane. However, it will also change the perspective. The more you zoom the more it will look like orthographic projection.

I think what you are trying to achieve is flying inside a model of a building. For that you don't need to dynamically adjust the zoom of the camera. But you do need to adjust the front and end planes.

I think I know what is the source of your confusion. When you change the near plane of the frustum but keep the ratio fixed, you actually change the zoom and view angle. Because the projection matrix's x and y focal values are calculated by the near plane divided by the left/right and top/bottom. The left, right and top, bottom in Matrix.frustumM are actually the dimensions of the near plane.

Here is the source code of frustumM. You can see x and y which are the focal point are calculated using only the near plane and not the far plane. If you want to maintain the zoom or viewing angle and change the near plane, you will have to multiply left, right(ratio in your case) and top, bottom(1 in your case) by the ratio between the original near depth and the new near depth.

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;
}
user1097185
  • 1,058
  • 3
  • 13
  • 28
  • Thanks for your comment! I've updated my question to show you my problem. I actually don't know if I have to zoom or to scale or to move my camera for the desired result :( Cheers! – Frame91 Jan 07 '14 at 08:41
  • Well, translating z works fine. But when I rotate my model, the axis are swapped so that z doesn't move nearer to my object but the the side for example... If I don't rotate it works good... – Frame91 Jan 08 '14 at 12:09
  • I am guessing that is because your model is no longer aligned to the z-axis? Not sure why you would rotate the model and not the camera? – user1097185 Jan 17 '14 at 23:31