繁体   English   中英

如何在OpenGL ES 2中正确缩放

[英]How to zoom properly in OpenGL ES 2

我在Android的OpenGL ES中有一个3D模型。 我已经实现了滑动手势来平移,旋转和缩放模型。 除了缩放外,其他所有功能都可以正常工作。 我不确定我缺少什么或必须更改什么,但是我无法放大模型。

该模型是建筑物。 我想做的是放大建筑物的不同楼层。 但是,无论我如何更改实现,我都无法做到这一点。

放大时建筑物消失了,或者缩放受到限制,因此我无法进一步放大...。

首先,我通过修改矩阵来减小视野:

frustumM(matrix, 0, -ratio/zoom, ratio/zoom, -1/zoom, 1/zoom, nearPlane, farPlane)

有人告诉我,这不是正确的方法,我应该修改eyeZ值,例如:

eyeZ = -1.0/zoom

第一种方法有效,但是我想知道第二种方法的错误之处,因为它有我一开始提到的问题。

我的渲染器类如下:

 public class MyGLRenderer implements GLSurfaceView.Renderer {

private float[] mModelMatrix = new float[16];
private final float[] mMVMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];

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

private float modelRatio = 1.0f;

private int offset = 0;
private float eyeX = 0;
private float eyeY = 0;
private float eyeZ = -1;
private float centerX = 0f;
private float centerY = 0f;
private float centerZ = 0f;
private float upX = 0f;
private float upY = 1.0f;
private float upZ = 0.0f;

private float mZoomLevel = 1f;

private float defaultRotationX = 100.0f; //building otherwise on the wrong side
private float defaultRotationZ = 180.0f; //building otherwise on the wrong side
private float rotationX = defaultRotationX;
private float rotationY = 0.0f;
private float rotationZ = defaultRotationZ;

private float translateX = 0.0f;
private float translateY = 0.0f;
private float translateZ = 0.0f;

private float scaleFactor = 20.0f; //no matter what scale factor -> it's not possible to zoom into the building...

private float ratio;
private float width;
private float height;

private List<IDrawableObject> drawableObjects;
public Model3D model3d;

public MyGLRenderer(Model3D model3d) {
    this.model3d = model3d;
    getModelScale();
}

private void getModelScale() {
    float highestValue = (model3d.width > model3d.height) ? model3d.width
            : model3d.height;
    modelRatio = 2f / highestValue;
}

@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    // Set the background frame color
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    GLES20.glDisable(GLES20.GL_CULL_FACE);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);

    drawableObjects = ... ; //to much detail, basically getting triangles
}

@Override
public void onDrawFrame(GL10 unused) {
    float[] mMVPMatrix = new float[16];

    // Draw background color
    Matrix.setIdentityM(mModelMatrix, 0);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    // model is in origin-solution too big
    Matrix.scaleM(mModelMatrix, 0, modelRatio * scaleFactor, modelRatio
            * scaleFactor, modelRatio * scaleFactor);

    Matrix.translateM(mModelMatrix, 0, translateX, translateY, translateZ);

    rotateModel(mModelMatrix, rotationX, rotationY, rotationZ, true);

    // 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
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVMatrix, 0);

    for (IDrawableObject d : drawableObjects) {
        d.draw(mMVPMatrix);
    }
}

private void rotateModel(float[] mModelMatrix, Float x, Float y, Float z,
        boolean rotateAroundCenter) {
    // translation for rotating the model around its center
    if (rotateAroundCenter) {
        Matrix.translateM(mModelMatrix, 0, (model3d.width / 2f), 0,
                (model3d.height / 2f));
    }
    if (x != null) {
        Matrix.rotateM(mModelMatrix, 0, x, 1.0f, 0.0f, 0.0f);
    }
    if (y != null) {
        Matrix.rotateM(mModelMatrix, 0, y, 0.0f, 1.0f, 0.0f);
    }
    if (z != null) {
        Matrix.rotateM(mModelMatrix, 0, z, 0.0f, 0.0f, 1.0f);
    }

    // translation back to the origin
    if (rotateAroundCenter) {
        Matrix.translateM(mModelMatrix, 0, -(model3d.width / 2f), 0,
                -(model3d.height / 2f));
    }
}

@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
    // Adjust the viewport based on geometry changes,
    // such as screen rotation
    GLES20.glViewport(0, 0, width, height);
    this.width = width;
    this.height = height;
    ratio = (float) width / height;
}

public static int loadShader(int type, String shaderCode) {
    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}

public int getFPS() {
    return lastMFPS;
}

public static void checkGlError(String glOperation) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
        Log.e(TAG, glOperation + ": glError " + error);
        throw new RuntimeException(glOperation + ": glError " + error);
    }
}

public void setZoom(float zoom) {
    this.mZoomLevel = zoom;
}

public void setDistance(float distance) {
    eyeZ = distance;
}

public float getDistance() {
    return eyeZ;
}

public float getRotationX() {
    return rotationX;
}

public void setRotationX(float rotationX) {
    this.rotationX = defaultRotationX + rotationX;
}

public float getRotationY() {
    return rotationY;
}

public void setRotationY(float rotationY) {
    this.rotationY = rotationY;
}

public float getRotationZ() {
    return rotationZ;
}

public void setRotationZ(float rotationZ) {
    this.rotationZ = defaultRotationZ + rotationZ;
}

public float getFarPlane() {
    return farPlaneDistance;
}

public float getNearPlane() {
    return nearPlaneDistance;
}

public void addTranslation(float mPosX, float mPosY) {
    this.translateX = mPosX;
    this.translateY = mPosY;
}

public void downPressed() {
    translateX -= 10;
}

public void upPressed() {
    translateX += 10;
}

public void actionMoved(float mPosX, float mPosY) {
    float translationX = (mPosX / width);
    float translationY = -(mPosY / height);
    addTranslation(translationX, translationY);
}

public float getmZoomLevel() {
    return mZoomLevel;
}

public void setmZoomLevel(float mZoomLevel) {
    this.mZoomLevel = mZoomLevel;
}

public float getWidth() {
    return width;
}

public float getHeight() {
    return height;
}

public void setTranslation(Float x, Float y, Float z) {
    if (x != null) {
        this.translateX = -x;
    }
    if (y != null) {
        this.translateY = y;
    }
    if (z != null) {
        this.translateZ = -z;
    }
}

public void setRotation(Float x, Float y, Float z) {
    if (x != null) {
        this.rotationX = defaultRotationX + x;
    }
    if (y != null) {
        this.rotationY = y;
    }
    if (z != null) {
        this.rotationZ = defaultRotationZ + z;
    }
}

public void setScale(float scale) {
    this.mZoomLevel = scale;
}

public float getDefaultRotationX() {
    return defaultRotationX;
}

}

您看到我目前正在做的任何错误吗? 您还可以查看github存储库: https : //github.com/Dalanie/OpenGL-ES/tree/master/buildingGL

首先,您必须定义“缩放”的含义。 在透视投影的情况下,有几种可能性:

  1. 您更改视场。 这类似于相机的变焦,变焦会导致更改焦距。
  2. 您只需在投影之前缩放模型。
  3. 您可以更改模型的距离(距离相机更近,可以放大,距离更远,可以缩小)

变体1是您通过更改视锥进行的操作。 我认为这是最直观的效果。 至少对于那些习惯了相机的人来说。 还请注意,这与放大2d投影图像的某些子矩形以填充整个屏幕的效果相同。

更改eyeZ是方法3。但是现在您必须小心,不要将对象移出查看空间(这似乎是您要描述的问题)。 理想情况下,您也可以在这里修改视锥。 但是为了保持视野,请在移动近/远平面时使对象始终停留在它们之间。 请注意,这需要更改所有6个视锥的值,保持不变的应该是left/nearright/neartop/nearbottom/near的比率,以保持以前的FOV /方面。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM