Народный учебник по opengl

Народный учебник по opengl

Урок 5. Создание фигур в 3D

Продолжая последний урок, мы сделаем объект, как ИСТИННЫЙ трехмерный объект, а не 2D объекты в 3D мире. Мы будем делать это добавлением с левой, задней и правой сторон треугольника, и с левой, правой, верхней и нижней сторон квадрата. Сделав это, мы превращаем треугольник в пирамиду с четырьмя гранями и квадрат в куб.

Мы будем смешивать цвета на пирамиде, создавая сглаженный закрашенный объект, а для квадрата мы назначим каждой грани свой цвет.

GLvoid DrawGLScene(GLvoid)
<
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Очистка экрана и буфера глубины
glLoadIdentity(); // Сброс просмотра
glTranslatef(-1.5f,0.0f,-6.0f); // Сдвиг влево и вглубь экрана
glRotatef(rtri,0.0f,1.0f,0.0f); // Вращение пирамиды по оси Y
glBegin(GL_TRIANGLES); // Начало рисования пирамиды

Некоторые из Вас взяли код из последнего урока и сделали свои собственные 3D объекты. Вот один вопрос, который вы задали : «как сделать, чтобы мои объекты не вращались по своим осям? Потому что кажется, что они вращаются на весь экран». Чтобы объект вращался вокруг оси, он должен быть разработан для вращения ВОКРУГ оси. Вы должны помнить, что центр любого объекта должен быть в 0 для X, 0 для Y, 0 для Z.

Следующий код создаст пирамиду вокруг центральной оси. Верх пирамиды на единицу выше центра, низ пирамиды на единицу ниже центра. Верхняя точка как раз в середине (ноль), а нижние точки одна слева от центра, а одна справа от центра.

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

Мы начинаем рисовать с Передней Грани. Поскольку во все грани входит верхняя точка, мы будем делать эту точку красной во всех треугольниках. Цвет нижних двух точек треугольника будет другим. Передняя грань будет зеленной в левой точке и синей в правой точке. Треугольник с правой стороны будет синим в левой точке и зеленным в правой точке. При помощи чередования двух нижних цветов на каждой грани, мы сделаем общие закрашенные точки снизу на каждой грани.

glColor3f(1.0f,0.0f,0.0f); // Красный
glVertex3f( 0.0f, 1.0f, 0.0f); // Верх треугольника (Передняя)
glColor3f(0.0f,1.0f,0.0f); // Зеленный
glVertex3f(-1.0f,-1.0f, 1.0f); // Левая точка
glColor3f(0.0f,0.0f,1.0f); // Синий
glVertex3f( 1.0f,-1.0f, 1.0f); // Правая точка

Сейчас мы нарисуем правую грань. Отметим, что две нижних точки нарисованы на единицу справа от центра, верхняя точка нарисована на единицу выше оси Y, и справа от середины оси X. Поэтому эта грань имеет наклон от центральной точки сверху вниз с правой стороны.

Замечу, что левая точка нарисована синим цветом в этот раз. Так как она нарисована синей, это будет тот же самый цвет, какой у точки правого нижнего угла лицевой грани. Градиент синего цвета идет от одного угла вдоль лицевой и правой граней пирамиды.

Замечу, что все четыре грани включены внутрь тех же самых glBegin(GL_TRIANGLES) и glEnd(), словно одна сторона. Поскольку мы делаем целый объект из треугольников, OpenGL знает, что каждые три точки мы рисуем как три точки одного треугольника. Треугольник рисуется из трех точек, если больше трех точек, то OpenGL поймет, что надо рисовать другой треугольник. Если вы выведете четыре точки вместо трех, OpenGL будет рисовать первые три точки и примет четвертую точку как начальную точку нового треугольника. Но не будет нарисован Четырехугольник. Поэтому проверьте, что вы не добавили любые дополнительные точки нечаяно.

Сейчас задняя сторона. Снова переключим цвета. Левая точка – зеленного цвета, поскольку этот угол так же и зеленный угол правой грани.

В завершении мы рисуем левую грань. Цвета переключаются в последний раз. Левая точка синего цвета, и смешивается с правой точкой на задней грани. Правая точка зеленного цвета, и смешивается с левой точкой на передней грани.

Мы закончили рисовать пирамиду. Поскольку пирамида только крутиться вдоль оси Y, мы не когда не увидим низ, поэтому нет необходимости выводить низ пирамиды. Если вы чувствуете потребность в экспериментах, попробуйте добавить низ используя четырехугольник, тогда вращайте по оси X для того чтобы увидеть низ, если конечно вы сделали все корректно. Проверьте, что цвет каждого угла в четырехугольнике совпадает с цветом, который использован в каждом из четырех углов пирамиды.

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

Замечу, что мы сдвинули куб немного вглубь экрана в этом уроке. Поэтому размер куба будет казаться меньше размера пирамиды. Если мы переместили бы куб на 6 единиц к экрану, то куб будет казаться больше чем пирамида, и часть куба будет за пределами экрана. Вы можете поиграться с этим настройками, и сдвинув куб дальше от экрана он будет казаться меньше, а придвинув к экрану он будет казаться больше. Это происходит из-за переспективы. Объекты на расстоянии кажутся меньше :).

glLoadIdentity();
glTranslatef(1.5f,0.0f,-7.0f); // Сдвинуть вправо и вглубь экрана
glRotatef(rquad,1.0f,1.0f,1.0f); // Вращение куба по X, Y & Z
glBegin(GL_QUADS); // Рисуем куб

Мы начнем рисовать куб сверху. Мы сдвигаемся на одну единицу от центра куба. Отметим, что по оси Y всегда единица. Затем мы рисуем квадрат на Z плоскости. Мы начинаем рисовать с правой точки вверху экрана. Правая верхняя точка должна быть на одну единицу справа, и на одну единицу вглубь экрана. Вторая точка будет на одну единицу влево и на единицу вглубь экрана. Сейчас мы нарисуем ту часть квадрата, которая ближе к зрителю. Поэтому для того чтобы сделать это, вместо смещения вглубь экрана, мы сдвигаемся на одну единицу к экрану. Улавливаете смысл?

Читайте также:  Лечение импотенции в домашних условиях лучшие народные средства

glColor3f(0.0f,1.0f,0.0f); // Синий
glVertex3f( 1.0f, 1.0f,-1.0f); // Право верх квадрата (Верх)
glVertex3f(-1.0f, 1.0f,-1.0f); // Лево верх
glVertex3f(-1.0f, 1.0f, 1.0f); // Лево низ
glVertex3f( 1.0f, 1.0f, 1.0f); // Право низ

Нижняя часть квадрата рисуется таким же образом, как и верхняя, но поскольку это низ, сдвигаемся вниз на одну единицу от центра куба. Замечу, что ось Y всегда минус единица. Если мы окажемся под кубом, и взглянем на квадрат, который снизу, вы заметите, что правый верхний угол – это угол ближний к зрителю. Поэтому вместо того чтобы рисовать дальше от зрителя в начале, мы рисуем ближе к зрителю, тогда левая сторона ближе к зрителю. И затем мы движемся вглубь экрана, для того чтобы нарисовать дальние две точки.

Если Вы действительно не заботитесь о порядке рисования полигонов (по часовой или против), вы должны скопировать код для верхнего квадрата, сдвинуть вниз по оси Y на единицу, и это будет работать, но игнорируя порядок рисования квадрата можно получить неверный результат, если вы захотите сделать, например, наложение текстуры.

glColor3f(1.0f,0.5f,0.0f); // Оранжевый
glVertex3f( 1.0f,-1.0f, 1.0f); // Верх право квадрата (Низ)
glVertex3f(-1.0f,-1.0f, 1.0f); // Верх лево
glVertex3f(-1.0f,-1.0f,-1.0f); // Низ лево
glVertex3f( 1.0f,-1.0f,-1.0f); // Низ право

Сейчас мы рисуем передний квадрат. Мы сдвигаемся на одну единицу ближе к экрану, и дальше от центра для того чтобы нарисовать переднею грань. Заметим, что ось Z всегда равна единице. В гранях пирамиды ось Z не всегда единица. Вверху, ось Z равна нулю. Если Вы попробуете установить ось Z равной нулю в привиденом ниже коде, вы увидите, что угол, который вы изменили наклонен к экрану. Но это не то, что мы хотим сейчас сделать ;).

glColor3f(1.0f,0.0f,0.0f); // Красный
glVertex3f( 1.0f, 1.0f, 1.0f); // Верх право квадрата (Перед)
glVertex3f(-1.0f, 1.0f, 1.0f); // Верх лево
glVertex3f(-1.0f,-1.0f, 1.0f); // Низ лево
glVertex3f( 1.0f,-1.0f, 1.0f); // Низ право

Задняя грань квадрата такая же ка передняя грань, но сдвинута вглубь экрана. Отметим, что ось Z всегда минус один во всех точках.

glColor3f(1.0f,1.0f,0.0f); // Желтый
glVertex3f( 1.0f,-1.0f,-1.0f); // Верх право квадрата (Зад)
glVertex3f(-1.0f,-1.0f,-1.0f); // Верх лево
glVertex3f(-1.0f, 1.0f,-1.0f); // Низ лево
glVertex3f( 1.0f, 1.0f,-1.0f); // Низ право

Сейчас нам осталось нарисовать только два квадрата. Как вы уже успели заметить одна ось всегда имеет тоже самое значение у всех точек квадрата. В этом случае ось X всегда равна минус один. Поскольку мы рисуем левую грань.

glColor3f(0.0f,0.0f,1.0f); // Синий
glVertex3f(-1.0f, 1.0f, 1.0f); // Верх право квадрата (Лево)
glVertex3f(-1.0f, 1.0f,-1.0f); // Верх лево
glVertex3f(-1.0f,-1.0f,-1.0f); // Низ лево
glVertex3f(-1.0f,-1.0f, 1.0f); // Низ право

И последняя грань завершит куб. Для нее ось X всегда равна единице. Рисуем против часовой стрелки. Если вы хотите, то вы можете не рисовать эту грань и получите коробку ;).

Если вы хотите поэксперементировать, вы всегда можете изменить цвет каждой точки в кубе для того чтобы сделать градиент, как в пирамиде. Вы можете посмотреть пример интерполяционной заливки куба скопировав первую демонстрацию Evil с моего сайта. Запустите ее и нажмите TAB. Вы увидите чудесный цветной куб, с изменяющимися цветами вдоль всех граней.

glColor3f(1.0f,0.0f,1.0f); // Фиолетовый
glVertex3f( 1.0f, 1.0f,-1.0f); // Верх право квадрата (Право)
glVertex3f( 1.0f, 1.0f, 1.0f); // Верх лево
glVertex3f( 1.0f,-1.0f, 1.0f); // Низ лево
glVertex3f( 1.0f,-1.0f,-1.0f); // Низ право
glEnd(); // Закончили квадраты

rtri+=0.2f; // Увеличим переменную вращения для треугольника
rquad-=0.15f; // Уменьшим переменную вращения для квадрата
>

В конце этого урока, вы должны лучше понимать как объекты создаются в 3D пространстве. Вы должны представлять экран OpenGL, как гиганская милиметровка, с множеством прозрачных слоев за ней. Это похоже на гигантский куб сделаный из точек. Некоторые точки двигаются слева направо, некоторые двигаются верх и вниз, и некоторые точки двигаются взад и вперед в кубе. Если вы может представить глубину экрана, вы не будете иметь проблем с разработкой новых 3D объектов.

Если вы с трудом понимаете 3D пространство, то это не бесполезно. Это может быть сложным только вначале. Объекты подобные кубу хороший пример для обучения. Если вы заметили задняя грань рисуется также как передняя грань, только дальше от экрана. Поиграйте с этим кодом, и если вы не можете понять это, спросите меня, и я вам отвечу.

Источник

Народный учебник по opengl

Урок 1. Инициализация в Windows

После того как вы создадите новое приложение в Visual C++, Вам надо будет добавить для сборки проекта библиотеки OpenGL. В меню Project/setting, выберите закладку LINK. В строке «Object/Library Modules» добавьте «OpenGL32.lib GLu32.lib GLaux.lib». Затем кликните по OK. Теперь все готово для создания программы с OpenGL.

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

#include // Заголовочный файл для Windows
#include // Заголовочный файл для OpenGL32 библиотеки
#include // Заголовочный файл для GLu32 библиотеки
#include // Заголовочный файл для GLaux библиотеки

Первые две строки устанавливают Контексты Рендеринга, которые связывает вызовы OpenGL с окном Windows. Контекст Рендеринга OpenGL определен как hRC. Для того чтобы рисовать в окне, вам необходимо создать Контекст Устройства Windows, который определен как hDC. DC соединяет окно с GDI. RC соединяет OpenGL с DC.

