Tento tutorißl vßs nauΦφ pohyb objekt∙ ve 3D prostoru a kreslenφ bitmap bez Φern²ch mφst, zakr²vajφcφch objekty za nimi. Jednoduchou animaci a rozÜφ°enΘ pou₧itφ blendingu. Te∩ byste u₧ m∞li rozum∞t OpenGL velmi dob°e. NauΦili jste se vÜe od nastavenφ OpenGL okna, po mapovßnφ textur za pou₧itφ sv∞tel a blendingu. To byl prvnφ tutorißl pro st°edn∞ pokroΦilΘ. A pokraΦujeme dßle...
#include <windows.h>// HlaviΦkov² soubor pro Windows
#include <stdio.h>// HlaviΦkov² soubor pro standardnφ vstup/v²stup
#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
Twinkle urΦuje, zda se pou₧φvß t°pytiv² efekt a tp indikuje stisk klßvesy T.
bool twinkle;// T°pytiv² efekt
bool tp;// Stisknuto T?
Num urΦuje kolik hv∞zd bude zobrazeno na obrazovce. Je definovßno jako konstanta, tak₧e ho m∙₧ete m∞nit libovoln∞, ale jen v tomto °ßdku. NezkouÜejte m∞nit hodnotu num pozd∞ji v k≤du, pokud nechcete p°ivodit katastrofu.
const num=50;// PoΦet zobrazovan²ch hv∞zd
Deklarujeme strukturu, v nφ₧ budeme uchovßvat informace o jednotliv²ch hv∞zdßch.
typedef struct// Struktura hv∞zdy
{
int r, g, b;// Barva
GLfloat dist,// Vzdßlenost od st°edu
angle;// ┌hel natoΦenφ
} stars;// JmΘno struktury je stars
Ka₧dß polo₧ka v poli star obsahuje objekt struktury stars, tj. p∞t hodnot popisujφcφch hv∞zdu.
stars star[num];// Pole hv∞zd o velikosti num
Dßle vytvo°φme prom∞nnΘ pro nastavenφ vzdßlenosti pozorovatele (zoom) a ·hlu pozorovßnφ (tilt). Deklarujeme prom∞nnou spin natßΦejφcφ hv∞zdy okolo osy z, co₧ bude vypadat jako by se otßΦely okolo svΘ souΦasnΘ pozice. Loop je °φdφcφ prom∞nnß cyklu, kter² pou₧ijeme pro nakreslenφ vÜech padesßti hv∞zd. Texture[1] uklßdß jednu Φernobφlou texturu.
GLfloat zoom=-15.0f;// Hloubka v obrazovce
GLfloat tilt=90.0f;// ┌hel pohledu
GLfloat spin;// NatoΦenφ hv∞zd
GLuint loop;// ╪φdφcφ prom∞nnß cyklu
GLuint texture[1];// Uklßdß texturu
Hned po p°edchßzejφcφm k≤du p°idßme k≤d pro nahrßnφ textury. Nebudu jej znovu opisovat. Je to ten sam² jako v lekci 6, 7 a 8. Bitmapa, kterou tentokrßt nahrajeme je nazvßna star.bmp. Textura bude pou₧φvat lineßrnφ filtrovßnφ.
if(TextureImage[0]=LoadBMP("Data/Tim.bmp"))// Loading bitmapy
V tomto projektu nebudeme pou₧φvat hloubkovΘ testovßnφ, tak₧e pokud pou₧φvßte k≤d z lekce 1, ujist∞te se, ₧e jste odstranili volßnφ glDepthFunc(GL_LEQUAL); a glEnable(GL_DEPTH_TEST); jinak zφskßte velmi ÜpatnΘ v²sledky. NicmΘn∞ v tomto k≤du pou₧φvßme mapovßnφ textur, tak₧e se ujist∞te, ₧e jste p°idali °ßdky, kterΘ nejsou v lekci 1. VÜimn∞te si ₧e povolujeme mapovßnφ textur a blending.
int InitGL(GLvoid)// VÜechna nastavenφ OpenGL
{
if (!LoadGLTextures())// Nahraje textury
{
return FALSE;
}
glEnable(GL_TEXTURE_2D);// Zapne texturovΘ mapovßnφ
glShadeModel(GL_SMOOTH);// Povolφ jemnΘ stφnovßnφ
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// ╚ernΘ pozadφ
glClearDepth(1.0f);// Nastavenφ hloubkovΘho bufferu
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// NejlepÜφ perspektivnφ korekce
glBlendFunc(GL_SRC_ALPHA,GL_ONE);// Typ blendingu pro pr∙hlednost
glEnable(GL_BLEND);// Zapne blending
Nßsledujφcφ k≤d je nov². Nastavφ poΦßteΦnφ ·hel, vzdßlenost a barvu ka₧dΘ hv∞zdy. VÜimn∞te si jak je jednoduchΘ zm∞nit hodnoty ve struktu°e. SmyΦka projde vÜech 50 hv∞zd.
for (loop=0; loop<num; loop++)// Inicializuje hv∞zdy
{
star[loop].angle=0.0f;// VÜechny majφ na zaΦßtku nulov² ·hel
PoΦφtßm vzdßlenost pomocφ aktußlnφ hv∞zdy (hodnoty prom∞nnΘ loop), kterou d∞lφm maximßlnφm poΦtem hv∞zd. PotΘ nßsobφm v²sledek p∞ti. V podstat∞ to posune ka₧dou hv∞zdu o trochu dßle ne₧ tu p°edchßzejφcφ. Kdy₧ je loop 50 (poslednφ hv∞zda), loop d∞leno num je 1.0f. P°φΦina proΦ nßsobφm p∞ti je, ₧e 1*5= 5 a to je okraj obrazovky. Nechci aby hv∞zdy nebyly zobrazenΘ tak₧e 5.0f je perfektnφ. Pokud nastavφte hodnotu prom∞nnΘ zoom hloub∞ji do obrazovky, m∙₧ete pou₧φt hodnotu v∞tÜφ ne₧ 5.0f, ale hv∞zdy budou menÜφ (z d∙vodu perspektivy). VÜimn∞te si, ₧e barva ka₧dΘ hv∞zdy je tvo°ena pomocφ nßhodn²ch hodnot od 0 do 255. M∙₧ete se divit jak m∙₧eme pou₧φt tak velkΘ hodnoty, kdy₧ normßln∞ jsou hodnoty barev od 0.0f do 1.0f. Kdy₧ nastavujeme barvu, pou₧ijeme funkci glColor4ub namφsto glColor4f. ub znamenß unsigned byte, kter² m∙₧e nab²vat hodnot od 0 do 255. V tomto programu je jednoduÜÜφ pou₧φt byty ne₧ generovat desetinnΘ hodnoty.
star[loop].dist=(float(loop)/num)*5.0f;// Vzdßlenost od st°edu
star[loop].r=rand()%256;// Barva
star[loop].g=rand()%256;// Barva
star[loop].b=rand()%256;// Barva
}
return TRUE;
}
Na °adu p°ichßzφ vykreslovßnφ.
int DrawGLScene(GLvoid)// Vykreslovßnφ
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer
glBindTexture(GL_TEXTURE_2D, texture[0]);// V²b∞r textury
for (loop=0; loop<num; loop++)// Prochßzφ jednotlivΘ hv∞zdy
{
glLoadIdentity();// Reset matice
glTranslatef(0.0f,0.0f,zoom);// P°esun do obrazovky o zoom
glRotatef(tilt,1.0f,0.0f,0.0f);// Naklopenφ pohledu
Te∩ pohneme hv∞zdou. Prvnφ v∞c kterou ud∞lßme je pootoΦenφ okolo osy y. DalÜφ °ßdek k≤du posune hv∞zdu na ose x. Normßln∞ to znamenß posun na pravou stranu obrazovky, ale proto₧e jsme pootoΦili v²hled okolo osy y, kladnß hodnota osy x m∙₧e b²t kdekoli.
glRotatef(star[loop].angle,0.0f,1.0f,0.0f);// Rotace o ·hel konkrΘtnφ hv∞zdy
glTranslatef(star[loop].dist,0.0f,0.0f);// P°esun vp°ed na ose x
Hv∞zda je ve skuteΦnosti plochß textura. Pokud nakreslφte ploch² Φty°·helnφk a namapujete na n∞j texturu, bude to vypadat dob°e. Bude Φelem k vßm, jak mß. Ale kdy₧ scΘnu pootoΦφte o 90 stup≥∙ okolo osy y, textura bude Φelem k levΘ nebo pravΘ stran∞ obrazovky a vy uvidφte pouze tenkou linku, co₧ nechceme. Chceme aby hv∞zdy byly po°ßd Φelem k nßm nezßvisle na natoΦenφ a naklopenφ. Ud∞lßme to zruÜenφm vÜech rotacφ v opaΦnΘm po°adφ t∞sn∞ p°edtφm ne₧ vykreslφme hv∞zdu. PootoΦφme zp∞t zadßnφm invertovanΘho ·hlu pro rotaci a potΘ zruÜφme naklopenφ op∞t pomocφ zßpornΘho ·hlu. Proto₧e jsme d°φve posunuli poΦßtek, tak je na pozici ve kterΘ jsme ji cht∞li. Zm∞nili jsme jejφ polohu, ale texturu stßle vidφme sprßvn∞ zep°edu.
glRotatef(-star[loop].angle,0.0f,1.0f,0.0f);// ZruÜenφ pootoΦenφ
glRotatef(-tilt,1.0f,0.0f,0.0f);// ZruÜenφ naklopenφ
Jestli₧e je twinkle TRUE nakreslφme na obrazovku nerotujφcφ hv∞zdu. Pro zφskßnφ rozdφln²ch barev vezmeme maximßlnφ poΦet hv∞zd (num) a odeΦteme Φφslo aktußlnφ hv∞zdy (loop), potΘ odeΦteme 1, proto₧e loop nab²vß hodnot od 0 do num-1. Tφmto zp∙sobem zφskßme hv∞zdy rozdφln²ch barev. Nenφ to prßv∞ nejlepÜφ zp∙sob, ale je efektivnφ. Poslednφ hodnota je alfa hodnota. ╚φm je ni₧Üφ, tφm je hv∞zda pr∙hledn∞jÜφ. Pokud projde k≤d podmφnkou, bude ka₧dß hv∞zda nakreslena dvakrßt. To zpomalφ program. O kolik zßvisφ na vaÜem poΦφtaΦi, ale v²sledek bude stßt za to - smφsφ se barvy dvou hv∞zd. Proto₧e se nenatßΦφ, budou vypadat, jako by byly animovanΘ. VÜimn∞te si jak je jednoduchΘ p°idat barvu do textury. T°eba₧e je textura Φernobφlß, dostaneme takovou barvu, jakou zvolφme p°ed vykreslenφm.
if (twinkle)// Pokud je zapnut² t°pytiv² efekt
{
glColor4ub(star[(num-loop)-1].r,star[(num-loop)-1].g,star[(num-loop)-1].b,255);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();
}
Te∩ vykreslφme hlavnφ hv∞zdu. Jedin² rozdφl od p°edchßzejφcφho k≤du je, ₧e tato hv∞zda je natoΦena okolo osy z a mß jinou barvu (viz. indexy).
glRotatef(spin,0.0f,0.0f,1.0f);
glColor4ub(star[loop].r,star[loop].g,star[loop].b,255);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();
PootoΦφme hv∞zdu zv∞tÜenφm hodnoty prom∞nnΘ spin. PotΘ zm∞nφme ·hel ka₧dΘ hv∞zdy o loop/num. To znamenß, ₧e vzdßlen∞jÜφ hv∞zdy se otßΦφ rychleji. Nakonec snφ₧φme vzdßlenost hv∞zdy od st°edu, tak₧e to vypadß, ₧e jsou nasßvßny doprost°ed.
spin+=0.01f;// PootoΦenφ hv∞zd
star[loop].angle+=float(loop)/num;// Zv²Üenφ ·hlu hv∞zdy
star[loop].dist-=0.01f;// Zm∞na vzdßlenosti hv∞zdy od st°edu
Zkontrolujeme zda hv∞zda dosßhla st°edu. Pokud se tak stane, dostane novou barvu a je posunuta o 5 jednotek od st°edu, tak₧e m∙₧e op∞t zaΦφt svou cestu jako novß hv∞zda.
if (star[loop].dist<0.0f)// Dosßhla st°edu
{
star[loop].dist+=5.0f;// Novß pozice
star[loop].r=rand()%256;// Novß barva
star[loop].g=rand()%256;// Novß barva
star[loop].b=rand()%256;// Novß barva
}
}
return TRUE;
}
P°idßme k≤d zjiÜ¥ujφcφ stisk klßvesy T. P°ejd∞te k funkci WinMain(). Najd∞te °ßdek SwapBuffers(hDC). PφÜeme za n∞j.
// Funkce WinMain()
SwapBuffers(hDC);// Prohozenφ buffer∙
if (keys['T'] && !tp)// T - t°pytiv² efekt
{
tp=TRUE;
twinkle=!twinkle;
}
if (!keys['T'])// Uvoln∞nφ T
{
tp=FALSE;
}
if (keys[VK_UP])// èipka nahoru - naklonφ obraz
{
tilt-=0.5f;
}
if (keys[VK_DOWN])// èipka dolu - naklonφ obraz
{
tilt+=0.5f;
}
if (keys[VK_PRIOR])// PageUp - zv∞tÜφ hloubku
{
zoom-=0.2f;
}
if (keys[VK_NEXT])// PageDown - zmenÜφ hloubku
{
zoom+=0.2f;
}
A mßme hotovo. NauΦili jste se jednoduchou, ale celkem efektnφ animaci.
napsal: Jeff Molofee - NeHe
p°elo₧il: Milan Turek