(Продолжение, начало см. в МК № 22 (193))

Прежде чем приступить к изложению материала второй части статьи, хотелось бы извиниться перед теми, кто читал первую. Дело в том, что в прошлую статью вкралась досадная оплошность, в результате которой при компиляции программы возникала ошибка в библиотеке GL. Чтобы этого впреть не повторялось, необходимо удалить все #include и оставить только два из них:

#include #include

Покончив с возникшим недоразумением, давайте попробуем разобраться с синтаксисом команд, используемых в OpenGL.

Первое, что хочется сказать, — в OpenGL названия типов данных отличаются от названий в Си++ (то есть эти типы переопределены). Например, тип Glint в OpenGL — это тип int в Си++. Зачем? Очень просто — для переносимости кода на другие платформы (операционные системы).

Итак, давайте рассмотрим основные типы данных:

GLint —int

GLuint —unsigned int

GLfloat —float

GLdouble —double

GLbyte —char

С этим, я думаю, все ясно (то есть, мы просто к типу добавляем две буквы «GL»). Теперь разберем синтаксис всех команд. Для того чтобы все команды были понятны, они имеют следующий вид:

glCommand_name[n][type][v]

Таким образом, имя любой команды состоит из нескольких частей:

gl — имя библиотеки, в которой находится данная функция. Мы можем использовать и другие библиотеки, а именно: glu — библиотека GLU, glut — функции из библиотеки GLUT, glaux — библиотека GLAUX.

Comand_name — имя команды, например, InitWindowSize (эта команда нам должна быть уже известна с прошлой статьи).

[n] — число аргументов.

[type] — тип аргумента. Возможные варианты:

f —GLfloat

d —GLdouble

s —GLshort

us —GLushort

b —GLbyte

ub —GLubyte

[v] — если указан этот параметр, это означает, что в качестве параметров функции используется указатель на массив.

Теперь давайте рассмотрим пару функций, чтобы закрепить то, что мы только что выучили:

Функция glColor3d(0.1,0.5,0.3); означает, что мы используем функцию, которая находится в библиотеке GL (приставка gl). Эта функция состоит из трех параметров, типа GLdouble (3d).

Функция glVertex2f(1.5,0.9); 2f — два параметра, типа float (GLfloat).

Помимо основной библиотеки, существует несколько других дополнительных библиотек, которые мы также будем использовать в нашей работе. Первая из таких библиотек — это GLU (graphics utility library). Все функции этой библиотеки обращаются к функциям из GL, и в ее состав входят обычно функции для рисования сложных объектов вроде сфер, конуса, цилиндра и т. д. Входит во все версии OpenGL.

Вторая дополнительная библиотека ответственна за взаимодействия с системой окон. Называется она GLUT (GL Utility Toolkit). Она содержит функции, которые могут понадобится при работе с окнами.

Существует еще библиотека GLAUX. В общих чертах, ее назначение —упростить разработчику жизнь. Например, с помощью этой библиотеки очень просто рисуются такие объекты как сферы, кубы, и другие сложные объекты. Но лучше для таких целей использовать библиотеку GLUT, так как в GLAUX есть некоторые ошибки (некоторые объекты не совсем правильно Рисунокотображаются).

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

Примитив — это объединение вершин в одно целое. То есть, примитив задается набором вершин. Вершина (Vertex) — это просто-напросто координата точки на экране. Например, треугольник можно нарисовать с помощью 3-х вершин (в двухмерной системе координат), для рисования линии нам хватит и двух, и т. д.

Синтаксис задания вершин таков:

glBegin(тип); glVertex*(…); … glVertex*(…); glEnd();

Где * может быть [2,3][i,d,f,b], в зависимости от количества точек и от типа чисел, которые мы будет использовать при задании точки. Например, если мы будем рисовать в двухмерном пространстве и при этом использовать тип double, тогда функция будет иметь вид glVertex2d(x,y). Я думаю, с этим все ясно.

А теперь займемся самим рисованием. Первое, что мы будем рисовать, — это точки. Но для начала давайте настроим наше приложение. Вот код, который мы написали в прошлый раз:

#include #include #include void Display(void) { } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowSize(400,500); glutInitWindowPosition(0,0); glutCreateWindow("OpenGL Lesson2"); glutDisplayFunc(Display); glutMainLoop(); }

Как вы помните, у нас создалось некрасивое, прозрачное окно. Давайте теперь зададим цвет окна. Для этого в функцию main() допишем одну строку:

glClearColor(r,g,b,t);

где r — красный цвет, g — зеленый, b — голубой, t — прозрачность. Значение цветов выставлять нужно в диапазоне от 0 до 1 (т. е. 0.01, 0.2, 0.5, 0.83 и т. д.). Итак, выставьте нужный вам цвет, например, поставим цвет фона белый.

glClearColor(1,1,1,1);

И теперь нужно в функцию Display(void) добавить еще одну строку:

glClear(GL_COLOR_BUFFER_BIT);

Этой командой мы закрашиваем цвет фона в тот цвет, который указали в функции glClearColor(r,g,b,t);

Давайте посмотрим на полный листинг нашей программы:

#include //подключаем библиотеки #include void Display(void) //функция для рисования { glClear(GL_COLOR_BUFFER_BIT); //закрасить фон } void main(int argc,char **argv) //главная функция { glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowSize(400,500); glutInitWindowPosition(0,0); glutCreateWindow("OpenGL Lesson2"); glClearColor(1,1,1,1); //задаем цвет фона, в данном случае белый glutDisplayFunc(Display); glutMainLoop(); }

Запустите это приложение теперь. И что мы видим? Правильно, красивое белое окно! :-)

Теперь что-нибудь нарисуем. Итак, для рисования фигуры нам одной вершины не достаточно. Для это нам нужно объединить несколько вершин (то есть, как мы уже знаем, — задать примитив). Задание примитива происходит внутри командных скобок:

void glBegin (GLenum mode); void glEnd (void);

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

GL_POINTS — каждая вершина задает координаты некоторой точки.

GL_LINES — каждая отдельная пара вершин определяет отрезок; если задано нечетное число вершин, то последняя вершина игнорируется.

GL_LINE_STRIP — каждая следующая вершина задает отрезок вместе с предыдущей.

GL_LINE_LOOP — отличие от предыдущего примитива только в том, что последний отрезок определяется последней и первой вершиной, образуя замкнутую ломаную.

GL_TRIANGLES — каждая отдельная тройка вершин определяет треугольник; если задано некратное трем число вершин, то остаток игнорируется.

GL_TRIANGLE_STRIP — каждая следующая вершина задает треугольник вместе с двумя предыдущими.

GL_TRIANGLE_FAN — треугольники задаются первой и каждой следующей парой вершин (пары не пересекаются).

GL_QUADS — каждая отдельная четверка вершин определяет четырехугольник; если задано некратное четырем число вершин, то остаток игнорируется.

GL_POLYGON — последовательно задаются вершины выпуклого многоугольника.

Теперь давайте разберем это на одном примере (нарисуем одну линию).

#include #include void Display(void) { glClear(GL_COLOR_BUFFER_BIT); //закрашиваем цвет glBegin(GL_LINES); //рисуем примитив- линию glColor3d(0,0,0); //цвет линии- черный glVertex2d(-1,0); //первая вершина glVertex2d(1,1); //вторая вершина glEnd(); //заканчиваем рисовать примитив glFlush(); //выводим изображение на экран } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowSize(400,500); glutInitWindowPosition(0,0); glutCreateWindow("OpenGL Lesson2"); glClearColor(1,1,1,1); glutDisplayFunc(Display); glutMainLoop(); }

После запуска этого приложения мы с вами увидим окошко, в котором будет нарисована линия (см. Рис.). В следующий раз мы научимся делать анимацию и создадим свою первую игру — «арканоидный теннис» (то есть, наша игра будет отличаться от арканоида тем, что в нее нужно будет играть вдвоем и стараться забить мячик друг другу).

(Продолжение следует)