WedX - журнал о программировании и компьютерных науках

Перевернутая ось X OpenGL

Итак, я посмотрел небольшой вводный курс на YouTube, чтобы изучить основы OpenGL и узнал такие вещи, как создание треугольника и простой класс камеры и т. д. Я хотел попробовать и работать над созданием воксельного движка, поэтому, очевидно, первое, что я думал сделать простой куб, который я мог бы в конечном итоге воспроизвести. Моя проблема заключается в том, что когда я отрисовываю вершины и треугольники, они кажутся в беспорядке, который не похож на то, что я жестко закодировал в классе куба. Я знаю, что 0,0 — это центр экрана; 1 по оси абсцисс — справа; -1 — левый; 1 по оси Y — это верх, а -1 — это низ. Тем не менее, когда я отправляю свои вершины и треугольники в буфер вершин, кажется, что он делает что-то совершенно другое. Скорее всего, это действительно глупая ошибка с моей стороны.

Cube::Cube()
{
m_vertices[0] = Vertex(glm::vec3(-0.5, -0.5, 0));
m_vertices[1] = Vertex(glm::vec3(-0.5, 0.5, 0));
m_vertices[2] = Vertex(glm::vec3(0.5, 0.5, 0));
m_vertices[3] = Vertex(glm::vec3(0.5, -0.5, 0));
m_vertices[4] = Vertex(glm::vec3(-0.5, -0.5, 1));
m_vertices[5] = Vertex(glm::vec3(-0.5, 0.5, 1));
m_vertices[6] = Vertex(glm::vec3(0.5, 0.5, 1)); 
m_vertices[7] = Vertex(glm::vec3(0.5, -0.5, 1));

m_triangles[0] = Triangle(0, 1, 2); //Front
//m_triangles[1] = Triangle(0, 2, 3); //Front

//m_triangles[2] = Triangle(1, 5, 6); //Top
//m_triangles[3] = Triangle(1, 6, 2); //Top

//m_triangles[4] = Triangle(3, 5, 4); //Left
//m_triangles[5] = Triangle(3, 5, 4); //Left

//m_triangles[6] = Triangle(3, 2, 7); //Right
//m_triangles[7] = Triangle(3, 3, 7); //Right

//m_triangles[8] = Triangle(7, 6, 4); //Back
//m_triangles[9] = Triangle(5, 6, 7); //Back

//m_triangles[10] = Triangle(0, 4, 7); //Bottom
//m_triangles[11] = Triangle(0, 3, 7); //Bottom
}

void Cube::Render()
{
   Draw(m_vertices, sizeof(m_vertices) / sizeof(m_vertices[0]), m_triangles, (sizeof(m_triangles) / sizeof(m_triangles[0])));
}

Функция рисования, унаследованная от моего класса сетки

void Mesh::Draw(Vertex* vertices, unsigned int numVertices, Triangle* triangles, unsigned int numTriangles)
{
//Array of indices
std::vector<unsigned int> indices;
for (int i = 0; i < numTriangles; i++)
{
    indices.push_back(triangles[i].GetTriangle()[0]);
    indices.push_back(triangles[i].GetTriangle()[1]);
    indices.push_back(triangles[i].GetTriangle()[2]);
}

//How many vertices to draw
m_drawCount = indices.size();

//Generate and bind vertex array
glGenVertexArrays(1, &m_vertexArrayObject);
glBindVertexArray(m_vertexArrayObject);

//Generate and bind buffers
glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]);
//Write vertex data to the buffer
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);

//Only one attribute for the vertex data
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vertexArrayBuffers[INDEX_VB]);
//Write vertex data to the buffer
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), &indices[0], GL_STATIC_DRAW);

//Unbind vertex array
glBindVertexArray(0);

glBindVertexArray(m_vertexArrayObject);

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawElements(GL_TRIANGLES, m_drawCount, GL_UNSIGNED_INT, 0);

