Главная » Free Pascal » Построение простейшего трехмерного изображения Free Pascal

0

Приведенная в листинге 16.5 программа Cube_1.pas воспроизводит на экране изображение разноцветного куба средствами библиотеки OpenGL. Массив Points задает координаты вершин куба. Каждой вершине присвоен индивидуальный цвет (массив Colors). Вдоль каждого ребра по умолчанию производится линейная ин- терполяция цветовых характеристик смежных вершин, и полученные цвета таким же образом распространяются на внутренние точки граней.

Для правильного построения многогранной фигуры следует различать внеш- нюю и внутреннюю грани. Грань считается внешней, если при взгляде на нее с по- зиции наблюдателя, находящегося перед гранью за пределами куба, вершины об- ходятся против часовой стрелки. Для этого именно в таком порядке следует задавать координаты точек вершин внешней грани в программе. На рис. 16.5 при- ведена нумерация вершин куба, использованная в программах Cube_1 и Cube_2.

3                                  2

7                

1

4

Рис. 16.5. Один из вариантов нумерации вершин

Довольно многие фрагменты программы Cube_1 напоминают уже прокоммен- тированные операции по созданию графического окна.

В разделе инициализации графики новыми являются процедуры задания режи- ма отображения, в которых выделены три признака — использование двойной бу- феризации (GLUT_DOUBLE) и буфера глубины (GLUT_DEPTH). В связи с использовани- ем Z-буфера пришлось включить режим отсечения невидимых граней (glEnable(GL_DEPTH_TEST);).

В обработчике события, возникающего при изменении размеров графического

окна, появились четыре дополнительные процедуры.

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

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

Два следующих поворота (glRotatef) объекта на    30вокруг оси x (вектор с компонентами 1, 0, 0) и на    60вокруг оси y (вектор с компонентами 0, 1, 0) сдела- ны для того, чтобы увидеть куб под углом, позволяющим рассмотреть не только лицевую грань.

В обработчике события, связанного с необходимостью перерисовать изображе- ние, потребовалось чистить не только плоскость отображения (GL_COLOR_BUFFER_BIT), но и Z-буфер (GL_DEPTH_BUFFER_BIT). Процедура quad, использованная в процедуре OnRedraw, позволила уменьшить число строк вызова функций OpenGL. Шесть об- ращений в цикле к процедуре quad со специально заготовленным массивом CubeInd позволили достаточно компактно выполнить обращения, необходимые для построения всех граней куба. В массиве CubeInd находятся четырехкомпонентные векторы с номерами вершин, соответствующих каждой грани и упомянутому выше правилу обхода вершин. Так как процедура quad в качестве входного параметра получает адрес вектора с номерами вершин, то она использует вызов процедур glColor и glVertex в соответствующем формате. Аналогичные приемы програм- мирования вы можете использовать и при построении других многогранников.

   Листинг 1 6 .5 .  По с тро е ние  ра зноцве тного  к уба                                                                            

program Cube_1; uses

GL,GLUT;

type

tv=array [0..3] of byte; pc=array [0..7,0..2] of single;

var

Points:pc=((-1,-1,-1),(1,-1,-1),(1,1,-1),(-1,1,-1),

(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1));

Colors:pc=((0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0), (1,0,1),(1,1,0),(1,1,1));

CubeInd:array [0..5] of tv = ((0,3,2,1),(2,3,7,6),

(0,4,7,3),(1,2,6,5),(4,5,6,7),(0,1,5,4));

//—————————————————

procedure quad(const v:tv);

// Процедура построения грани var

i,j: byte;

begin

glBegin(GL_QUADS);

for i:=0 to 3 do begin j:=v[i]; glColor3fv(Colors[j]); glVertex3fv(Points[j]);

end;

glEnd; end;

//—————————————————-

procedure OnRedraw; cdecl; var

i: byte; begin

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

for i:=0 to 5 do quad(CubeInd[i]);

