Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RedBook

.pdf
Скачиваний:
18
Добавлен:
11.06.2015
Размер:
7.43 Mб
Скачать

//функцию фоновой обработки (поворота) //При нажатии правой отменить регистрацию void mouse(int button,int state,int x,int y)

{

switch(button)

{

case GLUT_LEFT_BUTTON:

if (state==GLUT_DOWN) glutIdleFunc(spinDisplay); break;

case GLUT_RIGHT_BUTTON: if (state==GLUT_DOWN) glutIdleFunc(NULL); break;

}

}

//Запросить режим двойной буферизации //Зарегистрировать функции обработки мышиного ввода int main(int argc, char **argv)

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); glutInitWindowSize(250,250); glutInitWindowPosition(100,100); glutCreateWindow("Двойная буферизация"); init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMouseFunc(mouse);

glutMainLoop();

return 0;

}

Глава 2. Управление состоянием и рисование геометрических объектов

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

2.1 Необходимые приготовления

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

2.1.1 Очистка окна

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

текст. Если вы создаете вид из космического корабля, вы очищаете экран черным цветом перед тем, как рисовать на нем звезды, планеты и корабли пришельцев. В некоторых случаях вам вообще нет необходимости очищать экран, например, если вы изображаете некоторую сцену внутри комнаты, все графическое окно будет заполнено после того, как вы нарисуете все стены.К этому моменту вы можете задать вопрос: почему мы постоянно говорим об очистке окна почему просто не нарисовать прямоугольник нужного цвета и такого размера, чтобы он перекрыл все окно? Во- первых, специализированная команда очистки экрана может быть намного более эффективно реализована, чем команды общего назначения. Кроме того, как вы увидите позже, OpenGL позволяет устанавливать координатную систему, положение наблюдателя и направление обзора, так что может быть достаточно сложно выяснить нужный размер и положение для очищающего прямоугольника. И, наконец, на многих компьютерах графическая аппаратура включает несколько буферов, а не только тот, в котором содержатся пиксели текущего изображения. Эти буферы должны также очищаться время от времени, и довольно удобно иметь одну единую команду, которая может очищать любую их комбинацию.Вы также должны знать, как цвета пикселей хранится в графической аппаратуре, называемой битовыми плоскостями. Существует два метода хранения. Либо непосредственно красное, зеленое, синее и альфа значения (RGBA) пикселя сохраняются в битовых плоскостях, либо там сохраняется единственный индекс, ссылающийся на цветовую таблицу. RGBA – режим в наше время используется более часто. До поры до времени вы можете игнорировать присутствие альфа значения и не пытаться понять, что оно означает.Как пример, следующие строки кода очищают окно в RGBA – режиме в белый цвет:

glClearColor(1.0,1.0,1.0,0.0); glClear(GL_COLOR_BUFFER_BIT);

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

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

glClearColor(1.0,1.0,1.0,0.0);

glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

В этом случае вызов glClearColor() идентичен предыдущему, команда glClearDepth() указывает значение, которое будет присвоено каждому пикселю в буфере глубины, и параметр команды glClear() теперь состоит из двух констант, указывающих, какие буферы нужно очищать, объединенных логическим ИЛИ. Следующая информация по команде glClear() включает таблицу с именами буферов, которые можно очищать и соответствующие им константы.

void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

Устанавливает текущий цвет очистки буфера цвета в RGBA – режиме. Если необходимо, значения red, green, blue и alpha приводятся к диапазону [0, 1]. Цвет очистки по умолчанию черный, то есть (0.0,0.0,0.0,0.0).

void glClear (GLbitfield mask);

Очищает указанные буферы указанными для них величинами очистки. Аргумент mask это битовая комбинация констант, перечисленных в таблице 2-1, полученная операцией ИЛИ.

Таблица 2-1. Буферы, которые можно очищать

Название буфера

Соответствующая константа

Буфер цвета

GL_COLOR_BUFFER_BIT

Буфер глубины

GL_DEPTH_BUFFER_BIT

Буфер аккумуляции (аккумулятор)

GL_ACCUM_BUFFER_BIT

Буфер трафарета

GL_STENCIL_BUFFER_BIT

 

 

До того, как выполнять команду очистки нескольких буферов, вы должны установить очищающие значения для каждого из них, если хотите получить что-то кроме значений по умолчанию для RGBA – цвета, значения глубины, цвета аккумуляции и индекса трафарета. В дополнение к командам glClearColor() и glClearDepth() установки значений очистки для буфера цвета и буфера глубины, glClearIndex(), glClearAccum() и glClearStencil() указывают цветовой индекс, цвет аккумуляции и индекс трафарета, которые будут использоваться для очистки соответствующих буферов.

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

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

