OpenGL (5.) - Urychlení pomocí glDrawElements

Dnes se dostávám k psaní dalšího článku, ve kterém vám ukáži pár způsobů, jak zlepšit dosavadní práci. Mezi novinky patří vytvoření odděleného procesu, tzv. thread, který se používá místo časovače a volání funkce glDrawElements, která se rovněž významný podílí na zvýšení fps.

Aplikace používá místo časovače oddělený proces Thread,

function Tread(P : pointer) : integer;
var
  i: integer;
begin
  i := 1;
  repeat
    Form1.Repaint;
  until
    i = 2;
end;

který se vytvoří touto funkcí volanou v TForm1.create:

Handles := BeginThread(nil, 0, Tread, nil, 0, ThreadID);
Popis obrázku

Největší změna oproti předešlým dílům je volání funkce glDrawElements. V proceduře InicializaceOpenGL je zavolána další procedura InitElements, která vypadá následově:

procedure TForm1.InitElements;
var
  Path : string;
begin
  Path := ExtractFilePath(Application.ExeName);



   //nacteni textur
   LoadBitmap(Path + 'floor.bmp');
   glGenTextures(1, @textura[1]);
   glBindTexture(GL_TEXTURE_2D, textura[1]);
   glTexParameterf(GL_Texture_2D,GL_Texture_Wrap_S,GL_Repeat);
   glTexParameterf(GL_Texture_2D,GL_Texture_Wrap_T,GL_Repeat);
   glTexParameterf(GL_Texture_2D,GL_Texture_Mag_Filter,GL_Linear);
   glTexParameterf(GL_Texture_2D,GL_Texture_Min_Filter,GL_Linear);
   glTexImage2d(GL_Texture_2D,0,3,Velikost,Velikost,0,GL_RGB,
   					GL_Unsigned_byte,@buffer);

   LoadBitmap(Path + 'wall.bmp');
   glGenTextures(1, @textura[2]);
   glBindTexture(GL_TEXTURE_2D, textura[2]);
   glTexParameterf(GL_Texture_2D,GL_Texture_Wrap_S,GL_Repeat);
   glTexParameterf(GL_Texture_2D,GL_Texture_Wrap_T,GL_Repeat);
   glTexParameterf(GL_Texture_2D,GL_Texture_Mag_Filter,GL_Linear);
   glTexParameterf(GL_Texture_2D,GL_Texture_Min_Filter,GL_Linear);
   glTexImage2d(GL_Texture_2D,0,3,Velikost,Velikost,0,GL_RGB,
   					GL_Unsigned_byte,@buffer);