static HGLRC hRC; // Постоянный контекст рендеринга
static HDC hDC; // Приватный контекст устройства GDI

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

BOOL keys[256]; // Массив для процедуры обработки клавиатуры

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

Читайте также:  Народный участковый в воронеже

GLvoid InitGL(GLsizei Width, GLsizei Height) // Вызвать после создания окна GL
<

glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Очистка экрана в черный цвет

Следующие три строки создают Буфер Глубины. Думайте о буфере глубины как о слоях на экране. Буфер глубины указывает, как далеко объекты находятся от экрана. Мы не будем реально использовать буфер глубины в этой программе, но любая программа с OpenGL, которая рисует на экране в 3D будет его использовать. Он позволяет сортировать объекты для отрисовки, поэтому квадрат расположенный под кругом не изображен будет поверх круга. Буфер глубины очень важная часть OpenGL.

glClearDepth(1.0); // Разрешить очистку буфера глубины
glDepthFunc(GL_LESS); // Тип теста глубины
glEnable(GL_DEPTH_TEST); // разрешить тест глубины

glMatrixMode(GL_PROJECTION) сообщает о том, что следующие команды будут воздействовать на матрицу проекции. glLoadIdentity() – это функция работает подобно сбросу. Раз сцена сброшена, перспектива вычисляется для сцены. glMatrixMode(GL_MODELVIEW) сообщает, что любые новые трансформации будут воздействовать на матрицу просмотра модели. Не волнуйтесь, если вы что-то не понимаете этот материал, я буду обучать всему этому в дальнейших уроках. Только запомините, что НАДО сделать, если вы хотите красивую перспективную сцену.

glShadeModel(GL_SMOOTH); // разрешить плавное цветовое сглаживание
glMatrixMode(GL_PROJECTION); // Выбор матрицы проекции
glLoadIdentity(); // Сброс матрицы проекции
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
// Вычислить соотношение геометрических размеров для окна
glMatrixMode(GL_MODELVIEW); // Выбор матрицы просмотра модели
>

Следующая секция кода очень простая, по сравнению с предыдущим кодом. Это функция масштабирования сцены, вызываемая OpenGL всякий раз, когда вы изменяете размер окна (допустим, что вы используете окна чаще, чем полноэкранный режим, который мы не рассматриваем). Даже если вы не делаете изменение размеров окна (например, если вы находитесь в полноэкранном режиме), эта процедура все равно должна быть вызвана хоть один раз, обычно во время запуска программы. Замечу, что сцена масштабируется, основываясь на ширине и высоте окна, которое отображается.

GLvoid ReSizeGLScene(GLsizei Width, GLsizei Height)
<
if (Height==0) // Предотвращение деления на ноль, если окно слишком мало
Height=1;

glViewport(0, 0, Width, Height);
// Сброс текущей области вывода и перспективных преобразований

glMatrixMode(GL_PROJECTION); // Выбор матрицы проекций
glLoadIdentity(); // Сброс матрицы проекции

gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
// Вычисление соотношения геометрических размеров для окна
glMatrixMode(GL_MODELVIEW); // Выбор матрицы просмотра модели
>

В этой секции содержится весь код для рисования. Все, что вы планируете для отрисовки на экране, будет содержатся в этой секции кода. В каждом уроке, после этого будет добавлять код в эту секцию программы. Если вы уже понимаете OpenGL, вы можете попробовать добавить в код простейшие формы на OpenGL, ниже вызова glLoadIdentity(). Если вы новичок в OpenGL, подождите до следующего моего урока. Сейчас все что мы сделаем, это очистка экрана цветом, который мы определили выше, очистка буфера глубины и сброс сцены.

GLvoid DrawGLScene(GLvoid)
<
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// очистка Экрана и буфера глубины
glLoadIdentity();
// Сброс просмотра
>

Следующая секция кода наиболее важная секция в этой программе. Это установка окна Windows, установка формата пикселя, обработка при изменении размеров, при нажатии на клавиатуру, и закрытие программы.

Первые четыре строки делают следующее: переменная hWnd – является указателем на окно. Переменная message – сообщения, передаваемые вашей программе системой. Переменные wParam и lParam содержат информацию, которая посылается вместе с сообщением, например такая как ширина и высота окна.

LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)

Код между скобками устанавливает формат пикселей. Я предпочитаю не использовать режим индексации цвета. Если вы не знаете, что это означает, не заботьтесь об этом. Формат описания пикселя описывает, как OpenGL будет выводить в окно. Большинство кода игнорируется, но зачастую это необходимо. Я буду помещать короткий комментарий для каждой строки. Знак вопроса означает, что я не уверен, что это строка кода делает (я только человек!).

<
RECT Screen; // используется позднее для размеров окна
GLuint PixelFormat;
static PIXELFORMATDESCRIPTOR pfd=
<
sizeof(PIXELFORMATDESCRIPTOR), // Размер этой структуры
1, // Номер версии (?)
PFD_DRAW_TO_WINDOW | // Формат для Окна
PFD_SUPPORT_OPENGL | // Формат для OpenGL
PFD_DOUBLEBUFFER, // Формат для двойного буфера
PFD_TYPE_RGBA, // Требуется RGBA формат
16, // Выбор 16 бит глубины цвета
0, 0, 0, 0, 0, 0, // Игнорирование цветовых битов (?)
0, // нет буфера прозрачности
0, // Сдвиговый бит игнорируется (?)
0, // Нет буфера аккумуляции
0, 0, 0, 0, // Биты аккумуляции игнорируются (?)
16, // 16 битный Z-буфер (буфер глубины)
0, // Нет буфера траффарета
0, // Нет вспомогательных буферов (?)
PFD_MAIN_PLANE, // Главный слой рисования
0, // Резерв (?)
0, 0, 0 // Маски слоя игнорируются (?)
>;

Эта секция кода обрабатывает системные сообщения. Они генерируются, когда вы выходите из программы, нажимаете на клавиши, передвигаете окно, и так далее, каждая секция «case» обрабатывает свой тип сообщения. Если вы что вставите в эту секцию, не ожидайте, что ваш код будет работать должным образом, или вообще работать.

switch (message) // Тип сообщения
<

WM_CREATE сообщает программе, что оно должно быть создано. Вначале мы запросим DC (контекст устройства) для вашего окна. Помните, без него мы не можем рисовать в окно. Затем мы запрашиваем формат пикселя. Компьютер будет выбирать формат, который совпадает или наиболее близок к формату, который мы запрашиваем. Я не делаю здесь множества проверок на ошибки, чтобы сократить код, но это неправильно. Если что-то не работает, я просто добавляю необходимый код. Возможно, вы захотите посмотреть, как работают другие форматы пикселей.

case WM_CREATE:
hDC = GetDC(hWnd); // Получить контекст устройства для окна
PixelFormat = ChoosePixelFormat(hDC, &pfd);
// Найти ближайшее совпадение для нашего формата пикселов

Если подходящий формат пикселя не может быть найден, будет выведено сообщение об ошибке с соответствующем уведомлением. Оно будет ждать, когда вы нажмете на OK, до выхода из программы.

Читайте также:  Народная медицина против герпеса на теле

if (!PixelFormat)
<
MessageBox(0,»Can’t Find A Suitable
PixelFormat.»,»Error»,MB_OK|MB_ICONERROR);
PostQuitMessage(0);
// Это сообщение говорит, что программа должна завершится
break; // Предтовращение повтора кода
>

Если подходящий формат найден, компьютер будет пытаться установить формат пикселя для контекста устройства. Если формат пикселя не может быть установлен по какой-то причине, выскочит сообщение об ошибке, что формат пикселя не найден, и будет ожидать, пока Вы не нажмете кнопку OK, до выхода из программы.

Если код сделан, как показано выше, будет создан DC (контекст устройства), и установлен подходящий формат пикселя. Сейчас мы создадим Контекст Рендеринга, для этого OpenGL использует DC. wglCreateContext будет захватывать Контекст Рендеринга и сохранять его в переменной hRC. Если по какой-то причине Контекст Рендеринга не доступен, выскочит сообщение об ошибке. Нажмите OK для вызова программы.

hRC = wglCreateContext(hDC);
if(!hRC)
<
MessageBox(0,»Can’t Create A GL Rendering
Context.»,»Error»,MB_OK|MB_ICONERROR);
PostQuitMessage(0);
break;
>

Сейчас мы имеем Контекст Рендеринга, и нам необходимо сделать его активным, для того чтобы OpenGL мог рисовать в окно. Снова, если по не которой причине это не может быть сделано, выскочит сообщение об ошибке. Кликните OK в окошке ошибки для выхода из программы.

