Данный урок основан на предыдущем уроке.
Запустите приложение, которое вы только что создали. Вы увидите два окна: окно консоли и окно OpenGL. Теперь измените размер окна так, чтобы высота не соответствовала ширине. Треугольник исказится. Это происходит потому, что мы не настроили перспективное окно правильно. По умолчанию, пропорции отображаемых элементов, соответсвуют 1 к 1 ширины к высоте. Таким образом, когда соотношение изменяется, перспектива искажается. GLUT предлагает способ определить, в виде функции, вызываемой для изменения размеров окна, то есть для регистрации обратного вызова для повторного вычисления перспективы. Функция вызывается при создании окна и каждый раз при изменении размеров окна.
Окно, создаваемое по умолчанию.
Окна, с изменёнными пропорциями окна при растягивании по горизонтали и вертикали.
Зарегистрируем для GLUT функцию обратного вызова glutReshapeFunc.
void glutReshapeFunc(void (*func)(int width, int height));
Параметры:
*func - имя функции, которая будет отвечать за определение правильной перспективы, когда размер окна меняется.
Итак, что мы должны сделать, это вернуться к функции main из прошлого урока, и добавим вызов glutReshapeFunc. Давайте назовем нашу собственную функцию, следящую за изменениями размера окна ChangeSize. Код функции main с вызовом glutReshapeFunc добавлены в это:
int main(int argc, char **argv) { // инициализация glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(400,400); glutCreateWindow("Урок 2"); // регистрация glutDisplayFunc(renderScene); // Новая функция изменения размеров окна glutReshapeFunc(changeSize); // основной цикл glutMainLoop(); return 1; }
Следующее, что нам нужно сделать, это определить функцию, следящую за перспективой. Как видно по синтаксису glutReshapeFunc, ChangeSize функция имеет два аргумента, это новые значения ширины и высоты, соответственно, клиентской области окна, то есть без оформления окон.
void changeSize(int w, int h) { // предупредим деление на ноль // если окно сильно перетянуто будет if(h == 0) h = 1; float ratio = 1.0* w / h; // используем матрицу проекции glMatrixMode(GL_PROJECTION); // Reset матрицы glLoadIdentity(); // определяем окно просмотра glViewport(0, 0, w, h); // установить корректную перспективу. gluPerspective(45,ratio,1,1000); // вернуться к модели glMatrixMode(GL_MODELVIEW); }
На первом этапе мы вычисляем соотношение между шириной и высотой. Обратите внимание, что для того, чтобы это сделать правильно , мы должны заботиться о том случае, когда высота окна равна нулю. Затем мы устанавливаем матрицу проекции. Это матрица, которая определяет объём сцены. Затем мы загружаем единичную матрицу для его инициализации. После этого, мы устанавливаем, чтобы бы окно запускалось с функцией glViewport.
Вы можете попробовать с различными значениями, чтобы понять то, что вы придумали, первые два параметра это начало координат в пикселах для нового окна, а два последних являются ширина и высота соответсвенно.
GluPerspective является частью другой библиотеки для OpenGL, Библиотека утилит OpenGL или GLU. GLU представляет собой стандартный компонент реализации OpenGL.
GluPerspective устанавливает параметры точек зрения. Сначала определяют поле зрения и угол в плоскости YZ, потом соотношение между шириной и высотой просмотра. Последние два параметра определяют ближнюю и дальнюю границу плоскостей отсечения. Все, что ближе, чем ближайшее значение , или еще дальше, чем на дальнем значения , будет обрезано от места сцены. С этими настройками нужно быть внимательными, если мы хотим что-то вообще увидеть. Наконец , мы говорим OpenGL, что все матричные операции, которые следуют будет использовать матрицу вида модели.
Итоговый текст программы
#include <glut.h> void changeSize(int w, int h) { // предупредим деление на ноль // если окно сильно перетянуто будет if(h == 0) h = 1; float ratio = 1.0* w / h; // используем матрицу проекции glMatrixMode(GL_PROJECTION); // Reset матрицы glLoadIdentity(); // определяем окно просмотра glViewport(0, 0, w, h); // установить корректную перспективу. gluPerspective(45,ratio,1,1000); // вернуться к модели glMatrixMode(GL_MODELVIEW); } void renderScene(void) { glBegin(GL_TRIANGLES); glVertex3f(-1.5,-1.5,-5.0); glVertex3f(0.0,1.5,-5.0); glVertex3f(1.5,-1.5,-5.0); glEnd(); glutSwapBuffers(); } int main(int argc, char **argv) { // инициализация glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(400,400); glutCreateWindow("Урок 2"); // регистрация glutDisplayFunc(renderScene); // Новая функция изменения размеров окна glutReshapeFunc(changeSize); // основной цикл glutMainLoop(); }
Пробуем скомпилировать
Создаваемое окошко можно сколь угодно перетягивать по горизонтали и вертикали - но его содержимое не должно исказиться пропорционально. Только зумирование + и -.
Комментарии
Добавление к программе строки glutReshapeFunc(changeSize);
приводит к тому, что треугольник перестаёт совсем отрисовываться.
Отличные уроки(учу GL по ним), только в renderScene нужно добавить очистку буфера цвета и буфера глубины. При изменении размеров треугольники размножаются)