OpenGL рисует прямоугольник, заполняющий окно - PullRequest
1 голос
/ 16 апреля 2020

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

Скажем, у моего прямоугольника есть эти координаты:

GLfloat vertices[] = {
    -1.0f,  1.0f,  0.0f, // Top-left
     1.0f,  1.0f,  0.0f, // Top-right
     1.0f, -1.0f,  0.0f, // Bottom-right
    -1.0f, -1.0f,  0.0f, // Bottom-left
};

Вот мои 2 треугольника:

GLuint elements[] = {
    0, 1, 2,
    2, 3, 0
};

Если я нарисую прямоугольник с идентичными матрицами MVP, он заполняет экран, как и ожидалось. Теперь я хочу использовать усеченный конус. Вот его настройки:

float m_fov = 45.0f;
float m_width = 3840;
float m_height = 2160;
float m_zNear = 0.1f;
float m_zFar = 100.0f;

Из этого я могу вычислить ширину / высоту моего окна в z-near & z-far:

float zNearHeight = tan(m_fov) * m_zNear * 2;
float zNearWidth = zNearHeight * m_width / m_height;
float zFarHeight = tan(m_fov) * m_zFar * 2;
float zFarWidth = zFarHeight * m_width / m_height;

Теперь я могу создать свой вид & матрицы проекции:

glm::mat4 projectionMatrix = glm::perspective(glm::radians(m_fov), m_width / m_height, m_zNear, m_zFar);
glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -m_zNear));

Теперь я ожидаю, что мой прямоугольник заполнит окно:

glm::mat4 identity = glm::mat4(1.0f);
glm::mat4 rectangleModelMatrix = glm::scale(identity, glm::vec3(zNearWidth, zNearHeight, 1));

Но при этом мой прямоугольник слишком большой. Что я пропустил?


РЕШЕНИЕ: как указывал @ Rabbid76, проблема заключалась в вычислении моего размера z-near, который должен быть:

float m_zNearHeight = tan(glm::radians(m_fov) / 2.0f) * m_zNear * 2.0f;
float m_zNearWidth = m_zNearHeight * m_width / m_height;

Также я Теперь нужно указать координаты моего объекта в нормализованном пространстве вида ([-0,5, 0,5]), а не в пространстве устройства ([-1, 1]). Таким образом, мои вершины теперь должны быть:

GLfloat vertices[] = {
    -0.5f,  0.5f,  0.0f, // Top-left
     0.5f,  0.5f,  0.0f, // Top-right
     0.5f, -0.5f,  0.0f, // Bottom-right
    -0.5f, -0.5f,  0.0f, // Bottom-left
};

1 Ответ

1 голос
/ 16 апреля 2020

Спроецированная высота объекта на плане, параллельном плоскости xy вида, равна

h' = h * tan(m_fov / 2) / -z

где h - высота объекта на плоскости, -z - глубина, m_fov - угол поля зрения.

В вашем случае m_fov - 45 °, а -z - - 0,1 (-m_zNear), то есть tan(m_fov / 2) / z составляет ~ 4,142.
Поскольку высота квадра равна 2, прогнозируемая высота квада составляет ~ 8,282.

Чтобы создать квад, который точно соответствует в области просмотра используйте поле угла обзора 90 ° и расстояние до объекта 1, поскольку tan(90° / 2) / 1 равно 1. Например:

float m_fov = 90.0f;
glm::mat4 projectionMatrix = glm::perspective(glm::radians(m_fov), m_width / m_height, m_zNear, m_zFar);
glm::mat4 viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));

Если tan(m_fov / 2) == -z, то объект с нижняя часть -1 и верхняя часть 1 вписываются в область просмотра.
Из-за деления на z проецируемый размер объекта на области просмотра уменьшается линейно на расстоянии до камеры.

...