CodeNet / Приложения / Графика / Open GL
OpenGL и Delphi на практике
Любая теория хороша, если она может быть реализована на Delphi :-). Поэтому предлагаю не откладывая в долгий ящик написать первую программу на OpenGL - а потом, окрылившись успехом, вернуться к теории и как следует проштудировать все книги и сайты по сабжу, чтобы уж стать настоящими монстрами трехмерного моделирования.
Для начала придется проделать подготовительную работу:
- настроить формат пикселей с учетом отображаемой информации;
- создать контекст OpenGL и подготовить сам движок OpenGL к работе.
Формат пикселей удобно вынести в отдельную процедуру, которую мы оформим следующим образом:
procedure SetDCPixelFormat (dc: HDC);
var pfd: TPixelFormatDescriptor;
nPixelFormat: Integer;
begin
FillChar (pfd, SizeOf (pfd),0);
with pfd do
begin
nSize:= sizeof (pfd);
nVersion:= 1;
dwFlags:= PFD_DRAW_TO_WINDOW or
PFD_SUPPORT_OPENGL or
PFD_DOUBLEBUFFER;
iPixelType:= PFD_TYPE_RGBA;
cColorBits:= 16;
cDepthBits:= 64;
iLayerType:= PFD_MAIN_PLANE;
end;
nPixelFormat:=ChoosePixelFormat (DC,@pfd);
SetPixelFormat (DC, nPixelFormat,@pfd);
end;
Здесь при заполнении структуры TPixelFormatDescriptor мы задаем параметры будущего графического отображения, в том числе количество цветовых бит, а также тип пикселей (iPixelType). Мы также задаем флаги, которые, как видно из названия, указывают, что наша программа будет поддерживать OpenGL, а также что мы будем рисовать в окне и использовать двойную буферизацию (параметр, необходимый для воспроизведения движущихся объектов).
Далее посредством вызова ChoosePixelFormat система выбирает подходящий формат пикселя - и мы присваиваем его (через SetPixelFormat) нашему окну.
Теперь нужно инициализировать контекст самого OpenGL посредством функций, содержащихся в модуле Windows, и произвести дополнительную настройку движка:
procedure TForm1.FormCreate (Sender: TObject); begin H:=Handle; DC:=GetDC (H); SetDCPixelFormat (DC); RC:=wglCreateContext (DC); wglMakeCurrent (DC, RC); glClearColor (0.6,0.6,0.6,1.0); glMatrixMode (GL_PROJECTION); glLoadIdentity; glFrustum (-1,1,-1,1,2,20); glMatrixMode (GL_MODELVIEW); glLoadIdentity; glTranslatef (0.0,-1.0,-6.0); BeginPaint; end;
Как видим, сначала мы задали для нашей графики необходимый формат пикселей. Теперь при помощи функции wglCreateContext создаем OpenGL-контекст, а впоследствии делаем его текущим контекстом. Далее, используя уже универсальные функции**, произведем настройку "мира", который будем создавать. Для этого через glClearColor очистим контекст и заполним ее 60-процентным черным цветом. Далее выберем матрицу проекций, которая определяет, как будут проецироваться трехмерные объекты на плоскость экрана (в оконные координаты) и через glLoadIdentity установим единичную матрицу и зададим границы плана в "мировых координатах" при помощи вызова glFrustum. После чего загрузим модельно видовую матрицу и произведем ее смещение (glTranslatef).
Что будем рисовать
Конечно, можно было нарисовать простую пирамиду или же куб. Но мы сделаем большее - нарисуем "признание в любви"** (рис. 1). Специально для этого методом "научного перебора" была разработана модель, описывающая соответствующую кривую:

