OpenGLES20视图因应用旋转矩阵而失真

时间:2014-02-25 13:04:34

标签: android opengl-es rotation

现在看起来如何看的视频:

http://de.tinypic.com/r/2504bh5/8

我在我的视图矩阵中应用了一个旋转矩阵:

    float[] mTmpMatrix = new float[16];
    Matrix.setLookAtM(mTmpMatrix, 0, // mViewMatrix
            mCameraPosition[0], mCameraPosition[1], mCameraPosition[2], // eye
            mTargetRotPosition[0], mTargetRotPosition[1], mTargetRotPosition[2],
            0, 1, 0); // up
    Matrix.multiplyMM(mViewMatrix, 0, mRotationMatrix, 0, mTmpMatrix, 0);

让OpenGL视图相应于设备的方向旋转,以创建某种增强现实。旋转矩阵由传感器融合(磁力,加速度计,陀螺仪)计算,并且运行良好。

我现在遇到的问题如下:如果我旋转设备,屏幕,更好的是我正在绘制的物体,会扭曲,这应该是沿Z轴的旋转。

以下图片应该给出我正在谈论的内容的某种印象:

enter image description here

enter image description here

当我在相机周围绘制的矩形天花板上看“向上”时。屋顶突然变成了一个正方形,仍然适合屏幕,但我不知道为什么以及如何防止这种情况发生,因为如果我,而不是旋转视图矩阵,将旋转线,这不应该发生

为了完成起见,Line.class:

http://pastebin.com/GQszFEPm

Frustum设置(用于测试目的的FoV,我使用此值进行了一些实验,但没有效果)

@Override
public void onSurfaceChanged(GL10 arg0, int width, int height) {
    this.width = width;
    this.height = height;
    GLES20.glViewport(0, 0, width, height);
    if (height > width)
        setFrustumVertical(100f, (float) height / (float) width, 0.01f, 11f);
    else setFrustumHorizontal(100f, (float) width / (float) height, 0.01f, 11f);
}

辅助方法,我改编自教程:

private void setFrustumHorizontal(float fov, float aspect, float front, float back) {
    fov = (float) Math.toRadians(fov);                      // transform fov from degrees to radians
    fov = 2.0f * (float) Math.atan(Math.tan(fov * 0.5f) / aspect);  // transform from horizontal fov to vertical fov

    float tangent = (float) Math.tan(fov / 2.0f);               // tangent of half vertical fov
    float height = front * tangent;                 // half height of near plane
    float width = height * aspect;                  // half width of near plane

    setFrustum(-width, width, -height, height, front, back);
}

private void setFrustumVertical(float fov, float aspect, float front, float back) {
    fov = (float) Math.toRadians(fov);                      // transform fov from degrees to radians

    float tangent = (float) Math.tan(fov / 2.0f);               // tangent of half vertical fov
    float height = front * tangent;                 // half height of near plane
    float width = height * aspect;                  // half width of near plane

    setFrustum(-width, width, -height, height, front, back);
}

private void setFrustum(float left, float right, float bottom, float top, float near, float far) {
    Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}

3 个答案:

答案 0 :(得分:2)

在将mViewMatrix设置为mRotationMatrix * mTmpMatrix的行之前,将mViewMatrix设置为identity。

答案 1 :(得分:2)

您的错误很可能在这里:

setFrustumVertical(100f, height / width, 0.01f, 11f);

因为高度和宽度是整数,高度> width(&& height< 2 * width)结果将始终为1.尝试在分割之前将它们转换为

setFrustumVertical(100f, (float)height / (float)width, 0.01f, 11f);

答案 2 :(得分:1)

我认为setFrustumVertical()存在问题。让我们假设您的屏幕是100 x 200并且是纵向的(因此它的宽度是它的两倍)。由于高度>您将调用的宽度:

setFrustumVertical(100f, 2, 0.01f, 11f)

如果你使用这些值运行该方法(我在这里使用的是度数而不是弧度但是数学是相同的):

fov = 100 degrees
tangent = tan(100 / 2) = 1.191
height = 0.01 x 1.191 = 0.01191
width = 0.01191 x 2 = 0.02382
setFrustrum(-0.02382, 0.02382, -0.01191, 0.01191, 0.01, 11)

注意截头体的高度是它的两倍?那是回到前面 - 它应该是纵向宽度的两倍。切换宽度和高度:

float width = front * tangent;
float height = height * aspect;

或者宽度应该改为:

float width = height / aspect;

如果您在横向上遇到类似的问题,请手动干燥另一种方法,以确保它创建具有正确宽高比的截头体。