EliteHackers
SALUT 2022!! NE-AM MUTAT PE DISCORD ! Vrei să inviți un prieten? [T]eoria [H]aosului [C]ontrolat - https://discord.com/invite/U4HBCHzm7r Acesta aste link-ul oficial al acestui server.
Lista Forumurilor Pe Tematici
EliteHackers | Reguli | Inregistrare | Login

POZE ELITEHACKERS

Nu sunteti logat.
Nou pe simpatie:
Ioana Deea la Simpatie.ro
Femeie
24 ani
Prahova
cauta Barbat
24 - 49 ani
EliteHackers / Programare / Multitexturi in OpenGL C++ Moderat de Ad_Infinitum, AntiKiler, Puscas_marin, r3v
Autor
Mesaj Pagini: 1
Ad_Infinitum
Moderator

Inregistrat: acum 17 ani
Postari: 84
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 dimensiuni mai mari nu am rezolva problema deoarece 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 aspect 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 culoare deoarece ea da in principal doar culoarea zonelor de teren, detaliul fiind dat de textura a doua.

[img] [/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.



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.


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 membru 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. Primul 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 foarte 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 eficient vom utiliza resursele hardware ale placilor video, resurse construite special 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.



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” disponibil 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 deoarece implicit multitexturingul este dezactivat. Functia de initializare a multitexturing-ului pe care am utilizat-o este urmatoarea:




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:



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:



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 schimba este initializarea randarii si anume atasarea unei noi texturi pe unitatea a doua de texturare. Iata noua functie Render() a clasei CMTerrain:



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 principal 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 moduri disponibile, le puteti schimba 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 prima 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 precum si refacerea matricii de texturare scalata eliminand astfel posibile efecte nedorite.

Acesta este tutorialul, puteti sa experimentati cu multitexturingul pentru a adauga numeroase 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).



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


_______________________________________
Vizitati pentru mai multe tutoriale )

pus acum 17 ani
   
Pagini: 1  

Mergi la