Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Геометрические примитивы OpenGL




Вершины надо задавать обязательно применительно к какому-нибудь примитиву. Рисование примитива начинается с вызова функции glBegin(), которой в качестве параметра передается константа, обозначающая тип примитива. Завершается примитив функцией glEnd(). Прототипы этих функций:

void glBegin(Glenum mode);

void glEnd(void);

Между вызовами glBegin() и glEnd() делаются вызовы glVertex*(). Например, для описания многоугольника, показанного на рис. 3.5 слева, надо вызвать следующие функции:

 

glBegin(GL_POLYGON);

glVertex2d(0.0, 0.0);

glVertex2d(0.0, 3.0);

glVertex2d(3.0, 3.0);

glVertex2d(4.0, 1.5);

glVertex2d(3.0, 0.0);

glEnd();

Рис. 3.5. Примитивы двух типов: многоугольник и множество точек.

 

Если в качестве типа примитива вместо GL_POLYGON указать GL_POINTS, то будет нарисовано множество из 5-ти точек (рис. 3.5, справа). В табл. 3.1 перечислены все допустимые типы примитивов, которые можно указывать при вызове glBegin().

 

Таблица 3.1. Имена и назначение геометрических примитивов.

Имя константы Назначение
GL_POINTS Отдельные точки
GL_LINES Пары вершин, являющиеся концами отрезков
GL_POLYGON Граница простого выпуклого многоугольника
GL_TRIANGLES Тройки вершин, которые интерпретируются как вершины треугольников
GL_QUADS Четверки вершин, которые интерпретируются как вершины четырехугольников
GL_LINE_STRIP Вершины ломаной линии
GL_LINE_LOOP Вершины замкнутой ломаной линии (то же, что и предыдущий тип, но последняя и первая вершина соединяются автоматически)
GL_TRIANGLE_STRIP Связная полоса из треугольников (триангулированная полоса)
GL_TRIANGLE_FAN Веер из треугольников
GL_QUAD_STRIP Связная полоса из четырехугольников (квадрированная полоса)

 

На рис. 3.6 показаны примеры примитивов, перечисленных в табл. 3.1. Предполагается, что между glBegin() и glEnd() перечислено n вершин (v0, v1, v2,..., vn-1). Как следует из рис. 3.6, кроме точек, отрезков и многоугольников, в OpenGL есть еще несколько специальных типов примитивов.

Рис. 3.6. Типы геометрических примитивов.

 

Свойства точек, отрезков и многоугольников

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

Точки

Экранный размер точки задается с помощью функции:

void glPointSize(float size);

где size – диаметр точки в пикселах (должен быть больше 0.0, по умолчанию 1.0).

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

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

 

#include <windows.h>

#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glaux.h>

 

void CALLBACK display();

 

void main()

{

auxInitDisplayMode(AUX_SINGLE | AUX_RGBA);

auxInitPosition(0, 0, 200, 200);

auxInitWindow("Лекция 3, Программа 3.1");

 

glClearColor(0.0, 0.0, 0.0, 0.0);

glShadeModel(GL_FLAT);

 

auxMainLoop(display);

}

 

void CALLBACK display()

{

glClear(GL_COLOR_BUFFER_BIT);

 

// В 1-й строке три точки диаметром 2 пиксела, без сглаживания

glPointSize(2);

glBegin(GL_POINTS);

glColor3d(1, 0, 0);

glVertex2d(50, 180);

glColor3d(0, 1, 0);

glVertex2d(100, 180);

glColor3d(0, 0, 1);

glVertex2d(150, 180);

glEnd();

 

// Во 2-й строке три точки диаметром 5 пикселов, без сглаживания

glPointSize(5);

glBegin(GL_POINTS);

glColor3d(1, 0, 0);

glVertex2d(50, 100);

glColor3d(0, 1, 0);

glVertex2d(100, 100);

glColor3d(0, 0, 1);

glVertex2d(150, 100);

glEnd();

 

// В 3-й строке три точки диаметром 10 пикселов, со сглаживанием

glPointSize(10);

glEnable(GL_POINT_SMOOTH);

glBegin(GL_POINTS);

glColor3d(1, 0, 0);

glVertex2d(50, 20);

glColor3d(0, 1, 0);

glVertex2d(100, 20);

glColor3d(0, 0, 1);

glVertex2d(150, 20);

glEnd();

glDisable(GL_POINT_SMOOTH);

 

// Принудительное завершение всех операций рисования

glFlush();

}

Программа 3.1. Рисование точек разного размера при

выключенном и включенном сглаживании.

 

Отрезки

У отрезков в OpenGL можно задавать толщину и стиль (точечный пунктир, штриховой пунктир, штрих-точка и т.п.). Толщина отрезка (в пикселах) по умолчанию равна 1.0, для ее изменения имеется функция:

void glLineWidth(GLfloat width);

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

