Lekce 11 - Efekt vlnící se vlajky

Naučíme se jak pomocí sinusové funkce animovat obrázky. Pokud znáte standartní šetřič Windows "Létající 3D objekty" (i on by měl být programovaný v OpenGL), tak budeme dělat něco podobného.

Budeme vycházet z šesté lekce. Neopisuji celý zdrojový kód, takže možná bude lepší, když budete mít někde po ruce i zdrojový kód ze zmiňované lekce. První věc, kterou musíte udělat je vložit hlavičkový soubor matematické knihovny. Nebudeme pracovat s moc složitou matematikou, nebojte se, použijete pouze siny a kosiny.

#include <windows.h>// Hlavičkový soubor pro Windows

#include <stdio.h>// Hlavičkový soubor pro standardní vstup/výstup

#include <math.h>// Hlavičkový soubor pro matematickou knihovnu

#include <gl\gl.h>// Hlavičkový soubor pro OpenGL32 knihovnu

#include <gl\glu.h>// Hlavičkový soubor pro Glu32 knihovnu

#include <gl\glaux.h>// Hlavičkový soubor pro Glaux knihovnu

HDC hDC = NULL;// Privátní GDI Device Context

HGLRC hRC = NULL;// Trvalý Rendering Context

HWND hWnd = NULL;// Obsahuje Handle našeho okna

HINSTANCE hInstance;// Obsahuje instanci aplikace

bool keys[256];// Pole pro ukládání vstupu z klávesnice

bool active = TRUE;// Ponese informaci o tom, zda je okno aktivní

bool fullscreen = TRUE;// Ponese informaci o tom, zda je program ve fullscreenu

Deklarujte trojrozměrné pole bodů k uložení souřadnic v jednotlivých osách. Wiggle_count se použije k nastavení a následnému zjišťování, jak rychle se bude textura vlnit. Proměnná hold zajistí plynulé vlnění textury.

float points[45][45][3];// Pole pro body v mřížce vlny

int wiggle_count = 0;// Rychlost vlnění

GLfloat xrot;// Rotace na ose x

GLfloat yrot;// Rotace na ose y

GLfloat zrot;// Rotace na ose z

GLfloat hold;// Pomocná, k zajištění plynulosti pohybu

GLuint texture[1];// Ukládá texturu

Přesuňte se dolů k funkci LoadGLTexture(). Budete používat novou texturu s názvem Tim.bmp, takže najděte funkci LoadBMP("Data/NeHe.bmp") a přepište ji tak, aby nahrávala nový obrázek.

if(TextureImage[0]=LoadBMP("Data/Tim.bmp"))// Loading bitmapy

Teď přidejte následující kód na konec funkce InitGL(). Výsledek uvidíte na první pohled. Přední strana textury bude normálně vybarvená, ale jak se po chvíli obrázek natočí, zjistíte, že ze zadní strany zbyl drátěný model. GL_FILL určuje klasické kreslení polygony, GL_LINES vykresluje pouze okrajové linky, při GL_POINTS by šlo vidět pouze vrcholové body. Která strana polygonu je přední a která zadní nelze určit jednoznačně, stačí rotace a už je to naopak. Proto vznikla konvence, že mnohoúhelníky, u kterých byly při vykreslování zadány vrcholy proti směru hodinových ručiček jsou přivrácené.

// Konec funkce InitGL()

glPolygonMode(GL_BACK, GL_FILL);// Přední strana vyplněná polygony

glPolygonMode(GL_FRONT, GL_LINE);// Zadní strana vyplněná mřížkou

Následující dva cykly inicializují naši síť. Abychom dostali správný index musíme dělit řídící proměnou smyčky pěti (tzn. 45/9=5). Odčítám 4,4 od každé souřadnice, aby se vlna vycentrovala na počátku souřadnic. Stejného efektu může být dosaženo s pomocí posunutí, ale já mám radši tuto metodu. Hodnota points[x][y][2] je tvořená hodnotou sinu. Funkce sin() potřebuje radiány, tudíž vezmeme hodnotu ve stupních, což je naše x/5 násobené čtyřiceti a pomocí vzorce (radiány=2*PÍ*stupně/360) ji přepočítáme.

for (int x=0; x<45; x++)// Inicializace vlny

{

for (int y=0; y<45; y++)

{

points[x][y][0]=float((x/5.0f)-4.5f);

points[x][y][1]=float((y/5.0f)-4.5f);

points[x][y][2]=float(sin((((x/5.0f)*40.0f)/360.0f)*3.141592654*2.0f));

}

}

