2011. november 5., szombat

Tao Start 16 - Stencil-puffer és árnyékvetés síkra

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();
További részletek megtalálhatóak a forráskódban. A teljes forrás pedig letölthető innen: 


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