glBindVertexArray(0);
}

Структуры вершин и треугольников в mesh.h

struct Vertex
{
public:
//Constructor
Vertex()
{

}
//Constructor
Vertex(const glm::vec3& pos)
{
    //Set vertex position
    this->m_pos = pos;
}
protected:

private:
//Vertex position
glm::vec3 m_pos;
};

struct Triangle
{
public:
//Constructor
Triangle()
{

}

//Constructor
Triangle(int point1, int point2, int point3)
{
    SetTriangle(point1, point2, point3);
}

int* GetTriangle()
{
    return m_points;
}

void SetTriangle(int point1, int point2, int point3)
{
    m_points[0] = point1;
    m_points[1] = point2;
    m_points[2] = point3;
}
protected:

private:
int m_points[3];
};

Функции камеры

Camera::Camera(const glm::vec3 pos, float fov, float aspect, float zNear, float zFar)
{
m_perspectiveMatrix = glm::perspective(fov, aspect, zNear, zFar);
m_pos = pos;
m_forward = glm::vec3(0, 0, 1);
m_up = glm::vec3(0, 1, 0);
}

glm::mat4 Camera::GetViewProjection() const
{
 return m_perspectiveMatrix * glm::lookAt(m_pos, m_pos + m_forward, m_up);
}

Обратите внимание, что в конструкторе куба я создаю только один треугольник, который должен быть внизу слева, вверху слева, вверху справа, но вот результат:

Треугольник находится не там, где я его указал

Еще одно замечание: вращение моей камеры, похоже, тоже отключено. Изменение поворота y фактически вращает его по оси x, а изменение поворота x вращает по оси y.

Также, если у кого-то есть лучший способ создания и рендеринга куба, я был бы признателен. Как только я смогу это сделать, я, скорее всего, рассмотрю учебники letsmakeavoxelengine.

Редактировать: такое ощущение, что оси x и y перевернуты. Я мог бы просто инвертировать все свои функции, чтобы противостоять этому, но это своего рода хакерский способ обойти это, и он все еще не устраняет основную проблему, которая может вызвать больше проблем позже.

Редактировать2: Transform.h

#pragma once
#include <glm\glm.hpp>
#include <glm\gtx\transform.hpp>
#include "Camera.h"

struct Transform
{
public:
//Constructor
Transform(const glm::vec3& pos = glm::vec3(), const glm::vec3& rot = glm::vec3(), const glm::vec3& scale = glm::vec3(1.0f, 1.0f, 1.0f))
{
    this->m_pos = pos;
    this->m_rot = rot;
    this->m_scale = scale;
}

//Get the model matrix
inline glm::mat4 GetModelMatrix() const
{
    //Create all the transform matrices

    //Position matrix
    glm::mat4 posMatrix = glm::translate(m_pos);
    //Scale matrix
    glm::mat4 scaleMatrix = glm::scale(m_scale);
    //Rotation matrix X
    glm::mat4 rotXMatrix = glm::rotate(m_rot.x, glm::vec3(1.0f, 0.0f, 0.0f));
    //Rotation matrix Y
    glm::mat4 rotYMatrix = glm::rotate(m_rot.y, glm::vec3(0.0f, 1.0f, 0.0f));
    //Rotation matrix Z
    glm::mat4 rotZMatrix = glm::rotate(m_rot.z, glm::vec3(0.0f, 0.0f, 1.0f));
    //Combined rotation matrix
    glm::mat4 rotMatrix = rotXMatrix * rotYMatrix * rotZMatrix;

    return posMatrix * rotMatrix * scaleMatrix;
}

inline glm::mat4 GetMVP(const Camera& camera) const
{
    glm::mat4 ViewProjection = camera.GetViewProjection();
    glm::mat4 ModelMatrix = GetModelMatrix();

    return ViewProjection * ModelMatrix;//camera.GetViewProjection() * GetModel();
}

//Get position
inline glm::vec3* GetPosition() { return &m_pos; }
//Get rotation
inline glm::vec3* GetRotation() { return &m_rot; }
//Get scale
inline glm::vec3* GetScale() { return &m_scale; }

//Set Position
inline void SetPosition(const glm::vec3& pos) { this->m_pos = pos; }
//Set Rotation
inline void SetRotation(const glm::vec3& rot) { this->m_rot = rot; }
//Set Scale
inline void SetScale(const glm::vec3& scale) { this->m_scale = scale; }

private:
//Transform position
glm::vec3 m_pos;
//Transform rotation
glm::vec3 m_rot;
//Transform scale
glm::vec3 m_scale;
};