return TRUE;

}

Na začátku vykreslovací funkce deklarujeme proměnné. Jsou použity jako řídící v cyklů. Uvidíte je v kódu níž, ale většina z nich neslouží k něčemu jinému než, že kontrolují cykly a ukládají dočasné hodnoty

int DrawGLScene(GLvoid)// Vykreslování

{

int x, y;

float float_x, float_y, float_xb, float_yb;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Smaže obrazovku a hloubkový buffer

glLoadIdentity();// Reset matice

glTranslatef(0.0f,0.0f,-12.0f);// Posunutí do obrazovky

glRotatef(xrot,1.0f,0.0f,0.0f);// Rotace na ose x

glRotatef(yrot,0.0f,1.0f,0.0f);// Rotace na ose y

glRotatef(zrot,0.0f,0.0f,1.0f);// Rotace na ose z

glBindTexture(GL_TEXTURE_2D, texture[0]);// Výběr textury

Všimněte si, že čtverce jsou kresleny po směru hodinových ručiček. Z toho plyne, že čelní plocha, kterou vidíte bude vyplněná a zezadu bude drátěný model. Pokud bychom čtverce vykreslovali proti směru hodinových ručiček drátěný model by byl na přední straně.

glBegin(GL_QUADS);// Začátek kreslení čtverců

for( x = 0; x < 44; x++ )// Cykly procházejí pole

{

for( y = 0; y < 44; y++ )

{

Každý z polygonů (čtverce v síti) má 1/44x1/44 textury. Cyklus určuje levý dolní bod (první 2 řádky). Poté spočítáme pravý horní (další 2 řádky). Takže máme dva body na úhlopříčce čtverce a kombinací hodnot jejich souřadnic získáme zbylé dva body na textuře.

// Vypočítání texturových koordinátů

float_x = float(x)/44.0f;

float_y = float(y)/44.0f;

float_xb = float(x+1)/44.0f;

float_yb = float(y+1)/44.0f;

// Zadání jednotlivých bodů

glTexCoord2f(float_x, float_y);

glVertex3f(points[x][y][0], points[x][y][1], points[x][y][2]);

glTexCoord2f(float_x, float_yb);

glVertex3f(points[x][y+1][0], points[x][y+1][1], points[x][y+1][2]);

glTexCoord2f(float_xb, float_yb);

glVertex3f(points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2]);

glTexCoord2f(float_xb, float_y);

glVertex3f(points[x+1][y][0], points[x+1][y][1], points[x+1][y][2]);

}

}

glEnd();// Konec kreslení čtverců

Při sudém vykreslení v pořadí přesuneme souřadnice v poli do sousedních souřadnic a tím přesuneme i vlnu o kousek vedle. Celý první sloupec (vnější cyklus) postupně ukládáme do pomocné proměnné. Potom o kousek přesuneme vlnu jednoduchým přiřazením každého prvku do sousedního a nakonec přiřadíme uloženou hodnotu okraje na opačný konec obrázku. Tím vzniká dojem, že když mizí jedna vlna, okamžitě začíná vznikat nová, ale programově je to konec té staré :-] Zjednodušeně řečeno máme jen jednu vlnu, která se po opuštění obrázku přesouvá na začátek. Nakonec vynulujeme wiggle_count, abychom udrželi animaci v chodu.

if (wiggle_count == 2)// Pro snížení rychlosti pohybu

{

for (y = 0; y < 45; y++)// Prochází hodnoty na y

{

hold=points[0][y][2];// Uloží kraj vlny

for (x = 0; x < 44; x++)// Prochází hodnoty na x

{

points[x][y][2] = points[x+1][y][2];// Přiřazení do sousedního prvku

}

points[44][y][2]=hold;// Uložený kraj bude na druhé straně

}

wiggle_count = 0;// Nulování počítadla vykreslování

}

wiggle_count++;// Inkrementace počítadla

Aktualizujeme rotaci a ukončíme funkci.

xrot+=0.3f;

yrot+=0.2f;

zrot+=0.4f;

return TRUE;

}

Zkompilujte a spusťte program. Z přední strany byste měli vidět hezkou vlnící se bitmapu a po následném natočení z ní zůstane pouze drátěný model.

napsal: Bosco <bosco4 (zavináč) home.com>
přeložil: Michal Turek - Woq <WOQ (zavináč) seznam.cz>

Zdrojové kódy

Lekce 11

<<< Lekce 10 | Lekce 12 >>>