В выполнялось построение точек, линии и многоуголь-
ников при помощи команд: gIBegin, glEnd. Причем координаты вершин задавались
при помощи процедуры glVertex2f. Аналогично строятся точки, линии и отрезки в
трехмерном пространстве при помощи процедуры
glVertex3f(x: Single, y: Single, z: Single)
только координаты точек задаются тремя значениями.
Теперь можно строить многогранники в трехмерном пространстве, собирая
их из многоугольников-граней. Однако, такой способ построения таких трехмерных
объектов как сфера, цилиндр, конус, диск и т.д. очень неудобен. Поэтому была
разработана специальная надстройка над OpenGL – библиотека glu. Для ОС се-
мейства Windows она реализована в виде динамической библиотеки glu32.dll. С
помощью библиотеки glu вы сможете легко строить трехмерные примитивы (Quadric-
объекты), невыпуклые многоугольники (Tess-объекты), NURBS-поверхности и
Для работы с Quadric-объектами в библиотеке glu вводится специальный тип
GLUquadricObj. Для работы с Quadric-объектами, сначала надо объявить пере-
менную типа GLUquadricObj. Переменная инициализируется при помощи процеду-
ры gluNewQuadric. При окончании работы с Quadric-объктами, переменную необ-
ходимо удалить при помощи процедуры gluDeleteQuadric. Например:
var
QuadObj: GLUquadricObj;
. . .
begin
. . .
QuadObj:=gluNewQuadric;
. . .
{графические построения}
. . .
gluDeleteQuadric(QuadObj); // Удаление объекта
. . .
end;
Режим воспроизведения объекта задается процедурой:
gluQuadricDrawStyle(QuadObj:GLUquadricObj, mode:cardinal)
Первый аргумент – это имя переменной Quadric-объекта, а параметр mode
может быть GLU_LINE (тогда будет строиться каркасная модель объекта),
GLU_POINT (строятся только точки вершин объекта) или GLU_FILL (тогда грани
объекта будут закрашиваться).
Сфера строится при помощи процедуры:
gluSphere(QuadObj:GLUquadricObj, radius:double, slices:integer,
stacks:integer)
Второй параметр – это радиус сферы, а третий и четвертый параметры – количе-
ство «меридианов» и «параллелей» из которых состоит каркас сферы. Разумеется, чем
больше второй и третий параметры, тем точнее передается сферическая форма объекта.
Цилиндр и конус можно нарисовать процедурой:
GluCylinder(QuadObj:GLUquadricObj, baseRadius:double, topRadius:
double, height:double, slices:integer, stacks:integer)
Аргументы: имя Quadric-объекта, радиусы одного и второго основания ци-
линдра и два числа, задающие частоту каркасной сетки.
И, наконец, - диск:
GluDisk(QuadObj:GLUquadricObj, innerRadius:double, outerRadius:
double, slices:integer, loops:integer)
Аргументы: имя Quadric-объекта, внутренний и внешний радиусы, число сек-
торов и концентрических окружностей из которых состоит каркас диска.
Библиотека glu позволяет выводить объекты не целыми, а частями. Для это-
го существует процедура, задающая плоскость отсечения объекта:
glClipPlane(plane:cardinal,equation:PGLdouble)
Параметр plane – это символическая константа, задающая имя плоскости от-
сечения: GL_CLIP_PLANE0, GL_CLIP_PLANE1 и т.д. Указатель equation адресует
массив, состоящих из четырех элементов – коэффициентов уравнения нормали к
плоскости отсечения. Та часть сцены, куда направлен вектор нормали к плоскости
отсечения, и будет отображаться.
После того как плоскость отсечения задана, само отсечение можно включить
при помощи процедуры glEnable, в качестве параметра следует задать имя плос-
кости отсечения (GL_CLIP_PLANE0, GL_CLIP_PLANE1 и т.д.). Отключение отсече-
ния выполняется процедурой glDisable.
Еще один класс объектов, поддерживаемый библиотекой glu – это NURBS-
поверхности (Non-Uniform Rational B-Spline). NURBS-объекты задаются специаль-
ным типом gluNurbsObj. Как и при работе с Quadric-объектами, NURBS-объект на-
до создавать и удалять:
var
Nurb: gluNurbsObj;
. . .
begin
. . .
Nurb:=gluNewNurbsRenderer;
. . .
{графические построения}
. . .
gluDeleteNurbsRenderer(Nurb); // Удаление объекта
. . .
end;
Существует два режима отображения NURBS-поверхности: закрашенная и
каркасная. Режимы задаются следующим образом:
gluNurbsProperty(Nurb, GLU_DISPLAY_MODE, GLU_FILL)
или
gluNurbsProperty(Nurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON)
Команды построения заключаются в командные скобки:
gluBeginSurface(Nurb: gluNurbsObj)
gluEndSurface(Nurb: gluNurbsObj)
NURBS-поверхность строится при помощи процедуры
gluNurbsSurface(Nurb: gluNurbsObj,uknot_count:integer,
uknot:PGLFloat,vknot_count:integer,vknot:PGLFloat,
u_stride:integer,v_stride:integer,ctlarray:PGLFloat,
uorder:integer,vorder:integer,type:cardinal)
где Nurb – имя переменной NURBS-объекта, uknot_count, vknot_count – размер-
ность сетки узловых точек поверхности. Поверхность строится на сетке узловых
точек размерностью uknot_count x vknot_count узлов. Указатели *uknot и
*vknot адресуют одномерные массивы нелинейности (линейности) сетки узловых
точек в системе координат u;v. Массивы должны содержать соответственно по
uknot_count и vknot_count элементов, причем значения элементов массива должны
возрастать с ростом индекса массива. Параметры u_stride и v_stride указывают
сколько вещественных чисел содержится в строке структуры данных и сколько
вещественных чисел задают одну опорную точку. Параметр *ctlarray – это указа-
тель на массив опорных точек вида: ctlarray[0..u, 0..v, 0..2], где 0..u и 0..v это коли-
чество узловых точек в столбце и в строке матрицы поверхности соответственно,
а 0..2 место для хранения (x,y,z) координат опорной точки. Параметры uorder и
vorder – это степень сплайновой кривой плюс единица. Для кубических сплайнов
uorder и vorder равны 4. Последний параметр type задает тип возвращаемых зна-
чений. Если type равен GL_MAP2_VERTEX_3, то процедура возвращает координа-
ты точек в трехмерном пространстве. Количество опорных точек в массиве
*ctlarray должно равняться (uknot_count – uorder) x (vknot_count – vorder).
Например, для массивов нелинейности сетки опорных точек вида:
uknot: Array[0..7] of GLFloat = (0.0, 0.0, 0.0, 0.0,
1.0, 1.0, 1.0, 1.0);
vknot: Array[0..7] of GLFloat = (0.0, 0.0, 0.0, 0.0,
1.0, 1.0, 1.0, 1.0);
и массива координат сетки опорных точек вида:
ctlarray: Array [0..3,0..3,0..2] of GLFloat=
(
(//U[1]
(-0.8, 0.8, 0.5), //V[1]
(-0.5, 1, 0.2), //V[2]
(0.5, 1, 0.2), //V[3]
(0.8, 0.8, 0.5)), //V[4]
(//U[2]
(-1, 0.5, 0.5), //V[1]
(-0.5,0.5, -0.2), //V[2]
(0.5, 0.5, -0.2), //V[3]
(1, 0.5, 0.5)), //V[4]
(//U[3]
(-1, -0.5, 0.4), //V[1]
(-0.5,-0.5, -0.2), //V[2]
(0.5, -0.5, -0.2), //V[3]
(1, -0.5, 0.4)), //V[4]
(//U[4]
(-0.8, -0.8, 0.5), //V[1]
(-0.5, -1, 0.2), //V[2]
(0.5, -1, 0.2), //V[3]
(0.8, -0.8, 0.5)) //V[4]
);
Рис. 2. Пример NURBS-поверхности
следующий участок кода процедуры отрисовки строит каркасную модель простей-
шей NURBS-поверхности (рис.2):
. . .
gluNurbsProperty(N,GLU_DISPLAY_MODE,GLU_OUTLINE_POLYGON);
gluBeginSurface(N);
gluNurbsSurface(N, 4*2, @uknot, 4*2, @vknot,
4*3, 3, @ctlarray, 4, 4, GL_MAP2_VERTEX_3);
gluEndSurface(N);
. . .
Библиотека glu позволяет еще и вырезать куски из NURBS-поверхностей.
Внутри операторных скобок:
gluBeginTrim(Nurb:gluNurbsObj)
gluEndTrim(Nurb:gluNurbsObj)
После построения поверхности командой gluNurbsObj, задаем область вырезки:
gluPwlCurve(Nurb:gluNurbsObj, count:integer,
points:PGLFloat, stride:integer, type:cardinal)
Здесь: Nurb – имя поверхности, count – количество точек, которыми задается
замкнутая кусочно-линейная кривая. Та часть NURBS-поверхности, которая попа-
дет внутрь этой кривой, и будет отображаться. Points – указатель на массив точек,
задающих область вырезки. Причем точки следует задавать в координатах
NURBS-поверхности, то есть u, v и w. Параметр stride задает количество действи-
тельных чисел, которое отводится для задания одной точки в массиве, задающем
ограничивающую кривую. И наконец type – это тип возвращаемых значений, он
может принимать значения GLU_MAP1_TRIM_2, когда точки ограничивающей кри-
вой задаются двумя координатами (u и v), или GLU_MAP1_TRIM_3, если точки за-
даются тремя координатами.
Область вырезки можно задать не только в виде кусочно-гладкой кривой, но
и в виде гладкой сплайновой кривой. Так же, внутри операторных скобок вырезки,
используйте команду.
gluNurbsCurve(Nurb:gluNurbsObj, nknots:integer, knot:PGLFloat,
stride:integer, ctlpts:PGLFloat, order:integer, type:cardinal)
Здесь с аргументами попробуйте разобраться сами используя справочную
систему Delphi.
После того как объект сцены создан, его следует разместить на сцене в нуж-
ном месте. Для этого можно использовать процедуры перемещения, вращения и
масштабирования.
glTranslatef(x:single, y:single, z:single)
где x,y,z – смещения по координатным осям.
glRotatef(angle:single, x:single, y:single, z:single)
Для процедуры вращения следует указать угол и координаты вектора нор-
мали к плоскости вращения.
glScalef(x:single, y:single, z:single)
Для масштабирования надо задать масштабы сжатия/растяжения по коор-
динатным осям.
Для того, чтобы преобразования трансформации коснулись только заданно-
го объекта сцены и не повлияли на остальные, требуется заключить участок кода
формирования этого объекта и процедуры его трансформации в стек матриц пре-
образования вида, между командами glPushMatrix() и glPopMatrix().
Например, следующий участок программы рисует цилиндр, повёрнутый на
90 градусов вокруг оси X:
. . .
glPushMatrix();
glRotatef(90, 1, 0, 0);
gluCylinder(QuadObj, 1, 1, 2, 36, 12);
glPopMatrix();
. . .
Чтобы объекты на сцене выглядели более выразительно, включите источник
света с помощью команд:
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
Пример:
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
wX:=X;
wY:=Y;
rotate:=true;
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
rotate:=false;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState;
X,Y: Integer);
begin
if rotate then
begin
rX:=rX+(X-wX)/2;
rY:=rY+(Y-wY)/2;
wX:=X;
wY:=Y;
InvalidateRect(Handle,nil,false);
end;
end;
Кроме того, в обработчик события onPaint (процедуру отрисовки) необходи-
мо добавить команды вращения:
. . .
glRotatef(rX,0,1,0);
glRotatef(rY,1,0,0);
. . .
Переменные wX, wY, rX, rY, rotate – глобальные и имеют тип соответственно
single,single,single,single и boolean.
Исходники:
1.
2.
|