Вызовы Cube, Transform и Camera в main.cpp:

Cube cube;
Transform transform;
Camera camera(glm::vec3(0.0f, 0.0f, -3.0f), 70.0f, (float)display.GetWidth()/(float)display.GetHeight(), 0.01f, 100.0f);

Edit3: 100% перевернуто по оси X. Новый код cube.cpp:

m_vertices[0] = Vertex(glm::vec3(-0.5, -0.5, 0)); //BottomLeftFront
m_vertices[1] = Vertex(glm::vec3(-0.5, 0.5, 0)); //TopLeftFront
m_vertices[2] = Vertex(glm::vec3(0.5, 0.5, 0)); //TopRightFront
m_vertices[3] = Vertex(glm::vec3(0.5, -0.5, 0)); //BottomRightFront
m_vertices[4] = Vertex(glm::vec3(-0.5, -0.5, 1)); //BottomLeftBack
m_vertices[5] = Vertex(glm::vec3(-0.5, 0.5, 1)); //TopLeftBack
m_vertices[6] = Vertex(glm::vec3(0.5, 0.5, 1)); //TopRightBack
m_vertices[7] = Vertex(glm::vec3(0.5, -0.5, 1)); //BottomRightBack

m_triangles[0] = Triangle(0, 1, 2); //Front
m_triangles[1] = Triangle(0, 2, 3); //Front

//m_triangles[2] = Triangle(1, 5, 6); //Top
//m_triangles[3] = Triangle(1, 6, 2); //Top

m_triangles[4] = Triangle(3, 5, 4); //Left //BottomLeftFront, TopRightBack, BottomRightBack
//m_triangles[5] = Triangle(3, 5, 4); //Left

//m_triangles[6] = Triangle(3, 2, 7); //Right
//m_triangles[7] = Triangle(3, 3, 7); //Right

//m_triangles[8] = Triangle(7, 6, 4); //Back
//m_triangles[9] = Triangle(5, 6, 7); //Back

//m_triangles[10] = Triangle(0, 4, 7); //Bottom
//m_triangles[11] = Triangle(0, 3, 7); //Bottom

Я поместил комментарий рядом с новым треугольником, который говорит вам, каковы были фактически полученные точки треугольника. Треугольник, который я установил, должен был быть BottomRightFront, TopLeftBack, BottomLeftBack согласно коду. Я также добавлю скриншот того, как это выглядит.

