HTML

Az élet kódjai

Csináld maga. Senki nem csinálja meg helyetted.

Friss topikok

  • Travis.CG: Annyiban én is hibás vagyok, hogy könnyen előjönnek belőlem negatív posztok, ezt akartam ellensúly... (2025.05.22. 19:34) Ne csak a rosszat halljátok
  • sdani: Oh... néha eszembe jut, hogy az EBI után esetleg vissza kellene menni valamennyire az akadémiai vo... (2025.03.18. 16:58) Pontos, jól behatárolt célok
  • legyen úgy: Szia, Értem és köszönöm a válaszodat! T. (2025.02.24. 18:23) Expose CTF
  • sdani: Sajnos nekem is hasonló érzéseim vannak az R kiszorulásával kapcsolatban. Remélem jobban fogja tar... (2024.04.29. 10:48) R meetup
  • sdani: Nagyon jók ezek a bejegyzések! Feszültséggel teli, fordulatos, mint egy jobb krimi. :D Abba ne hag... (2024.04.29. 10:35) Wgel CTF

Dinamikus cubemap

2024.12.10. 19:48 Travis.CG

A magyarul viccesen hangzó kockatérképet (cubemap) elsősorban tükröződő felületek elkészítésére lehet használni. Olyan, mintha egy 360 fokos kamerával fényképeznénk. A tér minden irányába készítünk egy felvételt, és mindegyik oldalról elmentjük a képet egy textúrába. A neten fellelhető statikus példák helyett most egy dinamikus módszert mutatok be. Github-on is van egy csomó program, de némelyik látható hibáktól hemzseg. Ezért is döntöttem ennek bejegyzésnek a megírásáról.

A módszer hasonlít a textúrába renderelésre, ezért először egy framebuffert hozunk létre.

glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

A második lépés már egy kicsit különbözik, ugyanis létre kell hozni egy textúrát, de típusnak cubemap-et kell beállítani.

glGenTextures(1, &cubemap);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);

Most már elhagyjuk a biztonságos zónát. Hat textúrát kell beállítanunk, mindegyik dimenziónak kettőt. Mindegyik textúrának ugyan olyan típusúnak kell lennie. Habár a textúrák tetszőleges méretűek lehetnek OpenGL-ben, a kockatérképnél ez nem igaz. Itt kötelező a négyzet alak. (Habár ez így logikusnak tűnik, én egy napot kerestem a hibát a kódomban, mire rájöttem, hogy a méret inicializálással szúrtam el.)

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_INT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_INT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_INT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_INT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_INT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_INT, 0);

Ez a sok repetitív kód kicsit lehangoló lehet, ezért elárulom, hogy a függvény első paramétere egymást követő egész számok, ezért ciklusba szervezhetőek. Most csak a szemléltetés miatt vannak így leírva.

Ahogy lenni szokott, jönnek a textúra paraméterei. Fontos megjegyezni, hogy nem szeretnénk, ha a kocka éleinél ne legyen ronda csík, akkor GL_CLAMP_TO_EDGE opciót érdemes bekapcsolni.

De ez még nem elég. Kell egy renderbuffer, és a legtöbb esetben egy mélységi puffer is, hogy a renderelés során a takarások szépen jelenjenek meg. Természetesen a mérete akkora kell, hogy legyen, mint a fenti textúráknak.

glGenRenderbuffers(1, &render);
glBindRenderbuffer(GL_RENDERBUFFER, render);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size, size);

A legvégén mindig érdemes ellenőrizni a framebufferünket a glCheckFramebufferStatus-al, majd a framebuffer és a textúra állapotát nullára állítani.

if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
   printf("no framebuffer\n");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

Amikor eljön a renderelés ideje, akkor a jelenetet hatszor kell előállítani és a kamerát a megfelelő irányba állítani, hogy a kép a kocka megfelelő oldalára kerüljön. Tegyük fel, hogy a jelenetünket a geometry() nevű függvényben foglaltuk össze, aminek egy 4x4-es kamera mátrix a paramétere. Nem szabad elfelejteni, hogy ennek a függvénynek tartalmaznia kell a glClear() függvényt is.

glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, cubemap, 0);
camera.lookAt(pos, target1, up1);
geometry(camera);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, cubemap, 0);
camera.lookAt(pos, target2, up2);
geometry(camera);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, cubemap, 0);
camera.lookAt(pos, target3, up3);
geometry(camera);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, cubemap, 0);
camera.lookAt(pos, target4, up4);
geometry(camera);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, cubemap, 0);
camera.lookAt(pos, target5, up5);
geometry(camera);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, cubemap, 0);
camera.lookAt(pos, target6, up6);
geometry(camera);

Az kamera "up" paramétere redundáns, nincs szükség 6 különböző értékre. Természetesen kreatív kódolással ezt is ciklusba lehet szervezni, amit az olvasóra bízok.

Ezután jön egy újabb renderelés, ahol felhasználjuk a generált kockatérképet. Először csatoljuk a textúrát, ahogy bármelyik 2D textúrával is tennénk. A loc változó a glGetUniformLocation visszatérési értéke.

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
glUniform1i(loc, 0);

A shaderen belül a következő módon hivatkozunk a cubemap-re:

uniform samplerCube image;

Ez esetben "image" a változó neve, de természetesen bármi lehet, a lényeg, a típus. A képet ezután a shaderben felhasználhatjuk.

Mivel összesen hét renderelést hajtunk végre, célszerű a cubemap fázisoknál egyszerűsítéseket végezni, hogy csökkentsük a felhasználni kívánt erőforrásokat. Például ha tükröződő felületeket akarunk készíteni (jellemzően egy játékban például az autóra), akkor az autót, ami a legnagyobb poligonszámú, nem rajzoljuk ki, csak a környezetet. A távolságot is kisebbre vehetjük. De ha az autós példánál maradunk, akkor "lefelé" nem muszáj renderelni, mert az alváz nem sok krómot tartalmaz :-). Minden az adott felhasználástól függ.

Szólj hozzá!

Címkék: demoscene opengl

A bejegyzés trackback címe:

https://cybernetic.blog.hu/api/trackback/id/tr9818742570

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása