Teksturowanie brył
Wykorzystując biblioteki OpenGL i GLUT napisać program przedstawiający perspektywiczny obraz elipsoidy, na który została odwzorowana dwuwymiarowa tekstura RGBA zdefiniowana wzorcem:

Obiekt oświetlony jest białym światłem ze źródła reflektorowego (spot), a parametry jego materiału mają wartości domyślne, z wyjątkiem GL_SPECULAR, który ma przyjmować wartość (1.0, 1.0, 1.0, 1.0). Użytkownik powinien mieć możliwość:
- Zmiany rozmiarów tekstury w zakresie od 4×4 do 128×128 tekseli z zachowaniem proporcji wzorca.
- Powielania tekstury w zakresie od 1 do 5 niezależnie w kierunku poziomym i pionowym (GL_REPEAT).
- Zmiany metody filtrowania tekstury (GL_NEAREST, GL_LINEAR)
- Zmiany trybu teksturowania (GL_DECAL, GL_MODULATE, GL_BLEND)
- Zmiany położenia źródła światła.
- Zmiany położenia obserwatora poprzez podanie następujących parametrów:
- odległości obserwatora od środka układu współrzędnych sceny,
- wysokości względem płaszczyzny XZ,
- kąta obrotu wokół osi OY w zakresie [0o, 360o] z krokiem 1o.
Oświetlony obiekt powinien zawsze znajdować się w centralnej części okna.
Zadanie rozpocząłem od zamodelowania elipsoidy.
x=2*r*cos(DEGRAD(v))*cos(DEGRAD(u)); y=r*sin(DEGRAD(v)); z=r*cos(DEGRAD(v))*sin(DEGRAD(u)); wejscie[0][0]=x; wejscie[0][1]=y; wejscie[0][2]=z; x=2*r*cos(DEGRAD(v+f))*cos(DEGRAD(u)); y=r*sin(DEGRAD(v+f)); z=r*cos(DEGRAD(v+f))*sin(DEGRAD(u)); wejscie[1][0]=x; wejscie[1][1]=y; wejscie[1][2]=z; x=2*r*cos(DEGRAD(v+f))*cos(DEGRAD(u+e)); y=r*sin(DEGRAD(v+f)); z=r*cos(DEGRAD(v+f))*sin(DEGRAD(u+e)); wejscie[2][0]=x; wejscie[2][1]=y; wejscie[2][2]=z; x=2*r*cos(DEGRAD(v))*cos(DEGRAD(u+e)); y=r*sin(DEGRAD(v)); z=r*cos(DEGRAD(v))*sin(DEGRAD(u+e)); wejscie[3][0]=x; wejscie[3][1]=y; wejscie[3][2]=z;
Tablica dwuwymiarowa wejście zbiera współrzędne punktów do utworzenia wektora normalnego. Następnie musimy przekazać te parametry do funkcji glVertex, zanim jednak to zrobimy należy podać listy wierzchołków obiektu oraz odpowiednio dobrane koordynaty tekstury. Ma to na celu odpowiednie nałożenie tekstury na obiekt, tzn. prawa górna część obiektu powinna odpowiadać prawej górnej części tekstury itd. Służy do tego funkcja GLtexcoord2f. Wywołuje się ją przed wywołaniem funkcji rysującej każdy wierzchołek obiektu. Przyjmuje ona dwa parametry w zakresie od 0.0 do 1.0. Pierwszy parametr określa składową x. Podanie wartości 0.0 jako pierwszego parametru oznacza skrajnie lewą stronę tekstury, natomiast 1.0 wyznacza prawą część tekstury. Analogicznie należy postępować podając wartości w drugim parametrze. Wartość 0.0 oznacza dolną część tekstury, a 1.0 górną. Łącząc odpowiednie części tekstury z odpowiednimi częściami obiektu uzyskuje się optymalny obraz obiektu. Realizuje to kod:
ObliczanieWektora(wejscie,wektor); glNormal3f(wektor[0],wektor[1],wektor[2]); glTexCoord2f(0.0, 0.0); glVertex3fv(wejscie[0]); glTexCoord2f(0.0, 1.0); glVertex3fv(wejscie[1]); glTexCoord2f(1.0, 1.0); glVertex3fv(wejscie[2]); glTexCoord2f(1.0, 0.0); glVertex3fv(wejscie[3]);
Następnym krokiem będzie zdefiniowanie tekstury. W tym celu tworzę teksturę, która rozumiana jest jako prostokątna tablica zawierająca w każdym elemencie wartości składowe koloru R, G, B, A lub jasności.
float kolor1[4]={1.0,0.0,0.0,1.0};
float kolor2[4]={1.0,1.0,1.0,0.9};
for(i=0;i=(size-ctw)){
*(wsk++) = kolor1[0];
*(wsk++) = kolor1[1];
*(wsk++) = kolor1[2];
*(wsk++) = kolor1[3];
}
else {
*(wsk++) = kolor2[0];
*(wsk++) = kolor2[1];
*(wsk++) = kolor2[2];
*(wsk++) = kolor2[3];
}
}
for(i=0;i=(size-ptw)){
*(wsk++) = kolor1[0];
*(wsk++) = kolor1[1];
*(wsk++) = kolor1[2];
*(wsk++) = kolor1[3];
}
else {
*(wsk++) = kolor2[0];
*(wsk++) = kolor2[1];
*(wsk++) = kolor2[2];
*(wsk++) = kolor2[3];
}
}
glTexImage2D(GL_TEXTURE_2D,0,4,size,size,0,GL_RGBA,GL_FLOAT,tekstura);
W pierwszych dwóch tablicach float zostały zdefiniowane dwa kolory – czerwony i biały. Parametr alpha został wstępnie ustawiony na 0.9 aby było widać ustawioną teksturę. Kiedy tekstura (tablica) jest już utworzona można ją zdefiniować. Do definiowania dwuwymiarowej tekstury służy funkcja
glTexImage2D(rodzaj, poziom, kolory, szerokość, wysokość, ramka, format, typ, punkty);
rodzaj – rodzaj tekstury; powinno wynosić GL_TEXTURE_2D
poziom – poziom szczegółów mipmapy; jeśli mipmapy nie są używane wynosi 0
kolory – ilość komponentów koloru; może wynosić od 1 do 4
szerokość – szerokość obrazu tekstury; musi być potęgą liczby 2 powiększoną ewentualnie o szerokość ramki wokół tekstury
wysokość – wysokość obrazu tekstury; musi być potęgą liczby 2 powiększoną ewentualnie o wysokość ramki wokół tekstury
ramka – rozmiar ramki wokół obrazu tekstury; może wynosić 0, 1 lub 2
format – format danych (możliwe wartości podano w tabeli poniżej)
typ – typ danych dla wartości punktów (możliwe wartości podano w tabeli poniżej)
punkty – tablica o rozmiarze szerokość x wysokość x kolory zawierająca dane
Parametry tekstury ustawiam za pomocą funkcji:
glTexImage2D(GL_TEXTURE_2D,0,4,size,size,0,GL_RGBA,GL_FLOAT,tekstura); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,filtr); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,filtr); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,tryb); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); if(tryb==GL_BLEND) glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,kolor);
glTexParameteri(tekstura, parametr, wartość);
Umożliwia ona między innymi ustalenie w jaki sposób będą przeprowadzane operacje związane z obliczaniem wartości kolorów brakujących pikseli w przypadku nakładania tekstury na obiekt mniejszy od rozmiaru tekstury (czyli przy powiększaniu), czy też jak ma przebiegać ukrywanie pikseli przy zmniejszaniu tekstury. Danymi wejściowymi funkcji są:
tekstura – rodzaj tekstury: GL_TEXTURE_1D lub GL_TEXTURE_2D
parametr – jeden z parametrów z poniższej tabeli
wartość – wartość dla parametru
Parametry wejściowe:
GL_TEXTURE_MIN_FILTE – Określa sposób zmniejszania tekstury; możliwe wartości:
- GL_NEAREST – brakujący punkt przyjmuje kolor sąsiedniego
- GL_LINEAR – liniowa interpolacja pikseli
- GL_NEAREST_MIPMAP_NEAREST – przyjmowana jest mipmapa najbliższa rozmiarem do pokrywanego wielokąta; przy teksturowaniu brakujące punkty przyjmują kolor najbliższych
- GL_NEAREST_MIPMAP_LINEAR – przyjmowana jest mipmapa najbliższa rozmiarem do pokrywanego wielokąta; przy teksturowaniu wykorzystywana jest liniowa interpolacja
- GL_LINEAR_ MIPMAP_NEAREST – interpolowane są dwie mipmapy najbliższe rozmiarowi pokrywanego wielokąta; przy teksturowaniu brakujące punkty przyjmują kolor najbliższych
- GL_LINEAR_ MIPMAP_LINEAR – interpolowane są dwie mipmapy najbliższe rozmiarowi pokrywanego wielokąta; przy teksturowaniu wykorzystywana jest liniowa interpolacja
GL_TEXTURE_MAX_FILTER – Określa sposób powiększania tekstury; możliwe wartości:
- GL_NEAREST – brakujący punkt przyjmuje kolor sąsiedniego
- GL_LINEAR – liniowa interpolacja pikseli
GL_TEXTURE_WRAP_S – Określa sposób traktowania współrzędnej S tekstury poza zakresem od 0.0 do 1.0; możliwe wartości:
- GL_CLAMP – poza zakresem używany jest kolor ramki tekstury lub stały kolor
- GL_REPEAT – tekstura jest powtarzana na całej powierzchni wielokąta
GL_TEXTURE_WRAP_T – określa sposób traktowania współrzędnej T tekstury poza zakresem od 0.0 do 1.0; możliwe wartości:
- GL_CLAMP – poza zakresem używany jest kolor ramki tekstury lub stały kolor
- GL_REPEAT – tekstura jest powtarzana na całej powierzchni wielokąta
GL_BORDER_COLOR – Określa stały kolor ramki w przypadku, gdy tekstura nie posiada zdefiniowanej ramki; wartość stanowi wskaźnik do tablicy zawierającej składowe RGB koloru
Na koniec włączam teksturowanie dwuwymiarowe oraz wyłączam teksturowanie jednowymiarowe następującymi fukcjami:
glDisable(GL_TEXTURE_1D); glEnable(GL_TEXTURE_2D);
Tekstura została zamodelowana i nałożona na obiekt. Sprawdźmy więc jak wygląda nasza elipsoida przed oświetleniem. Aby sprawdzić czy prawidłowo zaprojektowaliśmy teksturę ustawimy parametr alpha koloru2 (białego) na 0.9.

