http://alpha-thema-online.uv.ro
Fa-ti si tu propriul forum, pe www.myforum.ro!
Pagina de start a forumului http://alpha-thema-online.uv.ro Autentificare Inregistrare FAQ Membri Cautare

Pagina de start a forumului http://alpha-thema-online.uv.ro » C / C++ / C# » Multitexturi in OpenGL C++
Creaza un subiect nou  Raspunde la subiect Subiectul anterior :: Subiectul urmator 
Multitexturi in OpenGL C++
MesajTrimis: 14/07/2007 09:37 Raspunde cu citat (quote)
Ad_Infinitum
Administrator
Administrator
Ad_Infinitum
Data inscrierii: 23/Iun/2007
Mesaje: 212




Acest tutorial se bazeaza pe cel anterior in care am prezentat modul cum se poate incarca un teren dintr-o imagine monocroma si cum se poate randa acel teren utilizand array-uri de date. Intreg tutorialul de acum este construit peste cel anterior, prin adaugarea de date suplimentare.

Poate ati observat ca atunci cand va apropiati de teren calitatea imaginii scade considerabil si aceasta datorita faptului ca imaginea utilizata drept textura pentru teren are o dimensiune limitata. Chiar daca am utiliza o textura de mărimi mai mari nu am rezolva problema căci efectele respective vor aparea in continuare cand ne vom apropia si mai mult de teren. Trebuie gasita o metoda prin care sa conferim terenului un alură mai realist, sa apara cu neregularitati, cu detalii mai multe. Aceasta o vom realiza prin adaugare unei noi texturi, numita textura de detaliu. Textura pe care am utilizat-o pana acum pentru teren poarta numele de obicei de textura de colorație deoarece ea da in de frunte doar culoarea zonelor de teren, detaliul fiind dat de textura a doua.

[img] http://www.itzone.ro/upload_img/tutoriale/tutorial_49/164_poza1.gif [/img]

Textura de detaliu este in general monocroma deoarece ea se aplica peste textura de culoare prin operatia de blending si nu necesita informatie de culoare. Aceasta nu este insa obligatoriu, textura de detaliu putand fi colorata daca se doreste acest lucru.

Multitexturi in OpenGL C++ Multitexturi in OpenGL C++

Avantajul texturii de detaliu este ca ea nu trebuie sa fie intinsa peste intreg terenul ca si textura de culoare, ci este tile-ata de un anumit numar de ori pana convine aspectului dorit pentru terenul respectiv.
Multitexturi in OpenGL C++ Multitexturi in OpenGL C++

Textura de detaliu se repeta de N ori pe intreaga suprafata a terenului de aceea trebuie ca ea sa fie tile-abila, adica partea de sus sa se continue jos iar cea din stanga in dreapta.
Respectand aceste conditii, textura poate fi multiplicata de oricate ori se doreste. Cu cat este multiplicata de un numar mai mare de ori, cu atat se va vedea mai bine terenul la o distanta mai mica. Numarul N corespunde unui nou penis al clasei de teren si anume m_fDetailScaleFactor.

Acest membru se declara in clasa CMTerrain dupa cum urmeaza:
float m_fDetailScaleFactor;

Sa prezentam in continuare modul de aplicare al texturii de detaliu. Putem aplica textura in doua moduri. Inițialul este cel mai dezavantajos din punctul de vedere al penalizarii aduse asupra performantei si se realizeaza prin randarea intregului teren cu textura de detaliu peste terenul randat cu textura de culoare. Nu este o medoda cumplit de buna tinand cont ca terenul are 65 de mii de triunghiuri. Prin aceasta metoda vom randa 130 de mii de triunghiuri per frame ceea ce nu reprezinta deloc o solutie convenabila. Asa ca pentru a adauga detaliul in mod eficace vom utiliza resursele hardware ale placilor video, resurse construite particular in acest scop. Incepand cu 1999, placile video au marit constant numarul de unitati de texturare proiectate sa lucreze in paralel. Noi vom utiliza numai 2.

Cum functioneaza multitexturingul?
Ideea este simpla. Pentru fiecare vertex randat, nu se dau o pereche de coordonate de textura, ci doua perechi, cate una pentru fiecare textura. Pipeline-ul grafic va culege in timp real culorile din cele doua texturi si le va combina intr-un singur pixel de pe ecran.

Multitexturi in OpenGL C++ Multitexturi in OpenGL C++

Nu avem insa niciodata certitudinea ca placa video are unitatile respective ‘sub capota’ asa ca mai intai trebuite sa verificam daca avem activa extensia OpenGL aferenta.