//**************************************************************************


    //1. ctverec
    VertexPointer1[0].X := 0;	//Pozice bodu 1 v ose x
    VertexPointer1[0].Y := 0;	//Pozice bodu 1 v ose y
    VertexPointer1[0].Z := 0;	//Pozice bodu 1 v ose z
    CoordPointer1[0].S := 0;	//Texturova koordinace bodu 1
    CoordPointer1[0].K := 0;	//Texturova koordinace bodu 1
    Indices1[0] := 0;  	  	//Identifikace bodu 1

    VertexPointer1[1].X := 10;
    VertexPointer1[1].Y := 0;
    VertexPointer1[1].Z := 0;
    CoordPointer1[1].S := 1;
    CoordPointer1[1].K := 0;
    Indices1[1] := 1;

    VertexPointer1[2].X := 10;
    VertexPointer1[2].Y := 0;
    VertexPointer1[2].Z := 10;
    CoordPointer1[2].S := 1;
    CoordPointer1[2].K := 1;
    Indices1[2] := 2;

    VertexPointer1[3].X := 0;
    VertexPointer1[3].Y := 0;
    VertexPointer1[3].Z := 10;
    CoordPointer1[3].S := 0;
    CoordPointer1[3].K := 1;
    Indices1[3] := 3;


    //2. ctverec
    VertexPointer2[0].X := 10;
    VertexPointer2[0].Y := 0;
    VertexPointer2[0].Z := 0;
    CoordPointer2[0].S := 0;
    CoordPointer2[0].K := 0;
    Indices2[0] := 0;

    VertexPointer2[1].X := 20;
    VertexPointer2[1].Y := 2;
    VertexPointer2[1].Z := 0;
    CoordPointer2[1].S := 1;
    CoordPointer2[1].K := 0;
    Indices2[1] := 1;

    VertexPointer2[2].X := 20;
    VertexPointer2[2].Y := 2;
    VertexPointer2[2].Z := 10;
    CoordPointer2[2].S := 1;
    CoordPointer2[2].K := 1;
    Indices2[2] := 2;

    VertexPointer2[3].X := 10;
    VertexPointer2[3].Y := 0;
    VertexPointer2[3].Z := 10;
    CoordPointer2[3].S := 0;
    CoordPointer2[3].K := 1;
    Indices2[3] := 3;




    //leva stena
    VertexPointer3[0].X := 0;
    VertexPointer3[0].Y := 0;
    VertexPointer3[0].Z := 0;
    CoordPointer3[0].S := 0;
    CoordPointer3[0].K := 2;
    Indices3[0] := 0;

    VertexPointer3[1].X := 0;
    VertexPointer3[1].Y := 2;
    VertexPointer3[1].Z := 0;
    CoordPointer3[1].S := 0;
    CoordPointer3[1].K := 0;
    Indices3[1] := 1;

    VertexPointer3[2].X := 20;
    VertexPointer3[2].Y := 2;
    VertexPointer3[2].Z := 0;
    CoordPointer3[2].S := 10;
    CoordPointer3[2].K := 0;
    Indices3[2] := 2;

    VertexPointer3[3].X := 10;
    VertexPointer3[3].Y := 0;
    VertexPointer3[3].Z := 0;
    CoordPointer3[3].S := 5;
    CoordPointer3[3].K := 2;
    Indices3[3] := 3;



    //zadni stena
    VertexPointer4[0].X := 0;
    VertexPointer4[0].Y := 0;
    VertexPointer4[0].Z := 0;
    CoordPointer4[0].S := 4;
    CoordPointer4[0].K := 2;
    Indices4[0] := 0;

    VertexPointer4[1].X := 0;
    VertexPointer4[1].Y := 0;
    VertexPointer4[1].Z := 10;
    CoordPointer4[1].S := 0;
    CoordPointer4[1].K := 2;
    Indices4[1] := 1;

    VertexPointer4[2].X := 0;
    VertexPointer4[2].Y := 2;
    VertexPointer4[2].Z := 10;
    CoordPointer4[2].S := 0;
    CoordPointer4[2].K := 0;
    Indices4[2] := 2;

    VertexPointer4[3].X := 0;
    VertexPointer4[3].Y := 2;
    VertexPointer4[3].Z := 0;
    CoordPointer4[3].S := 4;
    CoordPointer4[3].K := 0;
    Indices4[3] := 3;


    //prava stena
    VertexPointer5[0].X := 0;
    VertexPointer5[0].Y := 0;
    VertexPointer5[0].Z := 10;
    CoordPointer5[0].S := 10;
    CoordPointer5[0].K := 2;
    Indices5[0] := 0;

    VertexPointer5[1].X := 0;
    VertexPointer5[1].Y := 2;
    VertexPointer5[1].Z := 10;
    CoordPointer5[1].S := 10;
    CoordPointer5[1].K := 0;
    Indices5[1] := 1;

    VertexPointer5[2].X := 20;
    VertexPointer5[2].Y := 2;
    VertexPointer5[2].Z := 10;
    CoordPointer5[2].S := 0;
    CoordPointer5[2].K := 0;
    Indices5[2] := 2;

    VertexPointer5[3].X := 10;
    VertexPointer5[3].Y := 0;
    VertexPointer5[3].Z := 10;
    CoordPointer5[3].S := 5;
    CoordPointer5[3].K := 2;
    Indices5[3] := 3;



    glEnableClientState(GL_COLOR_ARRAY);   		//aktivuje pole barev
    glEnableClientState(GL_VERTEX_ARRAY);		//aktivuje pole bodu
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);	//akt. pole tex. koordinaci

    glColorPointer( 4, GL_UNSIGNED_BYTE, 0, @Buffer );	//nacte pole barev

end;

Samozřejmostí je, že máme všechny proměnné nadefinovány:

//body
type TVertexPointer = array [0..100] of record
  X: TGLFloat;
  Y: TGLFloat;
  Z: TGLFloat;
end;

//texturova koordinace
type TCoordPointer = array [0..100] of record
  S: TGLFloat;
  K: TGLFloat;