и

glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT)

заключается в том, что хотя финальный эффект и одинаков, первый фрагмент на

многих машинах может выполняться быстрее и уж в любом случае не будет работать медленнее.

2.1.1 Установка цвета

В OpenGL описание контура рисуемого объекта не зависит от описания его цвета. Когда бы ни рисовался геометрический объект, он рисуется с использованием текущей установленной цветовой схемы. Цветовая схема может быть простой рисовать все красным цветом») или очень сложной предположить, что объект сделан из голубого пластика, на нем два ярко-желтых отблеска здесь и здесь и по всей сцене распространяется слабый зеленый свет»). Обобщенно, программист сначала устанавливает цвет или цветовую схему и затем рисует объекты. Пока цвет или цветовая схема не изменены, все объекты рисуются с использованием установленного цвета или цветовой схемы. Этот метод позволяет OpenGL – программам достигать большего быстродействия, чем в том случае, если бы библиотека не отслеживала текущий цвет.

Например, следующий псевдокод

Установить_текущий_цвет(красный); Нарисовать_объект(A);

Нарисовать_объект(B); Установить_текущий_цвет(зеленый); Установить_текущий_цвет(синий); Нарисовать_объект(C);

рисует объекты A и B красным цветом, а C – синим. Команда на 4 строке, которая устанавливает текущий цвет в зеленый не имеет эффекта, так как сразу за ней (до каких-либо команд рисования) в 5 строке текущий цвет вновь меняется, на этот раз, на синий.

Чтобы установить цвет, используйте команду glColor3f(). Она принимает 3 параметра, каждый из которых является числом с плавающей точкой в диапазоне между 0.0 и 1.0. Эти параметры, по порядку, указывают красный, зеленый и синий компоненты цвета.

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

glColor3f(1.0,0.0,0.0);

делает текущий цвет ярко красным настолько, насколько его может изобразить ваша система, а зеленый и синий компоненты полностью отсутствуют. Если задать все нули, получится черный; если задать все единицы, получится белый, если установить три величины равными 0.5 – получится серый (полпути между черным и белым). Далее приведены 8 команд и цвета, которые они устанавливают.

glColor3f(0.0,0.0,0.0);

черный

glColor3f(1.0,0.0,0.0);

красный

glColor3f(0.0,1.0,0.0);

зеленый

glColor3f(1.0,1.0,0.0);

желтый

glColor3f(0.0,0.0,1.0);

синий

glColor3f(1.0,0.0,1.0);

фиолетовый

glColor3f(0.0,1.0,1.0);

голубой

glColor3f(1.0,1.0,1.0);

белый

 

 

2.1.2 Приказ завершить рисование

Как вы видели в разделе «Конвейер визуализации OpenGL» главы 1, о большинстве современных графических систем можно думать как о линии сборки. Центральный процессор (Central Processing Unit – CPU) выполняет команду рисования. Возможно, иная аппаратура производит геометрические трансформации. Производится отсечение, заливка и/или текстурирование. Наконец, значения записываются на битовые плоскости для отображения. В high-end архитектурах каждая из этих операций производится отдельной частью аппаратуры, и каждая часть разработана таким образом, чтобы очень быстро выполнять свою специфическую задачу. В таких архитектурах CPU не нужно ждать пока завершится предыдущая команда рисования, чтобы начать выполнение следующей. Пока CPU посылает вершину на конвейер, аппаратура трансформации обрабатывает предыдущую, в то же время та вершина, что была до нее, проходит этап отсечения и так далее. В таких системах ожидание CPU завершения каждой команды, до начала выполнения следующей может привести к изрядной потере быстродействия.

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

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

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

Существуют и другие ситуации, в которых glFlush() может быть полезной:

Программные построители изображений, строящие их в системной памяти и не желающие постоянно обновлять экран.

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

void glFlush(void);

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

Некоторые команды например, команды переключения буферов в режиме двойной буферизации автоматически выполняют glFlush() (или иную схожую операцию) до того, как сами могут выполниться.

