Metodichka по компьютерной графике. Е. А. Снижко, Н. А. Флерова, А. В. Воронцов программирование компьютерной графики с использованием
Скачать 1.31 Mb.
|
hIcon установлено равным нулю, т.е. иконка окна не нужна; для мыши используется стандартный указатель. Фоновый цвет не имеет значения (мы установим его в GL). Если меню в этом окне не требуется, то установим его значение в NULL. Имя класса – это любое имя. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = "OpenGL WinClass"; Если при регистрации класса произошла ошибка, появится соответствующее сообщение. if(!RegisterClass(&wc)) 9 { MessageBox(0,"Ошибка регистрации класса окна.", "Ошибка",MB_OK|MB_ICONERROR); return FALSE; } Создадим окно. Однако OpenGL будет вызвана только после того как будет послано сообщение WM_CREATE. Флаги WS_CLIPCHILDREN и WS_CLIPSIBLINGS требуются для OpenGL и должны быть добавлены именно здесь. hWnd = CreateWindow( "OpenGL WinClass", "Это минимальная программа OpenGL", // Заголовок вверху окна WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, // Позиция окна на экране 640, 480, // Ширина и высота окна NULL, NULL, hInstance, NULL); Далее следует обычная проверка на ошибки. Если окно не было создано по какой-то причине, сообщение об ошибке следует вывести на экран. При этом генерируется окно с сообщением об ошибке и предложением завершить программу. if(!hWnd) { MessageBox(0,"Ошибка создания окна.","Ошибка",MB_OK|MB_ICONERROR); return FALSE; } Для того, чтобы можно было перейти в полноэкранный режим необходимо следовать правилу: ширина и высота в полноэкранном режиме должна совпадать с шириной и высотой, которые установлены для окна вывода. DEVMODE dmScreenSettings; // Режим работы memset(&dmScreenSettings, 0, sizeof(DEVMODE)); // Очистка для хранения установок dmScreenSettings.dmSize = sizeof(DEVMODE);// Размер структуры Devmode dmScreenSettings.dmPelsWidth = 640; // Ширина экрана dmScreenSettings.dmPelsHeight = 480; // Высота экрана dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;// Режим Пиксела ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); // Переключение в полный экран Функция ShowWindow показывает созданное окно. Функция UpdateWindow обновляет окно, SetFocus делает окно активным, и вызывает wglMakeCurrent(hDC,hRC) чтобы убедиться, что Контекст рендеринга не освобожден. ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); SetFocus(hWnd); Для того чтобы программа не завершала свою работу сразу же после отрисовки изображения, создадим бесконечный цикл. Для выхода из цикла можно использовать нажатие клавиши ESC. При этом программе будет отправлено сообщение о выходе, и она прервется. while (1) { // Обработка всех сообщений while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 10 else { return TRUE; } } Функция DrawGLScene вызывает ту часть программы, которая фактически рисует объекты OpenGL. Пока оставим эту часть секции пустой, все что будет сделано - очистка экрана черным цветом. SwapBuffers(hDC) очень важная команда. Мы имеем окно с установленной двойной буферизацией. Это означает, что изображение рисуется на скрытом окне (называемым буфером). Затем с помощью команды переключения буферов скрытый буфер копируется на экран. При этом получается плавная анимация без рывков, и зритель не замечает процесс рисования объектов. DrawGLScene(); // Нарисовать сцену SwapBuffers(hDC); // Переключить буфер экрана if (keys[VK_ESCAPE]) SendMessage(hWnd,WM_CLOSE,0,0); // Если ESC - выйти } } Важно отметить, что этот код не будет скомпилирован на Cи, он должен быть сохранен как .CPP файл. 15. Скомпилируйте и выполните проект. Итак, наша программа создает окно, размером 640х480, очищает его черным цветом и ожидает нажатия клавиши ESC (Alt+F4) для закрытия окна. 16. Попробуем нарисовать что-либо в этом окне. Добавьте в раздел DrawGLScene() следующий код: { glClear(GL_COLOR_BUFFER_BIT); // очистка экрана glPointSize(2); //размер точки glBegin(GL_POINTS); glColor3d(1,0,0); glVertex3d(-0.45,-0.4,0); // первая точка glColor3d(0,1,0); glVertex3d(0.4,0.4,0); // вторая точка glColor3d(0,0,1); glVertex3d(-0.35,0.4,0); // третья точка glEnd(); } 17. Скомпилируйте и выполните проект. Сохраните результат вашей работы в своей папке. Этот шаблон будет использоваться в вашей дальнейшей работе. Контрольные вопросы. 1. Что понимается под контекстом устройства? 2. Что представляет собой контекст воспроизведения? 3. Какие основные фрагменты должна содержать минимальная программа OpenGL. 4. Что входит в понятие формат пиксела? 5. Какие библиотечные файлы должны быть подключены к программе для работы с OpenGL? 6. Какая цветовая модель используется при определении цвета в данной программе? 7. Какие параметры следует указать, чтобы цвет фона был зеленым? 8. Для чего нужна функция масштабирования сцены? 9. В какой секции кода можно записывать команды рисования сцены? 10. Какое правило необходимо соблюдать, чтобы иметь возможность перехода в полноэкранный режим? 11 Лабораторная работа № 2. Примитивы OpenGL, основные приемы построения двумерных объектов. Цель работы. Знакомство с примитивами OpenGL, предназначенными для вывода точек, линий и многоугольников. Определение цвета объектов. Различные способы закрашивания объектов. Необходимые теоретические сведения. Для выполнения работы необходимо иметь представление об основных принципах формирования изображения на экране ([7] – лекция 17), о моделировании объектов на плоскости ([7] – лекции 7, 8, 10); знать особенности представления цвета в цветовой модели RGB ([7] – лекция 4); понимать смысл термина «антиэлайзинг» ([7] – лекция 6). Область вывода в OpenGL задается командой glViewPort(0, 0, ClientWidth, ClientHeight), где первые два параметра задают положение левого верхнего угла окна вывода, параметры ClientWidth, ClientHeight определяют размер окна в экранных координатах. Центр полученной области вывода имеет координаты (0, 0). Координаты изменяются в диапазоне [-1; 1] по каждой оси. Если при установке формата пиксела был установлен режим двойной буферизации (флаг PFD_DOUBLEBUFFER), то изображение готовится во внеэкранном буфере, и необходимо обеспечить перезапись содержимого внеэкранного буфера в основной. Сделать это можно командой BOOL SwapBuffers(HDC hdc); Все изображения строятся из отдельных примитивов, которые описываются с помощью набора вершин (Vertex). Примитивами OpenGl являются точки (одиночные вершины), линии (пары вершин), треугольники (три вершины), четырехугольники (четыре вершины) и полигоны (3 и более вершин). Командные скобки. Использование функций glBegin и glEnd. Команды рисования заключаются между командными скобками glBegin и glEnd. Командные скобки библиотеки OpenGl представляют собой специальные функции (не имеющие никакого отношения к операторным скобкам языков программирования). Ошибка при использовании командных скобок не распознается компилятором, но может привести к непредсказуемым результатам работы программы. Внутри командных скобок могут находиться любые операторы языка и многие функции OpenGL. Главное назначение командных скобок – задание режима (примитива) для команд glVertex (вершина), определяющих координаты вершин для рисования примитивов OpenGL. Команды, устанавливающие размер точки, толщину и тип линии, включение и отключение режима сглаживания (антиэлайзинг) должны стоять вне командных скобок. Цвет отдельных вершин или примитивов может устанавливаться как вне командных скобок, так и внутри них. Для установки цвета используется команда glColor3f(0.3f, 0.5f, 0.1f) где цвет формируется как сумма компонент красного, зеленого и синего цветов в указанной пропорции. Значения компонент задаются в виде вещественных чисел в интервале [0; 1]. Компоненты цвета могут быть заданы и в целочисленной форме, предельным значением в этом случае будет являться максимальное 8-битное целое без знака, например, белый цвет будет записан следующим образом: glColor3i(214748647, 214748647, 214748647). Однако предпочтительно использовать команду в вещественной форме, т.к. OpenGL хранит данные именно в вещественном формате. Цифра 3 в названии команды означает число аргументов команды. 12 Аргументы функции glBegin. Аргументами функции glBegin могут быть стандартные константы OpenGl, определяющие примитивы библиотеки: GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON. В программе имена констант должны быть записаны именно так как это сделано здесь (все в верхнем регистре). Включение и отключение режима сглаживания (антиэлайзинг). Для установки режима сглаживания перед командными скобками должна стоять команда glEnable() с соответствующей константой в качестве аргумента, а после командных скобок – команда glDisable() также с соответствующей константой. Выбор константы определяется примитивом, сглаживание которого должно быть включено (или отключено): GL_POINT_SMOOTH (сглаживание для точек), GL_LINE_SMOOTH (сглаживание линий), GL_POLYGON_SMOOTH (сглаживание для полигонов). Вывод точек в OpenGL. Рассмотрим рисование точек. Точки представляют собой одиночные вершины. Для рисования вершины используется команда glVertex. Если точка должна быть изображена на плоскости, то для определения ее положения необходимы две координаты. В этом случае используется функция с двумя аргументами: glVertex2f(0, 0). Буква f в названии функции определяет тип аргументов – вещественные числа (float). Точка в пространстве определяется тремя координатами, следовательно должна использоваться команда с тремя аргументами: glVertex3f(0.5, 0.3,-0.7). Команды glVertex должны размещаться между командными скобками. При этом количество точек может быть любым. Аргументом функции glBegin для рисования точек является константа GL_POINTS. Аргументом команд glEnable() и glDisable() для включения/отключения режима сглаживания является константа GL_POINT_SMOOTH. Для задания размера точки используется команда glPointSize(). Аргументом является натуральное число, определяющее размер точки в пикселах. В режиме сглаживания существует ограничение на размер точек. Определите экспериментально максимальный размер точки, выводимой в режиме сглаживания. Пример: glColor3f(1.0, 0.0, 0.0); // Установили красный цвет glEnable(GL_POINT_SMOOTH); // Включение режима сглаживания для // точек glPointSize(3); // Установили размер точки 3 пиксела glBegin(GL_POINTS); // Режим рисования - точки glVertex2f(-0.5, -0.7); glVertex2f(0.0, 0.0); glVertex2f(0.1, 0.9); glVertex2f(0.3, -0.5); glEnd(); // Конец рисования glDisable(GL_POINT_SMOOTH); // Отключение режима сглаживания для // точек Линии: одиночные, ломаные, замкнутые ломаные. Для рисования линий существует три режима: одиночные линии, ломаная, замкнутая ломаная. Одиночная линия определяется двумя вершинами. Если требуется нарисовать несколько одиночных линий, то между командными скобками должны быть описаны координаты пар вершин, т.е. количество команд glVertex между командными скобками должно быть четным. В случае, если количество вершин нечетно – последняя вершина игнорируется. Аргументом функции glBegin для рисования одиночных линий является константа GL_LINES. 13 Аргументом команд glEnable() и glDisable() для включения/отключения режима сглаживания является константа GL_LINE_SMOOTH. Для задания толщины линии используется команда glLineWidth(). Аргументом является натуральное число, определяющее толщину в пикселах. Так же как и при установке размера точки команду установки толщины линии записывают за пределами командных скобок. Для изменения типа линии используется команда glLineStipple(), имеющая два аргумента. Первый аргумент – масштабный множитель, а второй представляет собой шестнадцатиричную константу 4 , определяющую шаблон штриховки (побитовым способом). Эта команда должна стоять вне операторных скобок. ПРИМЕР: glColor3f(1.0, 0.0, 0.0); // Установили красный цвет glEnable(GL_LINE_SMOOTH); // Включение режима сглаживания для // линий glLineWidth(3); // Установили толщину линии 3 пиксела glLineStipple(1, 0xF0F0); // Тип линии – пунктирная glEnable(GL_LINE_STIPPLE); // Разрешить изменение типа линии glBegin(GL_LINES); // Режим рисования – одиночные линии glVertex2f(-0.5, -0.7); // Начало первой линии glVertex2f(0.0, 0.0); // Конец первой линии glVertex2f(0.1, 0.9); // Начало второй линии glVertex2f(0.3, -0.5); // Конец второй линии glEnd(); // Конец рисования glDisable(GL_LINE_SMOOTH); // Отключение режима сглаживания для // линий Если требуется нарисовать ломаную линию, то в командных скобках используют константу GL_LINE_STRIP. Вершины, перечисленные между командными скобками, интерпретируются следующим образом: конечная точка первой линии является начальной точкой следующего звена ломаной и т.д. Количество вершин может быть как четным, так и нечетным. Ширина и тип ломаной линии задаются так же как и для одиночных линий. Для рисования замкнутой ломаной аргументом функции glBegin должна быть установлена константа GL_LINE_LOOP. Последний отрезок замкнутой ломаной в качестве начала имеет последнюю вершину списка, а в качестве конца – первую вершину. Вывод треугольников: одиночные треугольники, ленты треугольников, веера треугольников. Для рисования отдельных треугольников константа командных скобок: GL_TRIANGLES. Количество вершин, перечисленных между командными скобками должно быть кратно трем. Каждые три вершины определяют треугольник. Лента треугольников используется, если изображение может быть построено с помощью нескольких треугольников, имеющих смежные стороны (Рисунок 1. Лента треугольников). 4 В Delphi шаблон запишется в виде, например $F0F0. a1 a2 a3 a4 a5 a6 Рисунок 1. Лента треугольников. 14 Здесь сторона a2a3 является общей стороной для первого и второго треугольников, сторона a3a4 – общей стороной второго и третьего треугольников и т.д. Если такую фигуру описывать с помощью одиночных треугольников, то необходимо задавать координаты всех вершин всех треугольников: a1, a2, a3, a2, a3, a4, a3, a4, a5, a4, a5, a6 – всего 12 вершин. Использование ленты треугольников позволяет не дублировать вершины при описании их координат. Изображенная на рисунке фигура может быть представлена лентой треугольников, координаты вершин перечисляются в следующем порядке: a1, a2, a3, a4, a5, a6 – достаточно 6 вершин. Константа командных скобок для примитива «лента треугольников»: GL_TRIANGLE_STRIP. Другая возможность рисования с помощью треугольников – использование «веера треугольников» в тех случаях, когда несколько треугольников имеют общую вершину (Рисунок 2. Веер треугольников). При описании вершин первой в списке должна стоять общая вершина. Т.о. в списке из нескольких вершин первые три вершины определяют первый треугольник; первая, третья и четвертая – второй; первая, четвертая и пятая – третий; и т.д. Если в списке имеется N вершин, то будет изображено N-2 треугольника. Константа командных скобок для веера треугольников: GL_TRIANGLE_FAN. Вывод четырехугольников. Константа командных скобок для рисования отдельных четырехугольников: GL_QUADS. Четырехугольник определяется группой из 4-х вершин, следовательно, количество вершин, записанных между командными скобками, должно быть кратно 4. Лишние вершины игнорируются. Каждая четверка вершин определяет отдельный четырехугольник. Если изображение создается из связанных четырехугольников (каждая пара четырехугольников имеет общую сторону), то используется примитив «лента четырехугольников». Константа командных скобок: GL_QUAD_STRIP. Рисование полигонов, передние и задние грани полигонов. Для рисования многоугольников в командных скобках используется константа GL_POLIGON. При этом вершины, указанные между командными скобками определяют выпуклый многоугольник. Многоугольник строится из связанных треугольников с общей вершиной, в качестве общей вершины берется первая вершина списка (рисунок 2. Веер треугольников). Список вершин для данного многоугольника: a1, a2, a3, a4, a5, a6, a7. При рисовании многоугольников следует иметь в виду наличие лицевых (передних) и обратных (задних) граней. Может возникнуть вопрос, зачем при построении плоского изображения различать лицевые и обратные грани? Однако это различие следует иметь в виду при выводе закрашенных полигонов и тем более при трехмерных построениях. a1 a2 a3 a4 a5 a6 a7 |