更改相机的前向矢量在 Android openGL 中会产生奇怪的结果

Changing camera's forward vector has strange results in Android openGL

我正在尝试使用 OpenGL 库创建 3D Android 游戏。据我所知,Android 平台(或 OpenGL)不提供相机对象,所以我自己制作了一个。我设法创建了一个在屏幕上绘制的正方形。我还设法让相机在所有 3 个方向上毫无问题地移动。我遇到的问题是当我在 x 或 y 轴上转动相机时,正方形以一种非常奇怪的方式显示。它似乎高度扭曲了它的观点。这是一些图片

相机原点向前看:位置 [0,0,0.55f],向前 [0,0,-1],向上 [0,1,0]

相机向右移动:位置 [3,0,0.55f],向前 [0,0,-1],向上 [0,1,0]

镜头稍微向右转:位置 [0,0,0.55f],向前 [0.05f,0,-1],向上 [0,1,0]

我不确定问题是从哪里产生的。这是正方形的顶点:

static float vertices[] = {
        // Front face (CC order)
        -1.0f,  1.0f, 1.0f,   // top left
        -1.0f, -1.0f, 1.0f,   // bottom left
         1.0f, -1.0f, 1.0f,   // bottom right
         1.0f,  1.0f, 1.0f,   // top right
};

据我所知,我的矩阵乘法顺序正确。我将矩阵传递给顶点着色器并在那里进行乘法运算:

private final String vertexShaderCode =
        "uniform mat4 uVMatrix;" +
        "uniform mat4 uMMatrix;" +
        "uniform mat4 uPMatrix;" +
        "attribute vec4 aVertexPosition;" +     // passed in
        "attribute vec4 aVertexColor;" +
        "varying vec4 vColor;" +
        "void main() {" +
        "  gl_Position = uPMatrix * uVMatrix * uMMatrix * aVertexPosition;" +
        "  vColor = aVertexColor;" +    // pass the vertex's color to the pixel shader
        "}";

模型矩阵只是将它移动到原点并使其缩放 1:

Matrix.setIdentityM(ModelMatrix, 0);
Matrix.translateM(ModelMatrix, 0, 0, 0, 0);
Matrix.scaleM(ModelMatrix, 0, 1, 1, 1);

我使用我的相机对象来更新视图矩阵:

Matrix.setLookAtM(ViewMatrix, 0,
            position.x, position.y, position.z,
            position.x + forward.x, position.y + forward.y, position.z + forward.z,
            up.x, up.y, up.z);

这是我的投影矩阵:

float ratio = width / (float) height;

Matrix.frustumM(ProjectionMatrix, 0, -ratio, ratio, -1, 1, 0.01f, 10000f);

我错过了什么?

根据您的设置,您的顶点缓冲区可能有误。你的顶点数组是一个 vec3。而你shader中的属性position是一个vec4.

你的投影矩阵也很奇怪,根据你想要的宽高比,你会得到奇怪的结果。

您应该改用 perspectiveM。

用你传递给frustrumM()的参数:

Matrix.frustumM(ProjectionMatrix, 0, -ratio, ratio, -1, 1, 0.01f, 10000f);

你有非常强烈的观点。这就是为什么只要稍微旋转一下几何图形就会看起来非常扭曲的原因。

底部顶部 值是在近裁剪平面的深度处测量的距离。因此,例如,对于您的 top 值为 1.0,near 值为 0.01,视图体积的顶平面将移动距离为 1.0远离观察方向,向前距离为 0.01.

算一算,atan(top / near) = atan(1.0 / 0.01) = atan(100.0) = 89.42 度,垂直视角的一半,或整个视角的 178.85 度,对应到相机上的极端鱼眼镜头,几乎覆盖了相机前面的整个space。

要使用更合理的视角,您可以根据所需的视角计算值。 alpha 为垂直视角:

float near = 0.01f;
float top = tan(0.5f * alpha) * near;
float right = top * ratio;
Matrix.frustumM(ProjectionMatrix, 0, -right, right, -top, top, near, 10000f);

从 45 到 60 度范围内的视角开始,以获得总体上令人愉悦的视角。请记住,上面使用的 tan() 函数以弧度为单位获取角度,因此如果您的原始角度以度为单位,则必须先转换它。

或者,如果您害怕数学,可以随时使用 perspectiveM()。 ;)