Настройка перспективной проекции в Opengl ES 2.0 приводит к исчезновению объектов - PullRequest
2 голосов
/ 15 августа 2011

Я работаю над проектом, использующим opengl-es 2.0, и у меня возникли проблемы с настройкой перспективного проецирования.

Если я не настроил перспективную проекцию и просто умножил матрицу объекта на мир (я полагаю, это также называется матрицей модели) на позиции вершин, объекты на экране отображаются правильно, они выглядят растянутыми, но насколько я знаю, это то, что матрица проекции исправит. Проблема в том, что всякий раз, когда я устанавливаю матрицу перспективы и использую ее, объекты на экране исчезают, и независимо от того, насколько я их перемещаю, они никогда не появляются на экране.

Расчеты для получения матрицы Model-View-Projection выполняются в CPU, а последнее умножение MVP-Matrix на фактические данные вершин объектного пространства выполняется в вершинном шейдере, поэтому я считаю, что проблема может быть в процессе, чтобы получить эту MVP-матрицу. Я провел несколько модульных тестов, но согласно этим тестам (и моим базовым знаниям в области линейной алгебры) эти матрицы рассчитываются правильно, и мои интернет-исследования в течение дня пока не помогают. : - /

Это код, который я использую для расчета 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 для них сделает эту матрицу матрицей перспективы или идентичности. Вызов getRawData () для объектов Matrix4D возвращает данные матрицы в виде массива с плавающей точкой в ​​основной записи столбца, а переменная 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), в позиции -2,0f вдоль оси z, поэтому куб находится перед камерой и находится внутри усеченного взгляда. У кого-нибудь есть подсказки?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...