РефератыИнформатика, программированиеOpOpenGL и Delphi на практике

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;

<
br />

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<=t1 do


begin


x0b:=a*sin(t0)*sin(t0)*sin(t0)*sin(t0)*cos(t0);


y0b:=a*abs(sin(t0)*cos(t0));


x0e:=a*sin(t0+dt)*sin(t0+dt)*sin(t0+dt)*sin(t0+dt)*cos(t0+dt);


y0e:=a*abs(sin(t0+dt)*cos(t0+dt));


x1b:=b*sin(t0)*sin(t0)*sin(t0)*sin(t0)*cos(t0);


y1b:=b*abs(sin(t0)*cos(t0));


x1e:=b*sin(t0+dt)*sin(t0+dt)*sin(t0+dt)*sin(t0+dt)*cos(t0+dt);


y1e:=b*abs(sin(t0+dt)*cos(t0+dt));


glBegin(GL_TRIANGLE_STRIP);


glNormal((x0b+x1e)/2,(y0b+y1e)/2,(r1+r0)/2);


glVertex3f(x0b,y0b,r0);


glVertex3f(x0e,y0e,r0);


glVertex3f(x1e,y1e,r1);


glVertex3f(x1b,y1b,r1);


glEnd;


t0:=t0+dt;


end;


end;


procedure DrawFace(A,R:Single;Normal:Boolean);


var x,y:single; t0,t1,dt:Single;


begin


t0:=-3;t1:=3;


dt:=0.06;


glBegin(GL_POLYGON);


while t0<=t1 do


begin


x:=a*sin(t0)*sin(t0)*sin(t0)*sin(t0)*cos(t0);


y:=a*abs(sin(t0)*cos(t0));


glVertex3F(x,y,r);


t0:=t0+dt;


end;


t0:=0;


x:=a*sin(t0)*sin(t0)*sin(t0)*sin(t0)*cos(t0);


y:=a*abs(sin(t0)*cos(t0));


if Normal then glNormal3f(x,y,-r) else glNormal3f(x,y,r);


glEnd;


end;


procedure TForm1.FormPaint(Sender: TObject);


var m,n:single;dm:Single;a:Single;df:Single;


begin


a:=25;


df:=10;


glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);


glColor(1.0,0.0,0.0,0.0);


glMaterialfv(GL_FRONT,GL_AMBIENT,@mat1_amb);


glMaterialfv(GL_FRONT,GL_DIFFUSE,@mat1_dif);


glMaterialfv(GL_FRONT,GL_SPECULAR,@mat1_spec);


glMaterialf(GL_FRONT,GL_SHININESS,mat1_shininess);


m:=-1;n:=1;dm:=0.5;


while m<=n do


begin


DrawElement(Sqrt(a-m*m),Sqrt(a-(m+dm)*(m+dm)),m/df,(m+dm)/df);


m:=m+dm;


end;


DrawFace(Sqrt(a-(m)*(m)),(m)/df,True);


m:=-1;


DrawFace(Sqrt(a-(m)*(m)),(m)/df,True);


end;


procedure TForm1.FormResize(Sender: TObject);


const lm:Array[0..3] of Single = (0.5,0.5,0.5,1.0);


const


light_ambient:array[0..3] of glfloat = (0.0,0.0,0.0,1.0);


light_diffuse:array[0..3] of glfloat = (1.0,1.0,1.0,1.0);


light_specular:array[0..3] of glfloat = (2.0,2.0,2.0,1.0);


light_position:array[0..3] of glfloat = (2.0,1.0,3.0,1.0);


light_emission:array[0..3] of glfloat = (1.0,1.0,1.0,1.0);


light_spotdirection:array[0..3] of glfloat = (1.0,1.0,1.0,1.0);


begin


wglMakeCurrent(0,0);


wglDeleteContext(RC);


ReleaseDC(H,DC);


DC:=GetDC(H);


SetDCPixelFormat(DC);


RC:=wglCreateContext(DC);


wglMakeCurrent(DC,RC);


glClearColor(0.6,0.6,0.6,0.0);


glMatrixMode(GL_PROJECTION);


glLoadIdentity;


glFrustum(-1,1,-1,1,2,20);


glMatrixMode(GL_MODELVIEW);


glLoadIdentity;


glTranslatef(0.0,-1.0,-6.0);


glLightModel(GL_LIGHT_MODEL_LOCAL_VIEWER,Ord(True));


glLightModelfv(GL_LIGHT_MODEL_AMBIENT,@lm);


glLightfv(GL_LIGHT0,GL_AMBIENT,@light_ambient);


glLightfv(GL_LIGHT0,GL_DIFFUSE,@light_diffuse);


glLightfv(GL_LIGHT0,GL_SPECULAR,@light_specular);


glLightfv(GL_LIGHT0,GL_POSITION,@light_position);


glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,8);


glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,170);


glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,@light_spotdirection);


glEnable(GL_LIGHTING);


glEnable(GL_LIGHT0);


glEnable(GL_DEPTH_TEST);


glEnable(GL_NORMALIZE);


glEnable(GL_COLOR_MATERIAL);


end;


end.

Сохранить в соц. сетях:
Обсуждение:
comments powered by Disqus

Название реферата: OpenGL и Delphi на практике

Слов:915
Символов:13327
Размер:26.03 Кб.