Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование для начинающих и не только


Информационный Канал Subscribe.Ru

Поздравляю всех читателей с 19-м числом. НЕ забудьте заглянуть под подушку :)

По материалам сайта www.gigabyte.iatp.org.ua

©Gigabyte 2004

Чисто 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 контекст, а в последствии делаем его текущим контекстом. Далее мы используя уже универсальные функции1 проделаем настройку "мира" который будем создавать. Для этого мы через glClearColor очищаем наш контекст и заполняем ее 60 %-м черным цветом. Далее мы выбираем матрицу проекций, которая определяет как будут проецироваться трехмерные объекты на плоскость экрана (в оконные координаты) и через glLoadIdentity устанавливаем единичную матрицу и задаем границы плана в "мировых координатах" вызовом glFrustum. После чего мы загружаем модельно видовую матрицу и делаем ее смещение (glTranslatef).

Что мы будем рисовать

Конечно можно было нарисовать простую пирамиду или же куб. Но мы сделаем большее мы нарисуем "признание в любви"2(рис.1). Специально для этого, методом "научного перебора" была разработана модель описывающая соответствующую кривую:

И теперь нам осталось только перевести ее с языка математики на нормальный "человеческий".

Прорисовка сцены

Подготовку сцены мы начнем с подключения разных дополнительных функций, без которых дальнейшая работа невозможна. Эти функции прописаны в методе BeginPaint, а также в методе FormResize (чтоб соответственно менялся размер объекта при изменении размера формы). Для этого мы используем функций glEnable с соответствующими параметрами. Далее мы в FormPaint используем подготовленные заранее методы DrawFace и DrawElement (см. Листинг.1) для отрисовки вышеупомянутого объекта. А для придание ему еще большей "пикантности" используем возможности OpenGL по освещению сцены.

Листниг.1


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<=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.

©Gigabyte 2004

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.programmershelp
Отписаться

В избранное