Остается только перевести ее с языка математики на нормальный человеческий.
Прорисовка сцены
Подготовку сцены начнем с подключения разных дополнительных функций, без которых дальнейшая работа невозможна. Эти функции прописаны в методе BeginPaint, а также в методе FormResize (чтобы при изменении размера формы соответственно менялся размер объекта). Для этого используем функцию glEnable с соответствующими параметрами.
Далее в FormPaint используем подготовленные заранее методы DrawFace и DrawElement (см. листинг ниже) для отрисовки упомянутого объекта. А для придания ему еще большей "жары" используем возможности OpenGL по освещению сцены.
Итог
С точки зрения сложности освоения OpenGL сопоставим с другими подобными библиотеками. Так что с одной стороны нет разницы, в чем разбираться и что изучать. Но с точки зрения разумного подхода любой проект трехмерной графики должен как минимум поддерживать OpenGL в качестве одной из опций. Ведь серьезные вещи считаются и визуализируются, как правило, под Unix/IRIX/Linux/FreeBSD, и в то же время было бы неправильно игнорировать пользователей Windows. Так что OpenGL как раз и является тем универсальным языком и общим знаменателем, позволяющим вашим приложениям свободно мигрировать с одной платформы на другую
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,OpenGL, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Timer1: TTimer;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormResize(Sender: TObject);
private
RC:HGLRC;
DC:HDC;
H:THandle;
procedure BeginPaint;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
const mat1_dif:Array[0..2] of Single = (0.8,0.8,0.0);
const mat1_amb:Array[0..2] of Single = (0.2,0.2,0.2);
const mat1_spec:Array[0..2] of Single = (0.6,0.6,0.6);
const mat1_shininess = 0.5*128;
procedure DrawElement(A,b,R0,r1:Single);
procedure DrawFace(A,R:Single;Normal:Boolean);
implementation
procedure SetDCPixelFormat(dc:HDC);
var pfd:TPixelFormatDescriptor;
nPixelFormat:Integer;
begin
FillChar(pfd,SizeOf(pfd),0);
with pfd do
begin
nSize := sizeof(pfd);
nVersion := 1;
dwFlags := PFD_DRAW_TO_WINDOW or
PFD_SUPPORT_OPENGL or
PFD_DOUBLEBUFFER;
iPixelType:= PFD_TYPE_RGBA;
cColorBits:= 16;
cDepthBits:= 64;
iLayerType:= PFD_MAIN_PLANE;
end;
nPixelFormat:=ChoosePixelFormat(DC,@pfd);
SetPixelFormat(DC,nPixelFormat,@pfd);
end;
procedure TForm1.BeginPaint;
begin
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
timer1.enabled:=true;
end;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
H:=Handle;
DC:=GetDC(H);
SetDCPixelFormat(DC);
RC:=wglCreateContext(DC);
wglMakeCurrent(DC,RC);
glClearColor(0.6,0.6,0.6,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glFrustum(-1,1,-1,1,2,20);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glTranslatef(0.0,-1.0,-6.0);
BeginPaint;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
wglMakeCurrent(0,0);
wglDeleteContext(RC);
ReleaseDC(H,DC);
DeleteDC(DC);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
glRotatef(4.0,0.0,1.0,0.0);
SwapBuffers(DC);
InvalidateRect(H,nil,False);
end;
procedure DrawElement(a,b,r0,r1:Single);
var x1b,y1b:Single;
x1e,y1e:Single;
x0b,y0b:Single;
x0e,y0e:Single;
t0,t1:Single;
dt:single;
begin
t0:=-3;t1:=3;
dt:=0.06;
while t0
Оставить комментарий
Оставлять комментарии могут только зарегистрированные пользователи.
Если вы не являетесь зарегистрированным пользователем, то вам необходимо зарегистрироваться. Регистрация бесплатна. Если вы уже зарегистрированы на CodeNet, то вам необходимо ввести логин и пароль в верхней (Alt-U) части страницы.
Комментарии
1. Arhi2med / 20 мая 2011, 23:47:26

Да оно-то понятно но коментированый код читается легче.(ТЕМ КТО В НАЧАЛЕ ПУТИ)