Если вам недостаточно glFlush() попробуйте использовать glFinish(). Эта команда действует аналогично glFlush(), а затем ждет от аппаратуры или сети подтверждения о том, что рисование в буфере кадра окончено. glFinish() может понадобиться, если вы хотите синхронизировать задачи например, убедиться, что ваша трехмерная картина на экране, чтобы потом с помощью Display PostScript нарисовать поверх нее заметки. Другой пример, если вы хотите убедиться в том, что картинка нарисована, чтобы начать принимать пользовательский ввод. После вызова glFinish() программа блокируется до тех пор, пока не поступит подтверждение от аппаратуры, что рисование окончено. Имейте ввиду, что чрезмерно частое использование glFinish() может сильно понизить быстродействие приложения особенно в том случае, если оно запускается по сети, так как glFinish() требует двустороннего сетевого обмена между клиентом и сервером. Если для ваших нужд достаточно glFlush(), используйте ее вместо glFinish().

void glFinish(void);

Заставляет завершиться все ранее вызванные команды OpenGL. Выхода из этой команды не происходит, пока все ранее вызванные команды не отработают полностью.

2.2 Необходимые знания о координатных системах

Если вы только что создали окно, или передвинули имеющееся, или изменили его размер во всех этих случаях оконная система посылает сообщение уведомления в программу. Если в программе используется GLUT, обработка уведомления автоматизирована при получении сообщения будет вызвана любая функция,

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

Заново установить прямоугольный регион, в который будет осуществляться вывод.

Определить координатную систему, которая будет использоваться при рисовании объектов.

Функция в следующем примере 2-1 определяет простую двумерную систему координат.

Пример 2-1. Определение простой двумерной координатной системы

void reshape(int w, int h)