Треугольник должен был быть BottomRightFront, TopLeftBack, BottomLeftBack


  • Можете ли вы предоставить полный образец, который компилируется? Обычно мы используем правостороннюю систему, поэтому, если ось x указывает вправо, а ось y указывает вверх, то ось z указывает назад (к камере); но ваши zNear и zFar положительны, а ваш m_forwards равен (0 0 1), а не (0 0 -1); это глм вещь? 05.09.2016
  • Я думаю, что это должно быть блестяще, потому что, глядя на источник видео, которое я смотрел, кажется, что это одно и то же. также как лучше всего отправить вам проект? Гугл Диск? Источник для класса камеры из видео здесь, между прочим: github.com/BennyQBD/ModernOpenGLTutorial /blob/master/camera.h 05.09.2016
  • Ваша позиция имеет отрицательную координату z? Если нет, то, возможно, проблема в этом. Но опять же, возможно, нет, потому что если проблема именно в этом, то я ожидаю, что изображение будет перевернуто по горизонтали и по вертикали. 05.09.2016
  • Я думаю, что изображение перевернуто по обеим осям, но это зависит от того, о какой переменной pos вы говорите, у меня есть одна для моего transform.h и camera.h. Я добавлю код в основной вопрос. 05.09.2016
  • Извините, я не заметил вашего вопроса ранее, о том, как лучше отправить проект. В идеале весь код должен быть в вопросе, но я понимаю, что OpenGL и небольшой полный образец не очень хорошо сочетаются! Хотел бы я знать, какое рекомендуемое решение для StackOverflow. 05.09.2016
  • Я бы поместил все это в код, но форматирование кода, похоже, работает не очень хорошо и требует, чтобы я прошел и добавил пробелы в кучу строк, так как я не могу правильно использовать табуляцию. Я посмотрю, есть ли способ отправить мой проект 05.09.2016
  • Вызов glm::lookAt в Camera::GetViewProjection выглядит подозрительно; в частности, у вас есть центр (второй аргумент) позади глаза (первый аргумент), так как m_forwards указывает назад. 05.09.2016
  • Я попытался переключить их, потому что я не мог видеть треугольник, когда делал это, плюс в исходном коде руководств он такой же: github.com/BennyQBD/ModernOpenGLTutorial/blob/master/ Кстати, я просто хотел сказать спасибо за помощь, которую вы оказываете, это очень много значит! 05.09.2016
  • Не за что! Попробуйте lookAt с (0 0 0) для глаза, m_pos для центра и (0 1 0) для вверх? 05.09.2016
  • return m_perspectiveMatrix * glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), m_pos, glm::vec3(0.0f, 1.0f, 0.0f)); Нравится? Если да, то я не мог видеть треугольник. 05.09.2016
  • Да, это то, что я имел в виду. :( 05.09.2016
  • Хорошо, так что это 100% инвертировано по оси X. Я только что попробовал другой треугольник, результаты которого я добавлю в основной пост. 05.09.2016
  • Я должен оставить вас с этим на данный момент. Я надеюсь, что вы найдете свой ответ. Прекрасно, что вы хотите понять это, а не идти по хакерскому пути. Удачи! 05.09.2016
  • Большое спасибо! Я думаю, что вы были на правильном пути с отрицательной осью Z, так что большое спасибо за помощь, я действительно ценю это! 05.09.2016
  • И это исправлено. Большое спасибо, Бастер, то, что ты сказал, было правильно. Мне пришлось вернуться, изменив вместо этого прямое значение на -1, а затем изменить каждую из обратных вершин кубов на z=1 вместо z=-1. Наконец, я изменил z камеры на положительное значение, и оно было исправлено. У меня была последняя проблема, которая заключалась в том, что треугольники теперь отбрасывались не с той стороны, что означало, что мне пришлось перерисовывать их против часовой стрелки. Бастер, если вы добавите один из своих комментариев в качестве ответа, я приму его, большое спасибо. 05.09.2016
  • @therealkf: Можно ответить на свой вопрос. Неправильно помещать ответ в свой вопрос. Напишите как ответ. 05.09.2016

Ответы:


1

Ваше описание осей X и Y звучит правильно, но ось Z кажется перевернутой. Например, в опубликованном вами коде есть переменная m_forward, значение которой равно (0, 0, 1); это может быть правильным, но я обычно называю это направление "назад".

Обычно программы OpenGL используют правостороннюю систему координат, поэтому, если X указывает вправо, а Y указывает вверх, то Z указывает за пределы экрана к глазу. Если вы помните об этом и просматриваете свой код, проверяя знак компонента Z каждой позиции и вектора направления, вы должны найти ошибку (ошибки). Удачи!

05.09.2016
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]