OpenGL v C++ Builderu 5



Pohyb a rotace objektu

Příklad a zdroják ke stažení (465k)

Tutorial na pohyb glTranslatef() a rotaci glRotatef(). Načítání objektů ze souboru (*.txt)

Nejdříve si načteme objekt (krychli) ze souboru cube.txt. Soubor má tuto podobu
Vertices: 8
-1.0    -1.0     1    v0
-1.0     1.0     1    v1
 1.0    -1.0     1    v2
 1.0     1.0     1    v3
 1.0    -1.0    -1    v4
 1.0     1.0    -1    v5
-1.0    -1.0    -1    v6
-1.0     1.0    -1    v7
Hodnota za Vertices: nám zadává, kolik vertexů obsahuje objekt. Protože jde o krychli, tak máme 8 vrcholů Další hodnoty jsou X, Y, Z pozice jednotlivých vrcholů. v0 - v7 je jen informativní text, který se nenačítá. To samé platí o textu Vertices:.

cube.jpg(6 kb)

Pro načítání objektů a jejich vykreslování si vytvoříme tyto datové typy
//---------------------------------------------------------------------------

typedef struct    //struktura pro 3D bod
{
     GLfloat     x, y, z;    //bod x, y, z
} TPoint3d;

//---------------------------------------------------------------------------

typedef struct    //struktura objektu
{
        int  verts;    //počet vrcholů
        TPoint3d  *points;    //vrchol je složen z bodu x, y, z
} TGLObject;

//---------------------------------------------------------------------------
Vytvoříme si objekt typu TGLObject
TGLObject  cube1;    //objekt cube1
A budeme volat funkci pro načtení objektu ze souboru cube.txt
void LoadAllObjects()    //načti objekty
{
    cube1 = LoadObject("objects/cube.txt", &cube1);    //načti hodnoty uložené v souboru cube.txt a předej je objektu cube1
}
Funkce pro načítání vypadá takto
TGLObject LoadObject(char *name, TGLObject *k)    //načti objekt se souboru (name)
{
    //definice proměnných
    int     ver;    //pomocná proměnná pro počet vrcholů objektu
    GLfloat  rx,ry,rz;    //pomocna proměnna pro X, Y, Z pozici vrcholu objektu
    FILE  *filein;    //definice souboru, který budeme číst
    char  oneline[255];    //definice řádku souboru s maximálně 255 znaky

    //kód
    if ((filein = fopen(name, "rt"))== NULL)    //zkus otevřít soubor pro čtení v textovém modu "rt"
    {
        ShowMessage("Cannot open input file");    //jestli se to nezdaří, hoď chybovou hlášku
    }
    else    //jinak pokračuj v práci s načteným souborem
    {
      ReadLine(filein,oneline);    //volej funkci pro načtení řádky ze souboru
      sscanf(oneline, "Vertices: %d\n", &ver);    //přečti z první řádky počet vrcholů a předej ho proměnné ver
      k = new TGLObject;    //dynamicky alokuj pamět pro objekt (cube1)
      k->points = new TPoint3d[ver];    //dynamicky alokuj pamět pro počet vrcholů objektu
      k->verts = ver;    //načtenou hodnotu počtu vrcholů předej vrcholům objektu

      for (int i=0;i<ver;i++)    //cykluj podle počtu vrcholů
        {
          ReadLine(filein,oneline);    //čti řádek po řádku
           sscanf(oneline, "%f %f %f", &rx, &ry, &rz);    //najdi v řádce tři čísla typu float a předej je hodnotám rx, ry, rz
           k->points[i].x = rx;    //předej bodu X (aktuálního vrcholu) hodnotu rx
           k->points[i].y = ry;     //předej bodu Y (aktuálního vrcholu) hodnotu ry
           k->points[i].z = rz;     //předej bodu Z (aktuálního vrcholu) hodnotu rz
        }
      fclose(filein);    //zavři soubor
    }
    return *k;    //vrať funkci hodnoty všech vrcholů objektu
}
Tato funkce používá pro načtení řádky ze souboru funkci
void ReadLine(FILE *f,char *s)    //čti řádek ze souboru f a ukládej do řetězce s
{
    do    //cykluj
      {
        fgets(s, 255, f);    //a čti znak po znaku maximálně však 255
      } while ((s[0] == '/') || (s[0] == '\n'));    //dokud se nedostaneš na konec řádky

    return;    //vrať funkci hodnotu načteného řádku
}
Funkce pro načítání objektů se samozřejmě provádějí jen jednou, při startu aplikace. Při startu aplikace také musíme zapnout DEPTH buffer glEnable(GL_DEPTH_TEST);. Pokud bychom nechali vypnutý DEPTH buffer, objekty by se vykreslovali v tom pořadí, v jakém jsou volány, takže by se stalo, že by se zadní stěna krychle vykreslila před přední.
bool __fastcall TForm1::InitGL()
{
  ...
  ...
    ////sem budu zadávat funkce, které se mají provádět jen při startu aplikace////
      glEnable(GL_DEPTH_TEST);    //zapni hloubkový (DEPTH) buffer, aby objekty blíž ke kameře překrývali vzdálenější
      LoadGLTextures();    //vytvoř textury
      LoadAllObjects();    //načti objekty
    ////konec zadávání funkcí, které se mají provádět jen při startu aplikace////
  ...
  ...
}
Ještě, než začneme vykreslovat objekt, vypočítáme si pohyb a rotaci.
//definice proměnných
extern GLuint Texture[1];    //2d textura, pole s jednou texturou
extern TGLObject cube1;    //objekt krychle
TPoint3d angle;    //úhel rotace objektu
TPoint3d translate;    //pozice objektu
TPoint3d direction;    //směr pohybu objektu
bool start=true;    //pomocná proměnná pro načítání základních hodnot při startu aplikace