{

glViewport(0,0,(GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,0,(GLdouble)w, (GLdouble)h);

}

Внутренние части GLUT передают этой функции два аргумента: длину и высоту (в пикселях) измененного окна. glViewport() подгоняет размеры прямоугольника, в который осуществляется графический вывод под размер всего окна. Три следующих вызова определяют координатную систему для рисования таким образом, чтобы левый нижний угол имел координаты (0,0), в правый верхний (w,h) (рисунок 2-1).

Представьте себе лист бумаги миллиметровки. В этом случае значения w и h в

функции reshape() представляют собой количество квадратов по строкам и столбцам листа. Далее вам нужно определиться с осями координат. gluOrtho2D() помещает начало координат в самый левый нижний квадрат листа и указывает, что каждый квадрат представляет собой одну единицу. Теперь, когда вы будете рисовать точки, линии и полигоны, они будут появляться на бумаге в легко предсказуемых квадратах.

Рисунок 2-1. Координатная система, определенная величинами w=50 и h=50

2.3 Описание точек, линий и полигонов

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

2.3.1 Что такое точки, линии и полигоны?

Вероятно, у вас имеется некоторое представление о математическом смысле терминов точка, линия и полигон. Их смысл в OpenGL почти тот же самый, но не идентичный.

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

Более важное различие проистекает из ограничений растровых дисплеев. На таких дисплеях наименьшим отображаемым элементом является пиксель и, хотя пиксель по размеру может быть меньше 1/100 дюйма, он все равно значительно больше, чем математические понятия бесконечно малого элемента (для точек) и бесконечно короткого (для линий). Когда OpenGL производит вычисления, она предполагает, что точки представлены в виде векторов с координатами в формате с плавающей точкой. Однако точка, как правило (но не всегда), отображается на дисплее в виде одного пикселя, и несколько точек, имеющих слегка различающиеся координаты, OpenGL может нарисовать на одном и том же пикселе.

2.3.1.1 Точки

Точка определяется набором чисел с плавающей точкой, называемым вершиной. Все внутренние вычисления производятся в предположении, что координаты заданы в трехмерном пространстве. Для вершин, которые пользователь определил как двумерные (то есть задал только x- и y-координаты), OpenGL устанавливает z- координату равной 0.

Дополнительно: OpenGL работает в однородных координатах трехмерной проекционной геометрии, таким образом, во внутренних вычислениях все вершины представлены четырьмя числами с плавающей точкой (x,y,z,w). Если w отлично от 0, то эти координаты в Евклидовой геометрии соответствуют точке (x/w,y/w,z/w). Вы можете указывать w-координату в командах OpenGL, но это делается достаточно редко. Если w-координата не указана, она принимается равной 1.0.

2.3.1.2 Линии

В OpenGL термин линия относится к сегменту прямой (отрезку), а не к математическому понятию прямой, которая предполагается бесконечной в обоих направлениях.

Достаточно просто задавать серию соединенных отрезков или даже закрытую последовательность отрезков (рисунок 2-2). В любом случае отрезки описываются в терминах вершин на их концах.

Рисунок 2-2. Два примера соединенных сегментов линий (ломаная и замкнутая ломаная)

2.3.1.3 Полигоны

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

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

Рисунок 2-3. Допустимые и недопустимые полигоны

Причина, по которой OpenGL накладывает подобные ограничения, заключается в том,

что в аппаратуру намного проще заложить функции визуализации некоторого определенного класса полигонов. Простые полигоны визуализировать легко. Трудные случаи тяжело обнаружить быстро. Для увеличения быстродействия OpenGL «скрещивает пальцы» и предполагает, что все полигоны простые.

Многие реальные поверхности состоят их непростых полигонов, невыпуклых полигонов или полигонов с дырами. Поскольку каждый из таких полигонов может быть представлен в виде набора простых выпуклых полигонов, в библиотеке GLU имеется набор методов для построения более сложных объектов. Эти методы принимают описание сложного полигона и выполняют тесселяцию (teselation), то есть разбиение сложного полигона на группы более простых OpenGL – полигонов, которые в последствие могут быть визуализированы и отображены.

Поскольку вершины в OpenGL всегда трехмерны, точки, формирующие границу каждого конкретного полигона, не обязательно лежат на одной плоскости пространства. (Конечно, во многих случаях они лежат на одной плоскости например, если z-координаты всех точек равны 0 или если полигон является треугольником.)

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

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

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

Рисунок 2-4. Пример неплоского полигона, трансформированного в непростой

2.3.1.4 Квадраты

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

void glRect{sifd} (TYPE x1, TYPE y1, TYPE x2, TYPE y2); void glRect{sifd}v (TYPE *v1, TYPE *v2);

Рисует квадрат, определяемый угловыми точками (x1,y1) и (x2,y2). Квадрат лежит в плоскости z=0 и его стороны параллельны осям абсцисс и ординат. Если используется векторная форма функции, углы задаются в виде двух указателей на массивы, каждый из которых содержит пару (x,y).

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

2.3.1.5Кривые и изогнутые поверхности

Любая плавная кривая или поверхность может быть аппроксимирована с любой степенью точности короткими отрезками или полигональными регионами. Таким образом, достаточное разделение кривых или поверхностей на прямые отрезки или плоские полигоны может привести к тому, что они по-прежнему будут выглядеть плавно изогнутыми (рисунок 2-5). Если у вас есть сомнения относительно того, что это действительно работает, представьте такое разбиение, при котором каждый отрезок или полигон короче или меньше пикселя.

Рисунок 2-5. Аппроксимация кривых

2.3.2 Указание вершин

При использовании OpenGL каждый геометрический объект однозначно описывается в виде упорядоченного набора вершин. Для указания вершины используется команда glVertex*().

void glVertex{234}{sifd}(TYPE coords);

void glVertex{234}{sifd}v(const TYPE *coords);

Указывает одну вершину для использования в описании геометрического объекта. Для каждой вершины вы можете указывать от 2 (x,y) до 4 координат (x,y,z,w), выбирая соответствующую версию команды. Если используется версия, где в явном виде не задаются z или w, то z принимается равным 0, а w – равным 1. Вызовы glVertex*() имеют силу только между вызовами команд glBegin() и glEnd().

В примере 2-2 приводятся некоторые варианты использования glVertex*().

Пример 2-2. Варианты допустимого использования glVertex*()

glVertex2s(1,5);

glVertex3d(0.7,5.224,3.1415926535898); glVertex4f(2.1,1.3,-2.0,2.0);

GLdouble dvect[3]={5.0,9.0,1992.0}; glVertex3dv(dvect);

Первый пример представляет собой определение вершины с координатами в трехмерном пространстве (1,5,0). (Вспомните, что если z не указано явно, оно принимается равным 0.) Координаты во втором примере (0.7,5.224,3.1415926535898) (числа с плавающей точкой двойной точности). В третьем примере указывается вершина с трехмерными координатами (1.05, 0.65, -1.0). (В этом примере координаты

указаны в однородном виде и для приведения их к более привычному следовало разделить первые три цифры на последнюю w=2.0.) В последнем примере dvect это указатель на массив, содержащий три дробных числа двойной точности.

На некоторых машинах векторная форма glVertex*() работает более эффективно, поскольку в графическую подсистему требуется передать только один параметр.

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

2.3.3 Рисование геометрических примитивов

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

Соседние файлы в предмете Компьютерная Графика