Extensia OpenGL pentru a lucra cu mai multe unitati de texturare se numeste GL_ARB_multitexture. Ea este reprezentata prin 3 functii care trebuie declarate la inceputul programului. Pentru a putea utiliza functiile trebuie inclus headerul general pentru extensii “glext.h” la dispoziție pe site-ul oficial OpenGL, opengl.org.

PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;


glMultiTexCoord2fARB se utilizeaza atunci cand dorim sa specificam in mod explicit coordonatele pentru fiecare vertex si se utilizeaza in modul de randare “imediat”, adica nu cu vertex arrays (ci cu glBegin()..glEnd(), ati priceput).

GlActiveTextureARB si glClientActiveTextureARB sunt functiile pe care le vom folosi in program. In principal ele selecteaza unitatea curenta de lucru pentru OpenGL.

Pentru a utiliza insa functiile trebuie sa le intializam mai intain si asta fiindcă implicit multitexturingul este dezactivat. Functia de initializare a multitexturing-ului pe care am utilizat-o este urmatoarea:


Citat:

bool bIsMultitexture;

bool InitMultitexturing()
{
// obtinem lista cu toate extensiile suportate de placa video curenta
szExtensions = glGetString(GL_EXTENSIONS);

// verificam daca avem stringul ce ne indica prezenta multitexturing-ului
if(!strstr((char*)szExtensions, "GL_ARB_multitexture"))
{
// nu avem multitexturing
bIsMultitexture = false;
return false;
}

// cerem adresele functiilor
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress ("glActiveTextureARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress ("glMultiTexCoord2fARB");
glClientActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress ( "glClientActiveTextureARB");
// setam flag-ul de multitexturing in functie de rezultatul anterior
if(glActiveTextureARB && glMultiTexCoord2fARB && glClientActiveTextureARB)
bIsMultitexture = true;
else
bIsMultitexture = false;

return bIsMultitexture;
}


Dupa cum se vede, cerem sistemului sa ne returneze adresele functiilor insa numai dupa ce am verificat daca printre extensiile suportate se afla si GL_ARB_multitexture.

Ultima parte a functiei generale Init() a programului se modifica in felul urmator:

Citat:

if(!InitMultitexturing())
{
MessageBox(NULL, "Placa video nu suporta multitexturing", "Eroare", MB_OK);
exit(1);
}

LoadTGA("cer.tga", &nSkyTex);

g_Teren.LoadBaseTexture("teren.tga");
g_Teren.LoadDetailTexture("detail.tga");
g_Teren.LoadHeightmap("harta.bmp");
g_Teren.m_bLighting = false;

g_Cam.set_pos(100, 40, 100);
g_Cam.set_orientation(20.0f, 0.0f, 0.0f);
bWireframe = false;
bAutoRotate = true;




Textura de detaliu se incarca printr-o noua functie care a fost adaugata clasei CMTerrain si anume LoadDetailTexture:

Citat:

void CMTerrain::LoadDetailTexture(char* szTexName)
{
LoadTGA(szTexName, &m_nTexture[1]);
}




Nu mai avem altceva de facut decat sa prezentam noul mod de randare al terenului cu multitexturing. De fapt modificarile nu sunt foarte mari, randarea executandu-se la fel. Ceea ce se altera este initializarea randarii si anume atasarea unei noi texturi pe unitatea a doua de texturare. Iata noua functie Render() a clasei CMTerrain:

Citat:

void CMTerrain::Render()
{
if(m_bWireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

if(m_pTData)
{
// ========= COD NOU ===============
if(m_nTexture[1] > 0 && m_bShowDetail)
{
// activam unitatea 1 de texturare
glClientActiveTextureARB(GL_TEXTURE1_ARB);

// dam pointerul catre array-ul de coordonate de textura
// (este acelasi ca si pentru unitatea 0 de texturare)
glTexCoordPointer(2, GL_FLOAT, sizeof(struct _MTexCoord), m_pTData);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_nTexture[1]);

// selectam modul de combinare al celor 2 unitati
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);

// scalam matricea de texturare de pe unitatea 1 in
// functie de factorul de detaliu dorit
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(m_fDetailScaleFactor, m_fDetailScaleFactor, 1.0f);
glMatrixMode(GL_MODELVIEW);

// ne intoarcem pe unitatea 0 de texturare
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
// ==========================

glTexCoordPointer(2, GL_FLOAT, sizeof(struct _MTexCoord), m_pTData);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, m_nTexture[0]);
glEnable(GL_TEXTURE_2D);
}

if(m_bLighting)
if(m_pNData)
{
glNormalPointer(GL_FLOAT, sizeof(struct _MVertex), m_pNData);
glEnableClientState(GL_NORMAL_ARRAY);
}

if(m_pVData)
{
glVertexPointer(3, GL_FLOAT, sizeof(struct _MVertex), m_pVData);
glEnableClientState(GL_VERTEX_ARRAY);
}

if(m_pIData)
glDrawElements(GL_TRIANGLE_STRIP, m_nIndicesNo, GL_UNSIGNED_INT, m_pIData);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

if(m_nTexture[1] > 0 && m_bShowDetail)
{
// activam unitatea 1 de texturare
glClientActiveTextureARB(GL_TEXTURE1_ARB);

// dezactivam array-ul de coordonate de textura
// de pe unitatea 1 de texturare
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);

// resetam matricea de texturare la matricea identitate
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);