//---------------------------------------------------------------------------

void TranRotCube()    //vypočítej pohyb a rotaci
{
    //začátek výpočtu pohybu objektu
    if (start)    //jestliže probíhá první otočka cyklu
    {
      direction.x = 1;    //nastav směr pohybu objektu v X směru na 1
      direction.y = 1;    //nastav směr pohybu objektu v Y směru na 1
      direction.z = 1;    //nastav směr pohybu objektu v Z směru na 1
      translate.z = -8;   //nastav Z pozici objektu
      start = false;    //nastav start na false, aby při další otočce cyklu se základní hodnoty nenačítaly
    }

    if ((translate.x >= 3) || (translate.x <= -3))  //jetliže X pozice objektu přesáhne hodnoty 3 nebo -3
    {
        direction.x = -direction.x;    //otoč směr pohybu X
    }
    translate.x = translate.x + (0.01 * direction.x);    //přičti 0.01 pozici X, podle směru pohybu X

    if ((translate.y >= 2) || (translate.y <= -2))    //jetliže Y pozice objektu přesáhne hodnoty 2 nebo -2
    {
        direction.y = -direction.y;    //otoč směr pohybu Y
    }
    translate.y = translate.y + (0.01 * direction.y);    //přičti 0.01 pozici Y, podle směru pohybu Y

    if ((translate.z >= -6) || (translate.z <= -20))    //jetliže Z pozice objektu přesáhne hodnoty -6 nebo -20
    {
        direction.z = -direction.z;    //otoč směr pohybu Z
    }
    translate.z = translate.z + (0.01 * direction.z);    //přičti 0.01 pozici Z, podle směru pohybu Z
    //konec výpočtu pohybu objektu

    //začátek výpočtu rotace objektu
    angle.x = angle.x + 0.5;    //přičti úhel x rotace
    if (angle.x >= 360)    //jestliže je úhel větší, než 360 stupňů
    {
      angle.x = angle.x -360;    //odečti 360 stupňů
    }

    angle.y = angle.y + 1;    //přičti úhel y rotace
    if (angle.y >= 360)    //jestliže je úhel větší, než 360 stupňů
    {
      angle.y = angle.y -360;    //odečti 360 stupňů
    }

    angle.z = angle.z + 1.5;    //přičti úhel z rotace
    if (angle.z >= 360)    //jestliže je úhel větší, než 360 stupňů
    {
      angle.z = angle.z -360;    //odečti 360 stupňů
    }
    //konec výpočtu rotace objektu
}
Nyní můžeme vykreslovat objekt v nekonečné smyčce.
GLvoid DrawCube(GLvoid)    //vykresli krychli
{
    TranRotCube();    //vypočítej pohyb a rotaci krychle

    //začátek bloku OpenGL příkazu pro vykreslení objektu (krychle)
    glEnable(GL_TEXTURE_2D);    //zapni 2D texturování
    glBindTexture(GL_TEXTURE_2D, Texture[0]);    //potáhni následující objekt texturou číslo 0
    glPushMatrix;    //začátek prostorové matice

    //posouvej a rotuj objektem (který je mezi glPushMatrix; a glPopMatrix;) podle vypočtených hodnot
    glTranslatef( translate.x, translate.y, translate.z);    //pohni celým objektem
    glRotatef( angle.x, 1, 0, 0);    //rotuj objektem v X směru
    glRotatef( angle.y, 0, 1, 0);    //rotuj objektem v Y směru
    glRotatef( angle.z, 0, 0, 1);    //rotuj objektem v Z směru

    glBegin(GL_TRIANGLES);    //začni vykreslovat trojúhelníky
      //------------------------

      //přední stěna krychle
      //první trojúhelník
      glTexCoord2f( 0, 0);  glVertex3f( cube1.points[0].x, cube1.points[0].y, cube1.points[0].z);    //levý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[1].x, cube1.points[1].y, cube1.points[1].z);    //levý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[2].x, cube1.points[2].y, cube1.points[2].z);    //pravý dolní vrchol textury a výsledného čtverce

      //druhý trojúhelník
      glTexCoord2f( 1, 1);  glVertex3f( cube1.points[3].x, cube1.points[3].y, cube1.points[3].z);    //pravý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[2].x, cube1.points[2].y, cube1.points[2].z);    //pravý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[1].x, cube1.points[1].y, cube1.points[1].z);    //levý horní vrchol textury a výsledného čtverce

      //-------------------------

      //pravá stěna krychle
      //první trojúhelník
      glTexCoord2f( 0, 0);  glVertex3f( cube1.points[2].x, cube1.points[2].y, cube1.points[2].z);    //levý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[3].x, cube1.points[3].y, cube1.points[3].z);    //levý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[4].x, cube1.points[4].y, cube1.points[4].z);    //pravý dolní vrchol textury a výsledného čtverce

      //druhý trojúhelník
      glTexCoord2f( 1, 1);  glVertex3f( cube1.points[5].x, cube1.points[5].y, cube1.points[5].z);    //pravý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[4].x, cube1.points[4].y, cube1.points[4].z);    //pravý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[3].x, cube1.points[3].y, cube1.points[3].z);    //levý horní vrchol textury a výsledného čtverce

      //-------------------------

      //zadní stěna krychle
      //první trojúhelník
      glTexCoord2f( 0, 0);  glVertex3f( cube1.points[4].x, cube1.points[4].y, cube1.points[4].z);    //levý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[5].x, cube1.points[5].y, cube1.points[5].z);    //levý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[6].x, cube1.points[6].y, cube1.points[6].z);    //pravý dolní vrchol textury a výsledného čtverce

      //druhý trojúhelník
      glTexCoord2f( 1, 1);  glVertex3f( cube1.points[7].x, cube1.points[7].y, cube1.points[7].z);    //pravý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[6].x, cube1.points[6].y, cube1.points[6].z);    //pravý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[5].x, cube1.points[5].y, cube1.points[5].z);    //levý horní vrchol textury a výsledného čtverce

      //-------------------------

      //levá stěna krychle
      //první trojúhelník
      glTexCoord2f( 0, 0);  glVertex3f( cube1.points[6].x, cube1.points[6].y, cube1.points[6].z);    //levý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[7].x, cube1.points[7].y, cube1.points[7].z);    //levý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[0].x, cube1.points[0].y, cube1.points[0].z);    //pravý dolní vrchol textury a výsledného čtverce

      //druhý trojúhelník
      glTexCoord2f( 1, 1);  glVertex3f( cube1.points[1].x, cube1.points[1].y, cube1.points[1].z);    //pravý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[0].x, cube1.points[0].y, cube1.points[0].z);    //pravý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[7].x, cube1.points[7].y, cube1.points[7].z);    //levý horní vrchol textury a výsledného čtverce

      //-------------------------

      //vrchní stěna krychle
      //první trojúhelník
      glTexCoord2f( 0, 0);  glVertex3f( cube1.points[1].x, cube1.points[1].y, cube1.points[1].z);    //levý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[7].x, cube1.points[7].y, cube1.points[7].z);    //levý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[3].x, cube1.points[3].y, cube1.points[3].z);    //pravý dolní vrchol textury a výsledného čtverce

      //druhý trojúhelník
      glTexCoord2f( 1, 1);  glVertex3f( cube1.points[5].x, cube1.points[5].y, cube1.points[5].z);    //pravý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[3].x, cube1.points[3].y, cube1.points[3].z);    //pravý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[7].x, cube1.points[7].y, cube1.points[7].z);    //levý horní vrchol textury a výsledného čtverce

      //-------------------------

      //spodní stěna krychle
      //první trojúhelník
      glTexCoord2f( 0, 0);  glVertex3f( cube1.points[6].x, cube1.points[6].y, cube1.points[6].z);    //levý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[0].x, cube1.points[0].y, cube1.points[0].z);    //levý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[4].x, cube1.points[4].y, cube1.points[4].z);    //pravý dolní vrchol textury a výsledného čtverce

      //druhý trojúhelník
      glTexCoord2f( 1, 1);  glVertex3f( cube1.points[2].x, cube1.points[2].y, cube1.points[2].z);    //pravý horní vrchol textury a výsledného čtverce
      glTexCoord2f( 1, 0);  glVertex3f( cube1.points[4].x, cube1.points[4].y, cube1.points[4].z);    //pravý dolní vrchol textury a výsledného čtverce
      glTexCoord2f( 0, 1);  glVertex3f( cube1.points[0].x, cube1.points[0].y, cube1.points[0].z);    //levý horní vrchol textury a výsledného čtverce

      //-------------------------


    glEnd();  //ukonči vykreslování trojúhelníků
    glPopMatrix;    //konec prostorové matice
    //konec bloku OpenGL příkazu pro vykreslení objektu (krychle)
}
V této funkci DrawCube() konečně používáme OpenGL příkazy. Všechny předešlé funkce nemají s OpenGL nic společného. Provádějí jen náčítání hodnot ze souboru cube.txt a výpočet pohybu a rotace.