Стиль отрезка (тип пунктира) устанавливается функцией glLineStipple():

void glLineStipple(GLint factor, GLushort pattern);

После вызова этой функции надо обязательно разрешить использование стиля с помощью glEnable(), например:

glLineStipple(1, 0x3F07);

glEnable(GL_LINE_STIPPLE);

Тип пунктира определяется шаблоном – 16-ти битным числом pattern, в котором биты, равные 0 и 1, обозначают пустые и закрашенные пикселы. Размер шаблона можно увеличить с помощью множителя factor, который задает количество повторений каждого бита шаблона.

В приведенном примере задан шаблон 0x3F07 (в двоичной форме это число 0011111100000111). При рисовании отрезка сначала закрашиваются 3 пиксела, затем 5 пропускаются, затем 6 закрашиваются, 2 пропускаются (шаблон обрабатывается справа налево, от младших битов к старшим). Если задать factor=2, то шаблон будет задавать следующее правило рисования: закрасить 6 пикселов, 10 пропустить, 12 закрасить, 4 пропустить. На рис. 3.7 показаны отрезки различных стилей и соответствующие значения шаблона и множителя.

Рис. 3.7. Пунктирные отрезки.

 

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

 

Рис. 3.8. Отрезки различных стилей и разной толщины.

 

#include <windows.h>

#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glaux.h>

 

void drawOneLine(double x1, double y1, double x2, double y2);

void CALLBACK display();

 

void main()

{

auxInitDisplayMode(AUX_SINGLE | AUX_RGBA);

auxInitPosition(0, 0, 400, 150);

auxInitWindow("Лекция 3, Программа 3.2");

 

glClearColor(0.0, 0.0, 0.0, 0.0);

glShadeModel(GL_FLAT);

 

auxMainLoop(display);

}

 

 

void drawOneLine(double x1, double y1, double x2, double y2)

{

glBegin(GL_LINES);

glVertex2d(x1, y1);

glVertex2d(x2, y2);

glEnd();

}

 

 

void CALLBACK display()

{

glClear(GL_COLOR_BUFFER_BIT);

 

glColor3d(1.0, 1.0, 1.0); // Все отрезки рисуются белым цветом

 

// В 1-й строке 3 отрезка разных стилей

glEnable(GL_LINE_STIPPLE);

glLineStipple(1, 0x0101); // Точечный пунктир

drawOneLine(50.0, 125.0, 150.0, 125.0);

glLineStipple(1, 0x00FF); // Штриховой пунктир

drawOneLine(150.0, 125.0, 250.0, 125.0);

glLineStipple(1, 0x1C47); // Штрих-точка-штрих

drawOneLine(250.0, 125.0, 350.0, 125.0);

 

// Во 2-й строке 3 отрезка толщиной 5 пикселей и разных стилей

glLineWidth(5.0);

glLineStipple(1, 0x0101);

drawOneLine(50.0, 100.0, 150.0, 100.0);

glLineStipple(1, 0x00FF);

drawOneLine(150.0, 100.0, 250.0, 100.0);

glLineStipple(1, 0x1C47);

drawOneLine(250.0, 100.0, 350.0, 100.0);

glLineWidth(1.0);

 

// В 3-й строке 6 отрезков стиля штрих-точка-штрих, которые

// образуют один большой отрезок

glLineStipple(1, 0x1C47);

glBegin(GL_LINE_STRIP);

for (int i = 0; i < 7; i++)

glVertex2d((i + 1)*50.0, 75.0);

glEnd();

 

// В 4-й строке 6 отдельных отрезков стиля штрих-точка-штрих

for (i = 0; i < 6; i++)

drawOneLine((i + 1)*50.0, 50.0, (i + 2)*50.0, 50.0);

 

// В 5-й строке 1 отрезок стиля штрих-точка-штрих с множителем 5

glLineStipple(5, 0x1C47);

drawOneLine(50.0, 25.0, 350.0, 25.0);

 

// Принудительное завершение всех операций рисования

glFlush();

}

Программа 3.2. Управление свойствами отрезков.

 

Многоугольники

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

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

void glPolygonMode(GLenum face, GLenum mode);

Параметр face указывает сторону: GL_FRONT_AND_BACK (обе стороны), GL_FRONT (передняя сторона) или GL_BACK (задняя). Параметр mode задает режим рисования выбранных сторон: GL_POINT (только вершины), GL_LINE (контур) или GL_FILL (заливка). По умолчанию для обеих сторон установлен режим заливки.

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

glPolygonMode(GL_FRONT, GL_FILL);

glPolygonMode(GL_BACK, GL_LINE);

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

OpenGL определяет ориентацию многоугольника по знаку его площади (для передней стороны многоугольника S>0), которая вычисляется по формуле:

,

где xi и yi есть экранные координаты i-й вершины n-угольника. Операция Å является обычным сложением, за исключением того, что n Å 1 = 1:

.

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

void glCullFace(GLenum mode);

Параметр mode равен GL_FRONT, GL_BACK или GL_FRONT_AND_BACK. Перед вызовом этой функции надо включить режим отсечения сторон многоугольников с помощью вызова glEnable(GL_CULL_FACE).

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

 

#include <windows.h>

#include <math.h>

#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glaux.h>

 

void CALLBACK resize(int width, int height);

void CALLBACK display();

void CALLBACK addAngleX();

void CALLBACK subAngleX();

void CALLBACK addAngleY();

void CALLBACK subAngleY();

 

// Расположение пирамиды относительно осей X и Y

int angle_x = 0, angle_y = 0;

 

void main()

{

auxInitDisplayMode(AUX_RGBA | AUX_DEPTH | AUX_DOUBLE);

auxInitPosition(50, 10, 400, 400);

auxInitWindow("Лекция 3, Программа 3.3");

 

// Включение ряда параметров OpenGL

glEnable(GL_DEPTH_TEST);

glEnable(GL_COLOR_MATERIAL);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

 

// Задание положения и направления нулевого источника света

float pos[4] = { 0, 5, 5, 1 };

float dir[3] = { 0, -1, -1 };

glLightfv(GL_LIGHT0, GL_POSITION, pos);

glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir);

 

// Регистрация обработчиков событий

auxReshapeFunc(resize);

auxKeyFunc(AUX_UP, subAngleX);

auxKeyFunc(AUX_DOWN, addAngleX);

auxKeyFunc(AUX_RIGHT, addAngleY);

auxKeyFunc(AUX_LEFT, subAngleY);

auxIdleFunc(display);

auxMainLoop(display);

}

 

 

void CALLBACK resize(int width, int height)

{

glViewport(0, 0, width, height);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(60.0, (double)width/(double)height, 1.0, 20.0);

gluLookAt(0,0,5, 0,0,0, 0,1,0);

}

 

 

void CALLBACK display()

{

const double BASE_R = 1; // Радиус основания

const double PYRAMID_H = 2; // Высота пирамиды

const double PI = 3.14159;

 

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

glPushMatrix();

glRotated(angle_x, 1, 0, 0);

glRotated(angle_y, 0, 1, 0);

 

glPolygonMode(GL_BACK, GL_LINE);

 

glBegin(GL_TRIANGLE_FAN);

glColor3d(1.0, 0.0, 1.0);

glVertex3d(0, PYRAMID_H, 0);

glColor3d(1.0, 1.0, 1.0);

for (int i = 0; i < 7; i++)

glVertex3d(cos(i*PI/3.0)*BASE_R, 0, -sin(i*PI/3.0)*BASE_R);

glEnd();

glPopMatrix();

 

auxSwapBuffers();

}

 

 

void CALLBACK addAngleX()

{

angle_x = (angle_x + 5) % 360;

}

 

void CALLBACK subAngleX()

{

angle_x = (angle_x - 5) % 360;

}

 

void CALLBACK addAngleY()

{

angle_y = (angle_y + 5) % 360;

}

 

void CALLBACK subAngleY()

{

angle_y = (angle_y - 5) % 360;

}

 

Программа 3.3. Различные режимы рисования передних и задних сторон многоугольников.

 

Сводка результатов

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

Все трехмерные объекты в OpenGL формируются из геометрических примитивов нескольких типов: точек, отрезков и многоугольников. Все примитивы задаются в виде упорядоченного множества вершин. Гладкие кривые и поверхности можно аппроксимировать с помощью отрезков и многоугольников. У примитивов можно изменить свойства, влияющие на их отображение на экране: диаметр точек, толщину и стиль отрезков, способ рисования многоугольников. У многоугольников различаются передняя и задняя стороны (по порядку перечисления вершин). Разные стороны можно рисовать разными способами: залитыми, контурными или только вершины.

 

Упражнения

Упражнение 1

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

 
 

 

 


Упражнение 2

Выполните программу 3.2. Затем напишите программу, рисующую каркасный куб в перспективной проекции. Видимые ребра нарисуйте штриховым пунктиром толщиной 3 пиксела, невидимые – точечным пунктиром толщиной 1 пиксел.

 

Упражнение 3

Выполните программу 3.3. Выясните, что произойдет, если:

1) убрать вызов функции, которая задает контурное рисование задних сторон многоугольников;

2) убрать функцию, задающую белый цвет для вершин основания пирамиды;

3) задать рисование передних сторон контурами, а задних – вершинами.

 

Упражнение 4

Постройте изображение втулки, аппроксимируя ее поверхность с помощью квадрированных полос (примитивов типа GL_QUAD_STRIP).

Упражнение 5

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

Напишите тестовую программу, которая с помощью разработанной функции строит полусферу и позволяет поворачивать ее клавишами курсора (см. программу 3.3).


Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...