OpenGL (1.) - Čtverec s interpolací barvy

OpenGL je grafické rozhrání, ve kterém se dají naprogramovat docela slušné hry i v Delphi a tak si myslím, že byste se sem měli alespoň podívat. Dnes se zaměřím na nastavení a tvorbu základní aplikace pod Delphi. Všechno je popsáno pěkně krok po kroku včetně příkladů a tak myslím, že se to dá pochopit.

Pro zprístupnění kouzel knihovny OpenGL potřebujeme přidat do našeho projektu knihovny GL, Glu, popř. i GLaux

uses
  GL, GLU;

Device context - obsahuje informace potřebné pro GDI (graphics device interface), součást operačního systému

Render kontext (render context) je potřebný pro každý příkaz prováděný OpenGL.

Prvním krokem inicializace OpenGL je získat device kontext, který obsahuje informace potřebné pro GDI. Pokud bude výstup směřovat do okna, můžeme použít funkci GetDC(Handle). Pak je třeba nastavit pixelový formát získanému device kontextu. Zde specifikujeme vlastnosti OpenGL jako Double buffering, z-buffering, alpha buffering, atd. Když budeme mít device kontext s nastaveným pixelovým formátem, můžeme začít vytvořit rendering kontext, do kterého budou kreslit funkce OpenGL

procedure TForm1.FormCreate(Sender: TObject);
begin
  UhelX := 0;
  UhelY := 0;
  UhelZ := 0;
  X := 0.0; Y := 0; Z := -4.0;
  DC := GetDC(Handle);
  SetDCPixelFormat(DC);
  hrc := wglCreateContext(DC);
  wglMakeCurrent(DC, hrc);
  Svetlo;
  Timer.Enabled := True;
end;

Funkce wglCreateContext nám vytvoří nový Render Context. Funkce wglMakeCurrent nastaví daný Render Context jako aktuální.

procedure TForm1.SetDCPixelFormat(DC : HDC);
var PFD : TPixelFormatDescriptor;
    nPixelFormat : integer;
begin
  FillChar(PFD,SizeOf(PFD),0);
  with PFD do
    begin
       nSize := SizeOf(TPixelFormatDescriptor);
       nVersion := 1;
       dwFlags := PFD_DRAW_TO_WINDOW or
                  PFD_SUPPORT_OPENGL or
                  PFD_DOUBLEBUFFER;
       iPixelType := PFD_TYPE_RGBA;
       cColorBits := 24;
       cDepthBits   := 32;
       iLayerType   := PFD_MAIN_PLANE;
    end;
  nPixelFormat := ChoosePixelFormat(DC,@PFD);
  Assert(nPixelFormat <> 0,PFDError);
  SetPixelFormat(DC,nPixelFormat,@PFD)
end;

Jestliže pracujeme s grafikou, určitě se budeme chtít na něco podívat. Následující procedura nám na plochu vykreslí barevný čtverec:

procedure TForm1.Ctverec;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
  glTranslatef(X,Y,Z);			//pozice kamery
  glTranslatef(0,0,0);			//střed rotace objektu
  glRotatef(UhelX, 1, 0, 0);		//rotace objektu po ose X
  glRotatef(UhelY, 0, 1, 0);		//rotace objektu po ose Y
  glRotatef(UhelZ, 0, 0, 1);		//rotace objektu po ose Z


    glEnable(GL_COLOR_MATERIAL);
    glBegin(GL_POLYGON);
    glNormal3f(0.0, 0.0, 1.0);
     glColor3b(0,0,127);
     glVertex3f(1.0, 1.0,0.0);
     glColor3b(0,127,0);
     glVertex3f(1.0, -1.0,0.0);
     glColor3b(127,0,0);
     glVertex3f(-1.0,-1.0,0.0);
     glColor3b(127,127,0);
     glVertex3f(-1.0, 1.0,0.0);
  glEnd;



  SwapBuffers(DC);
end;

Funkcí glClear vyčistíme buffery, potom nastavíme matici zobrazení objektu glMatrixMode a tuto matici načteme funkcí glLoadIdentity. Dále nastavíme rotaci objektu glRotatef a pozici kamery glTranslatef. Mezi příkazy glBegin a glEnd definujemepožadovaný obrazec. Funkcí glNormal3f nastavíme hodnotu normálového vektoru. Určuje se vlastně bod, do kterého míří světelný paprsek, který se odrazil od stěny objektu. Maximální hodnota je 1, minimální -1. Základní hodnoty jsou (0, 0, 1), což znamená, že se paprsek odráží kolmo od přední stěny objektu. Funkcemi glColor3b a glVertex3f nastavíme pozice a barvy bodů čtverce.

Pozn.: Když používáme double buffering, tak OpenGL vše vykresluje na neviditelné místo do paměti (back buffer). Scéna se nezobrazí v okně, dokud my nedáme OpenGL příkaz, který prohodí ukazatel na back a front buffer. To je velmi užitečné, protože se scéna vykresluje mimo obrazovku a celý obraz se objeví naráz a nebliká. Po vykreslení celé tedy stačí napsat:

SwapBuffers(DC);

Nastavení prostoru provedeme podle této funkce:

procedure TForm1.FormResize(Sender: TObject);
var
  PomerStran : GLdouble;

begin
  PomerStran := Width / Height;

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(30.0, PomerStran, 0.1, 400);
  glViewport(0, 0, Width ,Height);
  InvalidateRect(Handle, nil, False);
end;

Matici zobrazení objektu glMatrixMode nastavíme na GL_PROJECTION a funkcí glLoadIdentity načteme nastavenou matici. Nyní nastavíme prostor tak, jak bude vidět z pozice kamery pomocí funkce gluPerspective(UhelPohledu, PomerStran, Nejbliz, Nejdal), kde úhel pohledu je zorný úhel kamery, poměr stran je poměr výšky a šířky projekčního plátna, nejmenší vzdálenost, od které je objekt viditelný a nejdelší vzdálenost od které již objekt není viditelný. Funkce glViewport nastavuje velikost zobrazované plochy. Nastavený prostor zobrazíme funkcí InvalidateRect(Handle, nil, False).

Pro vykreslení scény si vytvoříme další procedulu, kterou pojmenujeme Kreslit. Mezi příkazy BeginPaint a EndPaint vypíšeme vše, co chceme, aby bylo vykresleno. V našem případě je zde uvedena jen procedura ctverec, ale nic nebrání abychom přidali další:

procedure TForm1.Kreslit(var Msg: TWMPaint);
var
  ps : TPaintStruct;

begin
  BeginPaint(Handle, ps);
  Ctverec;
  EndPaint(Handle, ps);
end;

Nyní bychom měli upravit zdroják pro korektní ukončení programu touto procedurou:

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Timer.Enabled := False;
  wglMakeCurrent(0, 0);
  wglDeleteContext(hrc);
  ReleaseDC(Handle, DC);

  if (Palette <> 0) then
    DeleteObject(Palette);
end;

Nakonec jsem do zdrojáku přidal pár funkcí pro pohyb a rotace námi vytvořeného čtverce. Pohybuje se pohybem myši a rotace se provádí pohybem myši se stisknutým levým nebo pravým tlačítkem.

procedure TForm1.FormMouseMove(Sender:TObject;Shift:TShiftState;DX,
  DY: Integer);
begin
if bool then begin oldx:=dx;oldy:=dy;bool:=false;end;

if not stisknuto then begin
x:=x+((oldx-dx));
z:=z+((oldy-dy));
end;

if stisknuto then uhely:=uhely+round((oldx-dx));
if stisknuto then uhelx:=uhelx+round((oldy-dy));

oldx:=dx;oldy:=dy;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
stisknuto:=true;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
stisknuto:=false;
end;

Nakonec dodám, že všechny použité proměnné a procedury musí být deklarovány. A to je asi tak vše, co jsem vám chtěl dnes ukázat. Ještě dodám, že zdrojový soubor toho, co jsme dnes vytvořili je zde (40 kB). Už se chystám na pokračování seriálu o tomto Doufám, že jsem vás tímto článkem moc neodradil ale pokud vydržíte, budete moci všem povídat, že jste již programovali v opravdovém 3D prostředí - v OpenGL.

Vyšlo 18.09.2001, v blogu: 0 1 2 3 4 5 6 7 8

Děkuji, že jste se rozhodl(a) přečíst tento článek. Budu rád i za komentář. Pokud Vás tento článek zaujal a rádi byste jej doporučili ostatním, podpořte mně prosím tím, že věnujete minutku svého času a uděláte mi reklamu na linkuj.cz, vybrali.sme.sk či jagg.cz. Přeji příjemné čtení

Poslední články

Diskuse k blogu

Zatím nikdo nevložil komentář. Chcete být první? Přidání příspěvku
©PC-guru.cz 2000-2008 | Optimalizováno pro 1024*768