2

我正在使用 opengl-es 2.0 开发一个项目,但在设置透视投影时遇到了一些麻烦。

如果我不设置透视投影并简单地将对象到世界矩阵(我相信它也称为模型矩阵)乘以顶点位置,则屏幕上的对象会正确渲染,它们看起来会被拉伸,但就我知道,这是投影矩阵可以解决的问题。问题是,每当我设置透视矩阵并使用它时,屏幕上的对象就会消失,无论我如何移动它们,它们都不会出现在屏幕上。

获得模型-视图-投影矩阵的计算是在 CPU 中完成的,MVP-Matrix 与实际对象空间顶点数据的最后一次乘法是在顶点着色器中完成的,这就是为什么我认为问题可能出在过程中得到那个MVP-Matrix。我已经运行了一堆单元测试,但是根据这些测试(以及我对线性代数的基本知识),这些矩阵正在被正确计算,而我整天的互联网研究目前没有帮助。:-/

这是我用来计算 MVP 矩阵的代码:

Matrix4D projection_matrix;
projection_matrix.makePerspective(45.0f, 0.001f, 100.0f, 480.0f/320.0f);

Matrix4D view_matrix;
view_matrix.makeIdentity(); //Should be a real view matrix. TODO.

Matrix4D model_matrix(getWorldMatrix());

Matrix4D mvp_matrix(projection_matrix);
mvp_matrix *= view_matrix;
mvp_matrix *= model_matrix;

mMesh->draw(time, mvp_matrix.getRawData());

我认为这段代码是不言自明的,但以防万一,那些 Matrix4D 是 4x4 矩阵,并且在它们上调用 makePerspective/makeIdentity 将使该矩阵成为 Perspective 或 Identity 矩阵。对 Matrix4D 对象的 getRawData() 调用以列优先表示法的浮点数组形式返回矩阵数据,而 mMesh 变量是另一个对象,当调用 draw 时,它将简单地将所有顶点和材质数据发送到着色器。

makePerspective 函数的代码如下:

Matrix4D& Matrix4D::makePerspective(const float field_of_view, 
        const float near, const float far, const float aspect_ratio) {
    float size = near * tanf(DEGREES_TO_RADIANS(field_of_view) / 2.0f); 

    return this->makeFrustum(-size, size, -size / aspect_ratio,
             size / aspect_ratio, near, far);
}

Matrix4D& Matrix4D::makeFrustum(const float left, const float right, 
        const float bottom, const float top, const float near, 
        const float far) {
    this->mRawData[0] = 2.0f * near / (right - left);  
    this->mRawData[1] = 0.0f; 
    this->mRawData[2] = 0.0f; 
    this->mRawData[3] = 0.0f;

    this->mRawData[4] = 0.0f; 
    this->mRawData[5] = 2.0f * near / (top - bottom); 
    this->mRawData[6] = 0.0f; 
    this->mRawData[7] =  0.0f;

    this->mRawData[8] = (right + left) / (right - left);
    this->mRawData[9] = (top + bottom) / (top - bottom); 
    this->mRawData[10] = - (far + near) / (far - near); 
    this->mRawData[11] = -1.0f;

    this->mRawData[12] = 0.0f; 
    this->mRawData[13] = 0.0f; 
    this->mRawData[14] = -2.0f * far * near / (far - near); 
    this->mRawData[15] = 0.0f;

    return *this;
}

getWorldMatrix() 调用执行此操作(带有一些相关代码):

const Matrix4D& getWorldMatrix() {
    return mWorldMatrix = 
            getTranslationMatrix() *
            getRotationMatrix() *
            getScaleMatrix();
}

const Matrix4D& getRotationMatrix() {
    return this->mRotationMatrix.makeRotationFromEuler(this->mPitchAngle,
        this->mRollAngle, this->mYawAngle);
}

const Matrix4D& getTranslationMatrix() {
    return this->mTranslationMatrix.makeTranslation(this->mPosition.x,
        this->mPosition.y, this->mPosition.z);
}

const Matrix4D& getScaleMatrix() {
    return this->mScaleMatrix.makeScale(this->mScaleX, this->mScaleY, this->mScaleZ);
}


///This code goes in the Matrix4D class.
Matrix4D& Matrix4D::makeTranslation(const float x, const float y, 
        const float z) {
    this->mRawData[0] = 1.0f; 
    this->mRawData[1] = 0.0f; 
    this->mRawData[2] = 0.0f; 
    this->mRawData[3] = 0.0f;

    this->mRawData[4] = 0.0f; 
    this->mRawData[5] = 1.0f; 
    this->mRawData[6] = 0.0f; 
    this->mRawData[7] = 0.0f;

    this->mRawData[8] = 0.0f; 
    this->mRawData[9] = 0.0f; 
    this->mRawData[10] = 1.0f; 
    this->mRawData[11] = 0.0f;

    this->mRawData[12] =    x; 
    this->mRawData[13] =    y; 
    this->mRawData[14] =    z; 
    this->mRawData[15] = 1.0f;

    return *this;
}