Jak widać tekstura została prawidłowo zamodelowana. Kolor biały jest lekko prześwitujący. Ustawmy więc jego intensywność alpha na 0.3. Widok perspektywiczny.

Teraz włączymy oświetlenie. Oświetlanie brył zrealizowałem w sprawozdaniu do laboratorium nr 3, tak więc nie będę rozpisywał się w tym temacie. Kod realizujący oświetlenie bryły.
Parametry światła:
GLfloat swiatlo[10][4] = {{1.0,1.0,1.0,1.0},//[0] swiatlo otoczenia
{1.0,1.0,1.0,1.0},//[1]swiatlo rozproszone
{1.0,1.0,1.0,1.0},//[2] swiatlo zwierciadlane
{4.0,-1.0,4.0,1.0},//[3] polozenie w=0 to światło kierunkowe
{-4.0,1.0,-4.0,1.0},//[4] kierunek swieceniaGL_SPOT_DIRECTION
{90.0,0.0,0.0,0.0},//[5] kąt odcięcia GL_SPOT_CUTOFF
{10.0,0.0,0.0,0.0},//[6]tlumienie kątowe światła GL_SPOT_EXPONENT
Ustawienie parametrów materiału:
float material[5][4]={{1.0,0.0,0.8,1.0},//[0]wspolczynnik odbicia siwatłaotoczenia
{1.0,0.0,0.8,1.0},//[1]wspolczynik odbicia swiatla rozpraszanego
{1.0,1.0,1.0,1.0},//[2]wspolczynnik odbicia swiatla lustrzanego
{10.0,0.0,0.0,1.0},//[3] polysk jak widziany
{0.0,0.0,0.0,0.0}};//[4]kolor swiatla emitowanego
glMaterialfv(GL_FRONT,GL_AMBIENT,material[0]);
glMaterialfv(GL_FRONT,GL_DIFFUSE,material[1]);
glMaterialfv(GL_FRONT,GL_SPECULAR,material[2]);
glMaterialfv(GL_FRONT,GL_SHININESS,material[3]);
glMaterialfv(GL_FRONT,GL_EMISSION,material[4]);
}
Teraz włączamy oświetlenie:
glEnable(GL_LIGHTING); glLightfv(GL_LIGHT1,GL_AMBIENT,swiatlo[0]); glLightfv(GL_LIGHT1,GL_DIFFUSE,swiatlo[1]); glLightfv(GL_LIGHT1,GL_SPECULAR,swiatlo[2]); glLightfv(GL_LIGHT1,GL_POSITION,swiatlo[3]); glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,swiatlo[4]); glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, swiatlo[6][0]); glLightfv(GL_LIGHT1,GL_SPOT_CUTOFF,swiatlo[5]); glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, swiatlo[7][0]); glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, swiatlo[8][0]); glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, swiatlo[9][0]); glEnable(GL_LIGHT1); glPushAttrib(GL_LIGHTING_BIT); glPushMatrix(); glDisable(GL_LIGHTING); glTranslatef(swiatlo[3][0],swiatlo[3][1],swiatlo[3][2]); glColor3f(1.0,1.0,1.0); glutSolidSphere(0.3,20,20); glPopMatrix(); glPopAttrib();
Światło zostało włączone, oraz utworzony reflektor (sfera o promieniu 0.3). Efekt w programie.
TRYB GL_MODULATE (zmiana za pomocą klawisza M – shift+m)

