Использование библиотеки OpenGL

Использование библиотеки OpenGL
Эта достаточно большая статья посвящена обзору библиотеки расширения OpenGL написанная Ricardo Sarmiento. Все примеры приведенные ниже написаны с использованием этой библиотеки - точнее я нашел примеры и написал статью. Cтатья скорее обзор возможностей технологии OpenGL, чем руководство к программированию. Хотя некоторые функции и процедуры Вы можете использовать и для своих приложений - например чтение файлов DXF.
Хочу разъяснить ситуацию со всевозможными версиями библиотек и заголовочных файлов OpenGL.
Начиная с Delphi 3 в каталоге Source можно найти файл OpenGL.pas - это и есть оригинальная версия заголовков библиотеки OpenGL. Она получена трансляцией файлов Gl.h и Glu.h, соответственно с языка C.
Существует еще одно практически стандартное расширение - Glut. В оригинале Glut.h и ее трансляция на Delphi Glut.pas. Это расширение создано для более быстрого построения различных объектов OpenGL и набор полезных процедур.
Все остальные версии библиотек и заголовков OpenGL являются расширениями стандартной версии и пишутся сторонними производителями. Как и та, о которой пойдет речь ниже.
Призываю использовать стандартную библиотеку OpenGL. Во первых вы получите наибольшую быстроту исполнения кода, и совместимость. Но в статье я использую обзор библиотеки расширения OpenGL, почему? Дело в том, что новичку порой сложно разобраться в дебрях программирования, а расширение стандартной библиотеки позволяет быстро написать код и получить зрелищный результат. Именно результат может подтолкнуть вас на дальнейшее изучение библиотеки OpenGL.
 
Итак начнем. Приведу иерархию объектов, использованных в данной библиотеке:
== Введение ==
=== Пример 1 ===
В этом примере рассмотрены следующие вопросы:
Создание сцены TSceneGL
var
 Scene: TSceneGL;
begin
 Scene := TSceneGL.create; // Создаем новую сцену
Создание объекта TEntity - куб, задание его с помощью TFace, установка цвета и добавление на сцену.
var
 Cube: TEntity;
 Face: TFace;
begin
 Cube := TEntity.Create; // Создаем пустой объект TEntity
 Cube.SetColor(90, 200, 150); // Инициируем цвета R,G,B
 Face := Cube.addFace;
 // Создаем 1-й face в исходном кубе всего 6 граней (в кубе)
 Face.AddVertex(1.0, 1.0, 1.0,0.0, 0.0, 1.0); // добавляем 1-й vertex
 Face.AddVertex(-1.0, 1.0, 1.0,0.0, 0.0, 1.0); // добавляем 2-й vertex
 Face.AddVertex(-1.0, -1.0, 1.0,0.0, 0.0, 1.0);// добавляем 3-й vertex
 Face.AddVertex(1.0, -1.0, 1.0,0.0, 0.0, 1.0);// добавляем 4-й vertex
 Scene.Entities.add(cube);// добавим куб на сцену
end;
Задание источника света Tlight и добавление на сцену.
 Light := TLight.Create(1); // создадим источник света и добавим его на сцену
 Scene.Lights.Add(Light); 
Инициализация сцены
 // передадим Handle Panel1 нашей сцене, на ней будет происходить рендеринг
 Scene.InitRC(Panel1.Handle);
 Scene.UpdateArea(Panel1.Width, Panel1.Height);
Простейший поворот объекта
procedure TForm1.Timer1Timer(Sender: TObject);
begin
 // изменяем rx, ry,rz
 {...}
 TEntity(Scene.Entities.Items[0]).Rotate(rx, ry, rz); // повернем куб
 Scene.Redraw; // обновим сцену
end; 
=== Пример 2 ===
Отличия от предыдущего примера: Оъект TEntity - дельфин задается не через TFace, а грузится из DXF файла - что очень упрощает жизнь.
 Dolphin := TEntity.Create;
 Dolphin.SetColor(100, 100, 160);
 Dolphin.LoadDXF('Dolphin.dxf', True);
 with Dolphin do
 begin
 Move(0, 0, -15); // переместим немного назад
 Rotate(-30, -30, -30); // и повернем
 end;
 Scene.Entities.Add(Dolphin); // добавим дельфина на сцену
=== Пример 3 ===
Изменения: У объекта Dolphin ищутся нормали к TFace, при этом получается эффект объемного пространства:
Dolphin.CalcNormals; // высчитываем нормали векторов объекта
Dolphin.Center;
=== Пример 4 ===
Добавили класс T3DMouse - теперь можно манипулировать объектами.
procedure TForm1.FormCreate(Sender: TObject);
begin
 Mouse := T3DMouse.Create(Dolphin); // Создаем T3DMouse для нашего объекта
 Mouse.Scale(1, 1, 0.1, 1, 1, 1); // задаем скорость перемещения и поворота
end;
Перемещение объекта можно осуществить:
procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
 Mouse.Move(X, Y, Shift); // обновляем объект - дельфин в новых координатах
 Scene.Redraw; // перерисуем сцену
end;
Можно установить блокировку на перемещение:
Mouse.Block(4, TSpeedButton(Sender).Down); // блокировка поворота rx
=== Пример 5 ===
Добавим управление отображением:
case dolphin.wireframe of
 0:
 begin
 SpeedButton5.Caption := 'Линии';
 Dolphin.WireFrame := 1;
 end;
 1:
 begin
 SpeedButton5.Caption := 'Заливка';
 Dolphin.WireFrame := 2;
 end;
 2:
 begin
 SpeedButton5.Caption := 'Точки';
 Dolphin.WireFrame := 0;
 end; 
end;
Scene.Redraw; // обновим сцену
=== Пример 6 ===
Соберем все в один пример, добавим возможность печати и покажем FPS при повороте.
Ну вот, самая основа должна стать Вам понятна. Если у Вас не запускаются примеры, проверьте наличие библиотек Opengl32.dll и Glu32.dll. Исходники примеров находятся в каталогах Demo1-XXX.
== Текстуры ==
Эта глава посвящена текстурированию объектов в OpenGL. В каждом примере я даю пояснения только к новому. По этому лучше посмотреть сначала пример 1 потом 2, а не начинать с примера 5. В этой главе описаны примеры использующие фильтрации текстур, и при использовании GL_linear нужен 3D ускоритель, иначе будет работать ОЧЕНЬ медленно.
=== Пример 1 ===
Закрашиваем полигоны
var
 Point: TVertex;
begin
 // Получаем выбранный полигон при нажатии на панель Panel1 
 Mouse.FindVertex(x, Panel1.Height-y, Scene, Point);
 for i := 1 to numFound do // Для всех полигонов найденных по Mouse.FindVertex
 begin
 poly := VertexHits[i] shr 16;
 vert := VertexHits[i] mod 65536;
 if (poly < Dolphin.Faces.Count)
 and (vert < TFace(Dolphin.Faces.Items[poly]).Vertices.Count) then
 begin
 // получаем составляющие цвета из ColorActual (TColor) 
 ir := (ColorActual) mod 256; // R
 ig := (ColorActual shr 8) mod 256; // G
 ib := (ColorActual shr 16) mod 256; // B
 TVertex(TFace(Dolphin.Faces.Items[poly].Vertices.Items[vert]).Point.SetColor(ir, ig, ib);
 end;
 end;
end;
=== Пример 2 ===
Формат DXF является очень неудобным для записи т.к. имеет большие размеры. Для этого автор создает другой формат записи. Добавлена функция чтения-записи.
=== Пример 3 ===
Наложение текстур на объект
thing.CreateTexture; // добавим текстуры на объект
thing.Texture.LoadTexture('texture.bmp');
thing.Texture.Automatic := False;
// а далее идет рутинный процесс задания вершин для текстур у каждой поверхности объекта
with thing do
begin
 vertex := TVertex(TFace(thing.Faces.Items[1]).Vertices.Items[0]); // x,y,z =0,0,0
 vertex.tx := 1;
 vertex.tz := 0;
end;
Да в качестве эксперимента вы можете убрать все начиная с with thing do ... end (задания точек для текстур ) и переписать thing.Texture.Automatic := True.
Использование типов фильтрации текстур
thing.Texture.MagFilter := GL_linear;
или
thing.Texture.MagFilter := GL_nearest; 
=== Пример 4 ===
Установка прозрачности у текстур (альфа каналов)
thing.Texture.EnvironmentMode := GL_decal; // Установка transparent texturing 
thing.Texture.EnvBlendColor[3] := ScrollBar1.Position; // Значение 0 - 255 
При запуске программы сначала создается сцена с освещением, но объект создается только после установки, по выполнению процедуры FormCreate_partII.
=== Пример 5 ===
Программная текстура :) Процесс прост - при нажатии на кнопки с цифрами мы создаем TBitmap и через его Canvas пишем эти цифры. Далее сохраняем этот ТBitmap в файл 'texture.bmp'. Удаляем с экрана компа старую текстуру и загружаем новую из ранее созданного 'texture.bmp'.
Исходные тексты всех примеров находятся в каталогах Demo2-XXX
== Освещение ==
=== Пример 1 ===
В этом примеры показано как задать параметры источника. Ранее источник света задавался по умолчанию. Создадим источник типа прожектор
Light := TLight.Create(1);
Light.LightType := CLspot;
Light.CutOffAngle := 5;
Light.SpotExponent := 100;
Параметры:
* CutOffAngle - угол расхождения луча.
* SpotExponent - параметр затухания источника.
Грубо говоря это коэффициент показывающий как далеко пройдет свет. Если SpotExponent=0, то пучок света уходит в бесконечность. Идем далее:
Light.SetOrientation(0, -1, 0);
Light.Source.SetPosition(0, 5, -20);
Задаем ориентацию прожектора и его положение в системе координат.
При изменении позиций полос прокрутки просто меняем компоненты цвета в источнике. Например для Ambient:
SBlightRed.Position := Round(Light.FAmbient[0] * 100);
SBlightGreen.Position := Round(Light.FAmbient[1] * 100);
SBlightBlue.Position := Round(Light.FAmbient[2] * 100);
=== Пример 2 ===
Наиболее полно контролируем параметры освещения и даже перемещаем источник в пространстве.
Все, исходные тексты всех примеров этой главы вы найдете в каталогах Demo3-XXX
== Туман ==
=== Пример 1 ===
Установить поддержку тумана в сцене очень просто :
var
 Scene: TSceneGL;
begin
 Scene.FogEnabled := True; 
Все остальное в примере это установка параметров тумана:
Тип тумана может быть:
fogType := Gl_Linear;
fogType := GL_exp;
fogType := GL_exp2;
Минимальная и максимальная дистанция:
 fogMaxDist
 fogMinDist
Интенсивность:
 fogDensity
Цвет для каждой компоненты RGB :
Scene.FogColor[0]; // R
Scene.FogColor[1]; // G
Scene.FogColor[2]; // B
После каждого изменения параметров не забывайте вызывать Redraw. Для нормального эффекта тумана очень важно подобрать правильный цвет фона и самого тумана. Они должны примерно совпадать /см картинку /.
== Файлы для загрузки ==
* Исходники примеров (102 Кб)
Author: Мироводин Дмитрий
Source: http://www.interface.ru/home.asp?artId=8520
Category:Графика
Category:OpenGL
Category:Учебники