glTranslatef( translate.x, translate.y, translate.z); - pohybuje objektem v X,Y,Z směru, podle předem vypočtených hodnot translate.x, translate.y, translate.z

glRotatef( angle.x, 1, 0, 0);
glRotatef( angle.y, 0, 1, 0);
glRotatef( angle.z, 0, 0, 1); - rotují objektem v X,Y,Z směru, podle předem vypočtených hodnot angle.x, angle.y, angle.z

glVertex3f( cube1.points[0].x, cube1.points[0].y, cube1.points[0].z);
glVertex3f( cube1.points[1].x, cube1.points[1].y, cube1.points[1].z);
glVertex3f( cube1.points[2].x, cube1.points[2].y, cube1.points[2].z);
glVertex3f( cube1.points[3].x, cube1.points[3].y, cube1.points[3].z);
glVertex3f( cube1.points[4].x, cube1.points[4].y, cube1.points[4].z);
glVertex3f( cube1.points[5].x, cube1.points[5].y, cube1.points[5].z);
glVertex3f( cube1.points[6].x, cube1.points[6].y, cube1.points[6].z);
glVertex3f( cube1.points[7].x, cube1.points[7].y, cube1.points[7].z); - vykreslí krychli z trojúhelníků, podle načtených hodnot cube1.points[ ], ze souboru cube.txt

Při ukončování aplikace nesmíme zapomenout vymazat objekt z paměti.
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
   ...
   ...
   ...
    DeleteAllObjects();    //vymaž objekty z paměti
}

//---------------------------------------------------------------------------

void DeleteAllObjects()    //vymaž objekty
{
    cube1 = DeleteObject(&cube1);    //vymaž objekt cube1 z paměti
}

//---------------------------------------------------------------------------

TGLObject DeleteObject(TGLObject *k)    //vymaž objekt z paměti
{
    delete k->points;    //vymaž všechny body objektu z paměti
    delete k;    //vymaž objekt z paměti

    return *k;    //vrať funkci hodnotu k
}

Stejný tutorial pro Delphi najdete zde


2D textura Výpočet FPS a plynulé animace




Home