Lekce 9

Lekce 9 - Pohyb bitmap ve 3D prostoru

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

ZdrojovΘ k≤dy

Lekce 9

<<< Lekce 8 | Lekce 10 >>>