// ne intoarcem pe unitatea 0 de texturare
glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}



Ceea ce prezinta interes este schimbarea unitatii de texturare curenta (cu care se lucreaza) si aceasta se realizeaza prin:

glClientActiveTextureARB( Gluint UNIT );

unde UNIT = GL_TEXTURE0_ARB …. (numarul maxim de unitati disponibile);

Numarul maxim de unitati disponibile pe placa video pe care ruleaza programul se obtine printr-un query adresat sistemului OpenGL astfel:

glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &MaxTexelUnits);

MaxTexelUnits este o variabila de tip intreg in care ni se returneaza numarul maxim de unitati disponibile. Orientativ, pe placile video pana la Geforce2 inclusiv exista 2 unitati de texturare in paralel iar pe Geforce 3 si Geforce 4 (nu MX) 4 unitati.

Dupa ce am selectat unitatea cu care lucram, toate operatiile se executa pe aceasta unitate. Daca atasam o textura, ea va fi atasata doar pe aceasta unitate. Terbuie sa activam si aici texturarea cu glEnable(GL_TEXTURE_2D), altfel nu vom putea utiliza textura proaspat atasata.

Prezinta interes instructiunile:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);

glTexEnvi se ocupa in de seamă cu setarea a diversi parametri legati de unitatile de texturare. Noi setam modul de combinare al celor 2 unitati la GL_COMBINE_ARB (exista multe alte chipuri disponibile, le puteti transforma pentru a vedea rezultatul asupra imaginii). Apoi setam scalarea in imagine a componentelor RGB la 2. Aceasta face ca imaginea rezultata sa fie ‘luminata’ artificial, sa fie mai luminoasa, cu un constrast mai bun. Se pot seta valorile 1,2 si 4, care reprezinta puteri. Valoarea 4 insa ofera o saturatie prea mare pentru teren si de aceea am folosit 2.

Se observa ca scalam matricea de texturare (atentie, numai pe cea de pe unitatea a doua de texturare) cu o valoare egala cu factorul de multiplicare al texturii de detaliu. Aceasta se face pentru a obtine o scalare a coordonatelor de textura deoarece aceste coordonate inainte sa fie aplicate pe vertecsi trec mai intai prin matricea GL_TEXTURE. Astfel scapam de necesitatea retinerii in memorie a unui array separat de coordonate de textura care sa serveasca doar unitatea a doua de texturare. Utilizam acelasi array ca si întâia unitate de texturare si schimbam doar scalarea matricii de textura pentru a obtine multiplicarea dorita a texturii.

Dupa ce se executa randarea, la dezactivarea array-urilor trebuie avut in vedere sa se dezactiveze si unitatea de texturare secundara utilizata ca de exemplu si refacerea matricii de texturare scalata eliminand astfel posibile consecințe nedorite.

Acesta este tutorialul, puteti sa experimentati cu multitexturingul pentru a adauga multiple efecte: lightmap, umbre nori, decals. Iata comparativ cum arata terenul cu si fara detaliul oferit de multitexturing (pe calculator se vede si mai clar, imaginea JPG de aici nu este la calitatea maxima).

Multitexturi in OpenGL C++ Multitexturi in OpenGL C++

Proiectul realizat in Visual C++ 6.0 . Utilizati tasta M pentru a comuta intre multitexturing On/Off si tasta Space pentru a opri miscarea camerei.

Autor Andrei pentru mai multe tutoriale vizitatzi http://www.itzone.ro/
Vezi profilul utilizatorului Trimite mesaj privat

Multitexturi in OpenGL C++
 Pagina de start a forumului http://alpha-thema-online.uv.ro » C / C++ / C#
Nu puteti crea un subiect nou in acest forum
Nu puteti raspunde in subiectele acestui forum
Nu puteti modifica mesajele proprii din acest forum
Nu puteti sterge mesajele proprii din acest forum
Nu puteti vota in chestionarele din acest forum
Ora este GMT + 3 ore  
Pagina 1 din 1  

  
  
 Creaza un subiect nou  Raspunde la subiect  


Fa-ti si tu propriul forum GRATUIT, pe www.myforum.ro
    Powered by phpBB © 2001-2004 phpBB Group. phpBB Skin by Vjacheslav Trushkin.