Nem is olyan rég elkészítettük első árnyékvető algoritmusunkat. Emlékezetül: Tao Start 15 - Síkra vetített árnyékok. A síkra vetített árnyék elég látványos, de akad vele egy fő probléma. Ha a földet szimbolizáló sík véges kiterjedésű, mint a mi esetünkben, előfordulhat, hogy a vetített árnyék egy része „kilóg a semmibe”.
Probléma: a síkra vetett árnyék egy része kilóg a semmibe (piros rész) |
Mindezen problémák orvoslására a módszert a stencil buffer használatával bővítjük ki. A stencil buffer működéséről itt olvashatunk részletesen.
A stencil buffer használata
Első lépésként töröljük a stencil buffer tartalmát (0), majd a földet szimbolizáló sík megjelenítésekor a buffer megfelelő pixeleibe egy pozitív számot írunk (1). Az objektumok második felrajzolásakor csak azokat a pixeleket módosítjuk, amelyeknél a stencil bufferben nem nulla áll.
A stencil buffer tartalma, ahol nem nulla oda rajzolunk |
Ezzel a lelógó árnyékok problémáját meg is oldottuk. A stencil buffert alkalmazó árnyékvető algoritmus:
1: //
2: // A sík felrajzolása a stencil pufferbe az árnyékvetéshez
3: //
4:
5: // Kitöröljük a stencil puffer tartalmát
6: Gl.glClearStencil(0);
7: Gl.glClear(Gl.GL_STENCIL_BUFFER_BIT);
8:
9: // A stencil-teszt bekapcsolása
10: Gl.glEnable(Gl.GL_STENCIL_TEST);
11: {
12: // A stencil-teszt eredményétől függetlenül minden sokszöget továbbengedünk
13: // referencia értékként pedig 1-et állítunk be
14: Gl.glStencilFunc(Gl.GL_ALWAYS, 1, 0xFFFFFFFF);
15:
16: //A stencil puffer tartalmát csak azokban a pixelekben változtajuk,
17: //azaz 1-et írunk a 0 helyébe, ahol a sík egy darabkája megjelenik
18: Gl.glStencilOp(Gl.GL_KEEP, Gl.GL_KEEP, Gl.GL_REPLACE);
19:
20: // Nem modósítható a szín puffer
21: Gl.glColorMask(Gl.GL_FALSE, Gl.GL_FALSE, Gl.GL_FALSE, Gl.GL_FALSE);
22: // Nem modósítható a mélység puffer
23: Gl.glDepthMask(Gl.GL_FALSE);
24:
25: // Kirajzoljuk a földet szimbolizáló síkot
26: DrawFloor();
27:
28: // Modósítható a szín puffer
29: Gl.glColorMask(Gl.GL_TRUE, Gl.GL_TRUE, Gl.GL_TRUE, Gl.GL_TRUE);
30: // Modósítható a mélység puffer
31: Gl.glDepthMask(Gl.GL_TRUE);
32: }
33: Gl.glDisable(Gl.GL_STENCIL_TEST);
34:
35: //
36: // A sík felrajzolása a színtérbe
37: //
38:
39: DrawFloor();
40:
41: //
42: // Árnyékvetés
43: //
44:
45: Gl.glEnable(Gl.GL_STENCIL_TEST);
46: // Csak oda rajzolunk ahol a stencil bufferben 1 van
47: Gl.glStencilFunc(Gl.GL_EQUAL, 1, 0xFFFFFFFF);
48: Gl.glStencilOp(Gl.GL_KEEP, Gl.GL_KEEP, Gl.GL_ZERO);
49:
50: Gl.glDisable(Gl.GL_LIGHTING);
51: Gl.glDisable(Gl.GL_DEPTH_TEST);
52: Gl.glEnable(Gl.GL_BLEND);
53:
54: Gl.glPushMatrix();
55: {
56: Gl.glMultMatrixf(shadowMatrix);
57: Gl.glColor3f(0.2f, 0.2f, 0.2f);
58:
59: Gl.glPushMatrix();
60: {
61: Gl.glTranslatef(0.0f, 2.5f, 0.0f);
62: Gl.glRotatef(-spinTeapot[1], 1.0f, 0.0f, 0.0f);
63: Gl.glRotatef(-spinTeapot[0], 0.0f, 1.0f, 0.0f);
64:
65: Glut.glutSolidTeapot(1.0d);
66: }
67: Gl.glPopMatrix();
68: }
69: Gl.glPopMatrix();
a végeredmény pedig a lenti képen látható.
A síkra vetett árnyék árnyéklevágással, most már teljes az illúzió |
A stencil buffert alkalmazó árnyékvető módszer gyors, viszont egy kép előállításához az összes objektumot kétszer kell felrajzolni és csak sík felületeken tud működni, valamint feltételezi, hogy tudjuk melyik felületen szeretnénk az árnyékot kiszámolni. Ezért érdemes más módszereket is megismerni.
Felhasznált Irodalom
0 megjegyzés :
Megjegyzés küldése