TRYB GL_BLEND (zmiana za pomocą klawisza B – shift+b)

TRYB GL_DECAL (zmiana za pomocą klawisza D – shift+d)

Dlaczego uzyskaliśmy takie efekty w każdym z tych trybów?
Scharakteryzuję po krótce każdy z tych trybów:
GL_DECAL
Tryb zdefiniowany jest tylko dla wartości parametri internationalformat równej trzy lub cztery. Gdy liczba składowych jest równa trzy, pierwotny kolor obiektu jest zastępowany kolorem tekstury, wartość składowej alfa fragmentu pozostaje bez zmian. Przy czterech składowych natomiast pierwotny kolor obiektu jest mieszany z kolorem tekstury w proporcji uzależnionej od wartości składowej tekstury, wartość składowej alfa fragmentu pozostaje bez zmian.
GL_MODULATE
Tryb zdefiniowany jest dla wszystkich możliwych wartości internalformat. Przy liczbie składowych równej jeden lub dwa, pierwotny kolor obiektu mnożony jest przez liczbę określającą jasność tekstury, tak więc kolor obiektu jest modulowany jasnością tekstury. Wartość koloru obiektu zmienia się pierwotnego koloru (jasność równa 1.0) do koloru czarnego (jasność równa 0.0). Gdy liczba składowych jest równa trzy lub cztery, wówczas składowe RGB pierwotnego koloru obiektu mnożone są przez odpowiadające składowe koloru tekstury. Gdy wartość alfa występuje w teksturze (internalformat równy dwa lub cztery), wówczas wynikowa wartość alfa obliczana jest jako iloczyn składowej obiektu oraz tekstury. W przeciwnym razie pozostawiana jest bez zmian.
GL_BLEND
Tryb określany jest dla liczby składowych równej jeden oraz dwa. Wartość koloru wyznaczana jest poprzez zmieszanie pierwotnego koloru obiektu z kolorem ustalony przez GL_TEXTURE_ENV_COLOR. Proporcja w jakiej ma miejsce zmieszanie kolorów jest ustalona na podstawie jasności tekstury. Gdy liczba składowych równa jest jeden wartość alfa obiektu pozostanie bez zmian, natomiast gdy równa jest dwa wartość alfa ustalana jest przez pomnożenie składowych alfa tekstury oraz obiektu.
Kilka screenshotów z działania programu pokazujących obiekt w różnych perspektywach oraz przy różnym zagęszczeniu tekstury.


Dołączam kod do przeanalizowania programu:
Zawodowo inżynier informatyk, administrator sieci IT, programista, webdeveloper. Prywatnie przeciętny facet usiłujący spełnić kilka swoich marzeń. Strona powstała po to, aby podzielić się z Wami moimi osiągnięciami. Zapraszam ;)