Я работаю над проектом, использующим 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, поэтому куб находится перед камерой и находится внутри усеченного взгляда. У кого-нибудь есть подсказки?