Matrix4D& Matrix4D::makeScale(const float x, const float y, 
        const float z) {
    this->mRawData[0] =    x; 
    this->mRawData[1] = 0.0f; 
    this->mRawData[2] = 0.0f; 
    this->mRawData[3] = 0.0f;

    this->mRawData[4] = 0.0f; 
    this->mRawData[5] =    y; 
    this->mRawData[6] = 0.0f; 
    this->mRawData[7] = 0.0f;

    this->mRawData[8] = 0.0f; 
    this->mRawData[9] = 0.0f; 
    this->mRawData[10] =    z; 
    this->mRawData[11] = 0.0f;

    this->mRawData[12] = 0.0f; 
    this->mRawData[13] = 0.0f; 
    this->mRawData[14] = 0.0f; 
    this->mRawData[15] = 1.0f;

    return *this;
} 

Matrix4D& Matrix4D::makeRotationFromEuler(const float angle_x, 
        const float angle_y, const float angle_z) {
    float a = cosf(angle_x);
    float b = sinf(angle_x);
    float c = cosf(angle_y);
    float d = sinf(angle_y);
    float e = cosf(angle_z);
    float f = sinf(angle_z);
    float ad = a * d;
    float bd = b * d;

    this->mRawData[0] = c * e;
    this->mRawData[1] = -bd * e + a * f;
    this->mRawData[2] = ad * e + b * f;
    this->mRawData[3] = 0.0f;

    this->mRawData[4] = -c * f; 
    this->mRawData[5] = bd * f + a * e;
    this->mRawData[6] = -ad * f + b * e; 
    this->mRawData[7] = 0.0f;

    this->mRawData[8] = -d; 
    this->mRawData[9] = -b * c;
    this->mRawData[10] = a * c; 
    this->mRawData[11] = 0.0f;

    this->mRawData[12] = 0.0f; 
    this->mRawData[13] = 0.0f;
    this->mRawData[14] = 0.0f; 
    this->mRawData[15] = 1.0f;

    return *this;
}

最后,顶点着色器几乎是这样的:

#version 110

const float c_one = 1.0;
const float c_cero = 0.0;

uniform float time;
uniform mat4 mvp_matrix;

attribute vec3 position;
attribute vec3 normal;
attribute vec2 texture_coordinate;

varying vec2 v_texture_coordinate;

void main()
{   
    gl_Position = mvp_matrix * vec4(position, c_one);
    v_texture_coordinate = texture_coordinate;
}

以防万一,正在渲染的对象在位置 (0.0f, 0.0f, -3.0f) 上渲染,所有三个轴都应用了 0.5f 比例。

我真的不知道可能出了什么问题,我希望有人能发现我可能缺少的东西,任何帮助将不胜感激。如果我可以在着色器上获得每个顶点的结果,那么调试会容易得多:-/。

作为旁注,我对如何计算视图或相机矩阵有疑问,据我所知,它只是一个带有相机必须做的倒置变换的矩阵,我理解这样的事情,如果我想将相机向右移动 100 个单位,我将它向左移动 100 个单位,对吗?

编辑:只是想提供更多信息,也许这样有人可以帮助我。我注意到模型矩阵与上面的代码不正确,主要是因为矩阵顺序,我已将其更改为以下,现在模型矩阵看起来不错:

const Matrix4D& getWorldMatrix() {
    return mWorldMatrix = 
            getScaleMatrix() * getRotationMatrix() * getTranslationMatrix();
}

尽管如此,仍然没有运气。我的测试数据产生的矩阵如下:

Projection matrix:
[1.609506,0.000000,0.000000,0.000000]
[0.000000,2.414258,0.000000,0.000000]
[0.000000,0.000000,-1.000020,-0.002000]
[0.000000,0.000000,-1.000000,0.000000]



Model matrix:
[0.500000,0.000000,0.000000,0.000000]
[0.000000,0.500000,0.000000,0.000000]
[0.000000,0.000000,0.500000,-3.000000]
[0.000000,0.000000,0.000000,1.000000]



MVP matrix:
[0.804753,0.000000,0.000000,0.000000]
[0.000000,1.207129,0.000000,0.000000]
[0.000000,0.000000,2.499990,-0.001000]
[0.000000,0.000000,-1.000000,0.000000]

我用来测试所有这些的网格是一个简单的立方体,每个轴上从 1.0f 到 -1.0f,以原点为中心。据我所知,这应该将最接近极限 (0.0001f) 的顶点定位在沿 z 轴的位置 -2.0f 上,因此立方体位于相机前面并带有视锥。任何线索有人吗?

4

0 回答 0