end;

//indikator poli
type TIndices = array [0..100] of TGluInt;


var VertexPointer1, VertexPointer2, VertexPointer3, 
    VertexPointer4, VertexPointer5 : TVertexPointer;
	
    CoordPointer1, CoordPointer2, CoordPointer3, 
    CoordPointer4, CoordPointer5 : TCoordPointer;
	
    Indices1, Indices2, Indices3, Indices4, Indices5: TIndices;

Funkce "GLDrawElements" načítá tyto pole barev, texturových koordinací, pozic bodů a z těchto hodnot renderuje objekty. Pole hodnot se načtou jen jednou a potom se v nekonečné smyčce volá funkce "glDrawElements", čímž se docílí rychlejšího překreslování scény, než u klasické metody renderování přes funkce "glBegin() .... glEnd".

procedure TForm1.DrawElements;
begin
  //1. ctverec
  glBindTexture(GL_TEXTURE_2D, textura[1]);	   //nacte texturu
  glTexCoordPointer(2, GL_FLOAT, 0, @CoordPointer1);   //nacte pole tex. koordinaci
  glVertexPointer(3, GL_FLOAT, 0, @VertexPointer1);	  //nacte pole bodu
  glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, @Indices1);//zobrazi vysledny objekt


  //2. ctverec
  glBindTexture(GL_TEXTURE_2D, textura[1]);
  glTexCoordPointer(2, GL_FLOAT, 0, @CoordPointer2);
  glVertexPointer(3, GL_FLOAT, 0, @VertexPointer2);
  glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, @Indices2);

  //leva stena
  glBindTexture(GL_TEXTURE_2D, textura[1]);
  glTexCoordPointer(2, GL_FLOAT, 0, @CoordPointer3);
  glVertexPointer(3, GL_FLOAT, 0, @VertexPointer3);
  glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_INT, @Indices3);

  //zadni stena
  glBindTexture(GL_TEXTURE_2D, textura[2]);
  glTexCoordPointer(2, GL_FLOAT, 0, @CoordPointer4);
  glVertexPointer(3, GL_FLOAT, 0, @VertexPointer4);
  glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_INT, @Indices4);

  //prava stena
  glBindTexture(GL_TEXTURE_2D, textura[2]);
  glTexCoordPointer(2, GL_FLOAT, 0, @CoordPointer5);
  glVertexPointer(3, GL_FLOAT, 0, @VertexPointer5);
  glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_INT, @Indices5);
end;

Proceduru DrawElements voláme v proceduře ZobrazitScenu, kde se zároveň nastaví posuny a rotace při procházení námi vytvořenou scénou:

procedure TForm1.ZobrazitScenu;
begin
  pohyb;
  wglMakeCurrent(Canvas.Handle,hRC);
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  VlastnostiObjektu;
  DrawElements;
  glFlush;
  SwapBuffers(Canvas.Handle);
  wglMakeCurrent(0,0)
end;

Také jsem vylepšil proceduru, která zajišťuje pohyb ve scéně. Pohyb už není tak sekaný, jak byl doposud. Nebudu se o ní však rozepisovat, protože si ji můžete stáhnout se zdrojákem.Zbytek zdrojáku zůstává stejný jako v předchozích příkladech, takže popis dalších použitých funkcí najdete v nich.

Pozn.: Na počítači AMD Duron 750Mhz s integrovanou grafikou při rozlišení 1024*768 běhá tento prográmek rychlostí přibližně 70fps, při změně rozlišení na 320*240 několikanásobně rychleji.

Popis obrázku

Tady (340 kB) si můžete dnešní stáhnout zdroják i s texturami.

Vyšlo 20.12.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

Fire.pas 
Zdravím, mám problém se spuštěním jelikož mi chybí fire.pas, který to potřebuje, do kodu je doložen fire.dcu, ale ten neumím překonvertovat do fire.pas a ani nikde na internetu jsem to nenašel, mohli by jste mi ho prosím zaslat? Děkuji 
Vložil: Lukeout (26.09.2009 11:29:45)
už OK 
Už je to OK, jen stačilo z kodu odstranit fire a valí to 
Vložil: Lukeout (28.09.2009 13:12:04)
Přidání příspěvku
©PC-guru.cz 2000-2008 | Optimalizováno pro 1024*768