|
Sky Box - vytváření oblohy a krajiny
|
|
|
Princip skyboxu je jednoduchý. Je to obyčejná krychle, složená ze šesti textur,
které na sebe navzájem navazují.
Při vytváření skyboxu jsem přišel na nepříjemný efekt. Tam, kde textury na sebe
navazovaly, se vytvořila čára. To se mi nelíbilo a proto jsem předělal původní
obrázky tak, že jsem kolem každého vytvořil černý rámeček o velikosti jednoho
pixelu. Každý čtverec skyboxu jsem pak posunul blíž ke kameře tak, aby černé rámečky
zmizely.
Skybox musí být dostatečně veliký, aby se do
něj vešla rozlehlá scéna. Pokud se však zadá větší hodnota mezi
nejbližším (near=1) a nejvzdálenějším (far=500) bodem, které jsou
definované ve funkci gluPerspective(), tak Depth Buffer začne zlobit a rozvlní
textury opět tam, kde jsou spojeny. To znamená, že skybox musí být veliký maximálně
500x500x500 jednotek.
Další fígl. Skybox chodí s kamerou, to znamená, že se nemůžeme dostat blízko
ke stěně skyboxu, nebo dokonce mimo něj.
No dost řečí a mrknem se na zdroják. Všechny funkce jsou obsaženy ve třídě KObject.
Nejdříve si načtem soubor skybox.txt pomocí funkcí LoadObject() a ReadLine()
|
|
//----------------------------------------------------------------------------------------------------//
void ReadLine(FILE *f,char *s) // Čti řádek ze souboru f a ukládej do řetězce s
{
do // Cykluj
{
fgets(s, 255, f); // Ćti znak po znaku maximálně však 255
} while ((s[0] == '/') || (s[0] == '\n')); // Dokud se nedostaneš na konec řádky
return; // Vrať funkci hodnotu načteného řádku
}
//----------------------------------------------------------------------------------------------------//
TGLObject LoadObject(char *name, TGLObject *k) // Načti objekt se souboru (name)
{
int ver; // Pomocná proměnná pro počet vrcholů objektu
GLfloat rx,ry,rz; // Pomocná proměnná pro X, Y, Z pozici vrcholu objektu
FILE *filein; // Definice souboru, ktery budeme číst
char oneline[255]; // Definice řádku souboru s maximálně 255 znaky
if ((filein = fopen(name, "rt"))== NULL) // Zkus otevřít soubor pro čtení v textovem módu "rt"
{
// Jestli se to nezdaří, vyhoď chybovou hlášku
MessageBox(NULL,"Cannot open input file","Error",MB_OK | MB_ICONSTOP);
}
else // Jinak pokračuj v práci s načteným souborem
{
ReadLine(filein,oneline); // Volej funkci pro načtení řádky ze souboru
sscanf(oneline, "Vertices: %d\n", &ver); // Přečti z první řádky počet vrcholů a výsledek předej proměnné ver
k->points = new TPoint3d[ver]; // Dynamicky alokuj paměť pro počet vrcholů objektu
k->verts = ver; // Načtenou hodnotu počtu vrcholů předej vrcholům objektu
for (int i=0;i<ver
;i++) // Cykluj podle počtu vrcholů
{
ReadLine(filein,oneline); // Čti řádek po řádku
sscanf(oneline, "%f %f %f", &rx, &ry, &rz); // Najdi v řádce tři čísla typu float a předej je hodnotám rx, ry, rz
k->points[i].x = rx; // Předej bodu X (aktuálniho vrcholu) hodnotu rx
k->points[i].y = ry; // Předej bodu Y (aktuálního vrcholu) hodnotu ry
k->points[i].z = rz; // Předej bodu Z (aktuálního vrcholu) hodnotu rz
}
fclose(filein); // Zavři soubor
}
return *k; // Vrať funkci hodnoty objektu
}
//----------------------------------------------------------------------------------------------------//
|
Funkce InitSkyBox() nám pak z načtených hodnot vytvoří skybox (krychli) a
posune každý čtverec o hodnotu aprox ke středu (kde bude kamera), aby zmizely čáry mezi texturama na
přechodu z jedné textury do druhé.
|
|
// Inicializuj Sky Box
void KObject::InitSkyBox(TPoint3d point0, // Texturová koordinace a pozice bodu 0
TPoint3d point1, // Texturová koordinace a pozice bodu 1
TPoint3d point2, // Texturová koordinace a pozice bodu 2
TPoint3d point3, // Texturová koordinace a pozice bodu 3
TPoint3d point4, // Texturová koordinace a pozice bodu 4
TPoint3d point5, // Texturová koordinace a pozice bodu 5
TPoint3d point6, // Texturová koordinace a pozice bodu 6
TPoint3d point7, // Texturová koordinace a pozice bodu 7
int TextureListNumber0, // Číslo Listu textury 0
int TextureListNumber1, // Číslo Listu textury 1
int TextureListNumber2, // Číslo Listu textury 2
int TextureListNumber3, // Číslo Listu textury 3
int TextureListNumber4, // Číslo Listu textury 4
int TextureListNumber5, // Číslo Listu textury 5
int ObjectListNumber) // Číslo Listu objektu
{
float aprox = 4.0f; // Hodnota přiblížení čtverců skyboxu. Čtverce se přibližují, aby zmizely spáry mezi nimi
// Nastav původní nastavení pozice bodů
TPoint3d origpoint0 , origpoint1, origpoint2, origpoint3, origpoint4, origpoint5, origpoint6, origpoint7;
origpoint0 = point0;
origpoint1 = point1;
origpoint2 = point2;
origpoint3 = point3;
origpoint4 = point4;
origpoint5 = point5;
origpoint6 = point6;
origpoint7 = point7;
// Nastav texturové koordinace
TPoint2d texcoord0, texcoord1, texcoord2, texcoord3;
texcoord0.x = 1.0f; // Texturová koordinace bodu 0
texcoord0.y = 1.0f;
texcoord1.x = 1.0f; // Texturová koordinace bodu 1
texcoord1.y = 0.0f;
texcoord2.x = 0.0f; // Texturová koordinace bodu 2
texcoord2.y = 0.0f;
texcoord3.x = 0.0f; // Texturová koordinace bodu 3
texcoord3.y = 1.0f;
glNewList(ObjectListNumber,GL_COMPILE); // Vytvoř Display List podle daného Object Display Listu
// Čelní stěna krychle
// Posuň celý čtverec blíž ke kameře, aby zmizely spáry
glBindTexture(GL_TEXTURE_2D, Texture1.TextureList[TextureListNumber0]); // Nastav texturu podle daného Texture Display Listu
point0.z -= aprox;
point1.z -= aprox;
point2.z -= aprox;
point3.z -= aprox;
// Vykresli čtverec
DrawTriangleFan(texcoord0, point0, // Texturová koordinace a pozice bodu 0
texcoord1, point1, // Texturová koordinace a pozice bodu 1
texcoord2, point2, // Texturová koordinace a pozice bodu 2
texcoord3, point3); // Texturová koordinace a pozice bodu 3
// Resetuj na původní hodnoty pozice bodů
point0 = origpoint0;
point1 = origpoint1;
point2 = origpoint2;
point3 = origpoint3;
// Pravá stěna krychle
// Posuň celý čtverec blíž ke kameře, aby zmizely spáry
glBindTexture(GL_TEXTURE_2D, Texture1.TextureList[TextureListNumber1]); // Nastav texturu podle daného Texture Display Listu
point3.x -= aprox;
point2.x -= aprox;
point4.x -= aprox;
point5.x -= aprox;
DrawTriangleFan(texcoord0, point3, // Texturová koordinace a pozice bodu 3
texcoord1, point2, // Texturová koordinace a pozice bodu 2
texcoord2, point4, // Texturová koordinace a pozice bodu 4
texcoord3, point5); // Texturová koordinace a pozice bodu 5
// Resetuj na původní hodnoty pozice bodů
point3 = origpoint3;
point2 = origpoint2;
point4 = origpoint4;
point5 = origpoint5;
// Zadní stěna krychle
// Posuň celý čtverec blíž ke kameře, aby zmizely spáry
point5.z += aprox;
point4.z += aprox;
point6.z += aprox;
point7.z += aprox;
glBindTexture(GL_TEXTURE_2D, Texture1.TextureList[TextureListNumber2]); // Nastav texturu podle daného Texture Display Listu
DrawTriangleFan(texcoord0, point5, // Texturová koordinace a pozice bodu 5
texcoord1, point4, // Texturová koordinace a pozice bodu 4
texcoord2, point6, // Texturová koordinace a pozice bodu 6
texcoord3, point7); // Texturová koordinace a pozice bodu 7
// Resetuj na původní hodnoty pozice bodů
point5 = origpoint5;
point4 = origpoint4;
point6 = origpoint6;
point7 = origpoint7;
// Levá stěna krychle
// Posuň celý čtverec blíž ke kameře, aby zmizely spáry
point7.x += aprox;
point6.x += aprox;
point1.x += aprox;
point0.x += aprox;
glBindTexture(GL_TEXTURE_2D, Texture1.TextureList[TextureListNumber3]); // Nastav texturu podle daného Texture Display Listu
DrawTriangleFan(texcoord0, point7, // Texturová koordinace a pozice bodu 6
texcoord1, point6, // Texturová koordinace a pozice bodu 7
texcoord2, point1, // Texturová koordinace a pozice bodu 0
texcoord3, point0); // Texturová koordinace a pozice bodu 1
// Resetuj na původní hodnoty pozice bodů
point7 = origpoint7;
point6 = origpoint6;
point1 = origpoint1;
point0 = origpoint0;
// Horní stěna krychle
// Posuň celý čtverec blíž ke kameře, aby zmizely spáry
point7.y -= aprox;
point0.y -= aprox;
point3.y -= aprox;
point5.y -= aprox;
glBindTexture(GL_TEXTURE_2D, Texture1.TextureList[TextureListNumber4]); // Nastav texturu podle daného Texture Display Listu
DrawTriangleFan(texcoord0, point7, // Texturová koordinace a pozice bodu 7
texcoord1, point0, // Texturová koordinace a pozice bodu 0
texcoord2, point3, // Texturová koordinace a pozice bodu 3
texcoord3, point5); // Texturová koordinace a pozice bodu 5
// Resetuj na původní hodnoty pozice bodů
point7 = origpoint7;
point0 = origpoint0;
point3 = origpoint3;
point5 = origpoint5;
// Dolní stěna krychle
// Posuň celý čtverec blíž ke kameře, aby zmizely spáry
point1.y += aprox;
point6.y += aprox;
point4.y += aprox;
point2.y += aprox;
glBindTexture(GL_TEXTURE_2D, Texture1.TextureList[TextureListNumber5]); // Nastav texturu podle daného Texture Display Listu
DrawTriangleFan(texcoord0, point1, // Texturová koordinace a pozice bodu 1
texcoord1, point6, // Texturová koordinace a pozice bodu 2
texcoord2, point4, // Texturová koordinace a pozice bodu 4
texcoord3, point2); // Texturová koordinace a pozice bodu 6
// Resetuj na původní hodnoty pozice bodů
point1 = origpoint1;
point6 = origpoint6;
point4 = origpoint4;
point2 = origpoint2;
glEndList(); // Konec Display Listu 1
}
|
Funkce pro načítání a iniciaci skyboxu provádí funkce LoadSkyBox()
|
|
int KObject::LoadSkyBox( char *name, // Cesta k souboru *.txt obsahující pozice bodů krychle
int TextureListNumber0, // Číslo Listu textury 0
int TextureListNumber1, // Číslo Listu textury 1
int TextureListNumber2, // Číslo Listu textury 2
int TextureListNumber3, // Číslo Listu textury 3
int TextureListNumber4, // Číslo Listu textury 4
int TextureListNumber5, // Číslo Listu textury 5
int ObjectListNumber) // Číslo Listu objektu
{
int Status=FALSE; // Kontrolu stavu načítaní nastav na FALSE
if (LoadObject(name)) // Pokud pude načíst objekt se souboru (name) tak
{
Status=TRUE; // Kontrolu stavu načítání nastav na TRUE
InitSkyBox( point[0], // Texturová koordinace a pozice bodu 0
point[1], // Texturová koordinace a pozice bodu 1
point[2], // Texturová koordinace a pozice bodu 2
point[3], // Texturová koordinace a pozice bodu 3
point[4], // Texturová koordinace a pozice bodu 4
point[5], // Texturová koordinace a pozice bodu 5
point[6], // Texturová koordinace a pozice bodu 6
point[7], // Texturová koordinace a pozice bodu 7
TextureListNumber0, // Číslo Listu textury 0
TextureListNumber1, // Číslo Listu textury 1
TextureListNumber2, // Číslo Listu textury 2
TextureListNumber3, // Číslo Listu textury 3
TextureListNumber4, // Číslo Listu textury 4
TextureListNumber5, // Číslo Listu textury 5
ObjectListNumber); // Číslo Listu objektu
}
return Status; // Vrať funkci stav načítání
}
|
Funkce DrawSkyBox() vykresluje vytvořený Display List objektu
a nastaví skybox, aby se pohyboval s kamerou.
|
|
void KObject::DrawSkyBox(int ObjectListNumber) // Vykresli skybox
{
glPushMatrix(); // Začátek prostorové matice
glTranslatef(Camera1.Position.x, Camera1.Position.y, Camera1.Position.z); // Pohybuj skyboxem podle kamery
glCallList(ObjectListNumber); // Vykresli List
glPopMatrix(); // Konec prostorové matice
}
|
Funkce DrawSkyBox() je volána v nekonečné smyčce funkcí DrawScene()
|
|
void DrawScene(void) // Vykresli scénu
{
Camera1.Look(); // Pohybuj a rotuj kamerou
SkyBox1.DrawSkyBox(3); // Vykresli Sky Box (3 = ObjectList3)
Cube1.DrawRotateCube(1); // Vykresli rotující krychli (1 = ObjectList1)
Cube2.DrawCube(2); // Vykresli statickou krychli (2 = ObjectList2)
DrawFps(); // Vykresli FPS
}
|
To je vše.
Děkuji DigiBen
ovi, od kterého jsem si vypůjčil skybox obrázky.
Příště zkusíme načíst objekty, nebo scénu z formátu výborného 3D editoru
MilkShape
|
|
Home