glutSwapBuffers; end;

//—————————————————–

procedure OnResize(W,H:Longint); cdecl; begin

glViewport(0, 0, W, H); glLoadIdentity; glFrustum(-1,1,-1,1,3,10); glTranslatef(0,0,-8); glRotatef(30,1,0,0); glRotatef(60,0,1,0);

glMatrixMode(GL_PROJECTION);

glLoadIdentity;

if W>H then glScalef(H/W,1,1) else glScalef(1,W/H,1); glMatrixMode(GL_MODELVIEW);

end;

//—————————————————–

begin

glutInit(@argc,argv);

glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH); glutCreateWindow(‘OpenGL: Cube 1′); glutDisplayFunc(@OnRedraw);

glutReshapeFunc(@OnResize);

glMatrixMode(GL_MODELVIEW); glClearColor(0.7,0.7,0.7,1); glEnable(GL_DEPTH_TEST); glutMainLoop;

end.

Результат работы программы Cube_1 приведен на рис. 16.6.

Рис. 16.6. Разноцветный куб

Объем программы Cube_1 можно немного сократить за счет использования процедуры glDrawElements, которая внутри себя организует цикл, подобный шес- тикратному обращению к процедуре quad. Перед обращением к процедуре glDrawElements нужно сообщить пакету OpenGL, что он может воспользоваться массивами вершин и цветов, и передать ему адреса этих массивов. Нововведения выделены жирным шрифтом в приведенной ниже программе Cube_2.

   Листинг 1 6 .6 .  Оптимизирова нна я  програ мма  пос тро е ния  к уба                                                

program Cube_2; uses

GL, GLUT;

type

tv=array [0..3] of byte; pc=array [0..7,0..2] of single;

var

Points:pc=((-1,-1,-1),(1,-1,-1),(1,1,-1),(-1,1,-1),

(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1));

Colors:pc=((0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0), (1,0,1),(1,1,0),(1,1,1));

CubeInd:array [0..5] of tv = ((0,3,2,1),(2,3,7,6),

(0,4,7,3),(1,2,6,5),(4,5,6,7),(0,1,5,4));

//—————————————————-

procedure OnRedraw; cdecl; var

i:byte; begin

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,@CubeInd);

glutSwapBuffers; end;

//—————————————————–

procedure OnResize(W,H:Longint); cdecl; begin

glViewport(0, 0, W, H); glLoadIdentity; glFrustum(-1,1,-1,1,3,10); glTranslatef(0,0,-8); glRotatef(30,1,0,0); glRotatef(60,0,1,0);

glMatrixMode(GL_PROJECTION); glLoadIdentity;

if W>H then glScalef(H/W,1,1) else glScalef(1,W/H,1); glMatrixMode(GL_MODELVIEW);

end;

//—————————————————–

begin

glutInit(@argc,argv);

glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH); glutCreateWindow(‘OpenGL: Cube 1′); glutDisplayFunc(@OnRedraw);

glutReshapeFunc(@OnResize); glMatrixMode(GL_MODELVIEW); glClearColor(0.7,0.7,0.7,1); glEnable(GL_DEPTH_TEST); glEnableClientState(GL_COLOR_ARRAY);

glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3,GL_FLOAT,0,@Colors); glVertexPointer(3,GL_FLOAT,0,@Points); glutMainLoop;

end.

Объем исходной программы уменьшился примерно на 10 строк и работает она чуть-чуть быстрее за счет меньших потерь на передачу данных в подпрограмму glDrawElements и организацию соответствующих циклов.

Источник: Кетков, Ю. Л., Свободное программное обеспечение. FREE PASCAL для студентов и школьников, Ю. Л. Кетков, А. Ю. Кетков. — СПб.: БХВ-Петербург, 2011. — 384 с.: ил. + CD-ROM — (ИиИКТ)

По теме:

  • Комментарии