if(!wglMakeCurrent(hDC, hRC))
<
MessageBox(0,»Can’t activate GLRC.»,»Error»,MB_OK|MB_ICONERROR);
PostQuitMessage(0);
break;
>

Если все прошло удачно, то у нас есть все для того, чтобы создать область рисования OpenGL. GetClientRect возвратит нам ширину и высоту окна. Мы запомним ширину справа, и высоту снизу. После того как мы получили ширину и высоту, инициализируем экран OpenGL. Мы делаем это при помощи вызова InitGL, передавая в параметрах право и низ (ширину и высоту).

GetClientRect(hWnd, &Screen);
InitGL(Screen.right, Screen.bottom);
break;

WM_DESTROY и WM_CLOSE очень похожи. Программа будет посылать это сообщение каждый раз, когда вы выходите из программы, нажав ALT-F4, или если вы послали PostQuitMessage(0) также как мы делали, когда происходила ошибка.

ChangeDisplaySettings(NULL,0) будет переключать разрешение рабочего стола обратно, делая его таким, каким мы переключались из него в полноэкранный режим. ReleaseDC(hWnd,hDC) уничтожает контекст устройства окна. По существу это уничтожает окно OpenGL.

case WM_DESTROY:
case WM_CLOSE:
ChangeDisplaySettings(NULL, 0);

wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd,hDC);

WM_KEYDOWN вызывается всякий раз при нажатии клавиши. Клавиша, которая была нажата, сохраняется в переменной wParam. Итак, что же делает следующий код. Скажем, я нажал ‘A’. Буква фактически – это число, которое ее представляет. Поэтому в ячейку, которая представляет ‘A’ заносится TRUE. Позднее, в коде, если я проверю состояние ячейки и увижу TRUE, то я знаю, что клавиша ‘A’ действительно в этот момент нажата.

case WM_KEYDOWN:
keys[wParam] = TRUE;
break;

WM_KEYUP вызывается всякий раз, когда клавиша отпускается. Клавиша, которая отжата, также сохраняется в переменной wParam. Поэтому, когда я отпускаю клавишу ‘A’, это делает ячейку для клавиши ‘A’ равной FALSE. Когда я проверю ячейку, для того чтобы увидеть нажата ли клавиша ‘A’, она вернет FALSE, что означает «нет, она не нажата».

case WM_KEYUP:
keys[wParam] = FALSE;
break;

case WM_SIZE:
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
break;

Затем, дадим Windows обработать все сообщения, которые мы не обрабатываем и завершим процедуру.

default:
return (DefWindowProc(hWnd, message, wParam, lParam));
>
return (0);
>

Это то место, где начинается программа, где создается окно, где делается практически все, кроме рисования. Мы начинаем с создания окна.

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine,int nCmdShow)
<
MSG msg; // Структура сообщения Windows
WNDCLASS wc; // Структура класса Windows для установки типа окна
HWND hWnd; // Сохранение дискриптора окна

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»;

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

Сейчас мы сделаем окно. Не смотря на то, что мы делаем окно здесь, это не вызовет OpenGL до тех пор, пока сообщение WM_CREATE не послано. Флаги WS_CLIPCHILDREN и WS_CLIPSIBLINGS требуются для OpenGL. Очень важно, чтобы вы добавили их здесь. Я люблю использовать всплывающее окно, оно хорошо работает в полноэкранном режиме.

WS_POPUP |
WS_CLIPCHILDREN |
WS_CLIPSIBLINGS,

0, 0, // Позиция окна на экране
640, 480, // Ширина и высота окна

NULL,
NULL,
hInstance,
NULL);

if(!hWnd)
<
MessageBox(0,»Window Creation Error.»,»Error»,MB_OK|MB_ICONERROR);
return FALSE;
>

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

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(hWnd, SW_SHOW);
UpdateWindow(hWnd);
SetFocus(hWnd);

SwapBuffers(hDC) очень важная команда. Мы имеем окно с установленной двойной буферизацией. Это означает, что изображение рисуется на скрытом окне (называемым буфером). Затем, мы говорим компьютеру переключить буфера, скрытый буфер копируется на экран. При этом получается плавная анимация без рывков, и зритель не замечает отрисовку объектов.

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

Источник

Adblock
detector