?
Ich bin ein wenig weiter. Ein Bug existiert noch, bei dem ihr mir vielleicht helfen könnt:
public void display()
{
GL11.glColorMask(false, false, false, false);
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glDisable(GL11.GL_DEPTH_TEST);
Vector<Shape> shadows = new Vector<Shape>();
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
for(int i=2;i<lights.size()+2;++i)
{
for(int d = 0; d<drawables.size();++d)
{
shadows.add(lights.get(i-2).calculateShadow(drawables.get(d)));
}
GL11.glStencilFunc(GL11.GL_ALWAYS, i, i);
for(int s = 0; s<shadows.size();++s)
{
shadows.get(s).render();
}
shadows.clear();
}
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_ZERO);
for(int i=2;i<lights.size()+2;++i)
{
GL11.glStencilFunc(GL11.GL_NOTEQUAL, i, 255);
lights.get(i-2).render();
}
GL11.glStencilFunc(GL11.GL_ALWAYS, 125, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
for(int i=0;i<drawables.size();++i)
{
drawables.get(i).render();
}
GL11.glStencilFunc(GL11.GL_EQUAL, 125, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_ZERO);
for(int i=0;i<lights.size();++i)
{
lights.get(i).render();
}
GL11.glColorMask(true,true,true,true);
GL11.glStencilFunc(GL11.GL_EQUAL, 0, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
GL11.glDisable(GL11.GL_DEPTH_TEST);
for(int i=0;i<backgrounds.size();++i)
{
backgrounds.get(i).render();
}
for(int i=0;i<drawables.size();++i)
{
drawables.get(i).render();
}
GL11.glDisable(GL11.GL_STENCIL_TEST);
drawables.clear();
}
Die Effekte sind jetzt wie gewollt: Schatten malen nicht in fremde Lichter rein, Lichter erleuchten den korrekten Bereich etc.
Was ich mache:
-Stencilbuffer wird bei jedem glClear auf "1" gecleart (glClearStencil(1)) (gecleared wird übrigens außerhalb der Funktion).
-der Wert 0 symbolisiert "hier hin wird gezeichnet". Demnach wird auch das "farbige" Zeichnen so konditioniert:
GL11.glColorMask(true,true,true,true);
GL11.glStencilFunc(GL11.GL_EQUAL, 0, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
GL11.glDisable(GL11.GL_DEPTH_TEST);
for(int i=0;i<backgrounds.size();++i)
{
backgrounds.get(i).render();
}
for(int i=0;i<drawables.size();++i)
{
drawables.get(i).render();
}
- ich berechne und zeichne die Schatten mit einer "ID" in den Stencilbuffer.
- Lichter einzeln durchlaufen: Wenn an Stell im Stencilbuffer, an das das i-te Licht hinmalen will, bereits der Wert "i" steht (die ID), dann dort nix ändern, wenn irgendein anderer Wert dort steht, den Wert auf 0 setzen.
Das ganze ist dieser Code-Teil:
GL11.glColorMask(false, false, false, false);
GL11.glEnable(GL11.GL_STENCIL_TEST);
GL11.glDisable(GL11.GL_DEPTH_TEST);
Vector<Shape> shadows = new Vector<Shape>();
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
for(int i=2;i<lights.size()+2;++i)
{
for(int d = 0; d<drawables.size();++d)
{
shadows.add(lights.get(i-2).calculateShadow(drawables.get(d)));
}
GL11.glStencilFunc(GL11.GL_ALWAYS, i, i);
for(int s = 0; s<shadows.size();++s)
{
shadows.get(s).render();
}
shadows.clear();
}
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_ZERO);
for(int i=2;i<lights.size()+2;++i)
{
GL11.glStencilFunc(GL11.GL_NOTEQUAL, i, 255);
}
Da die berechneten Schattenflächen gezwungenermaßen aber manchmal mit den Drawables überlappen, von denen sie geworfen werden, muss jetzt noch ein letzter Schritt her:
- Zeichne alle "Drawables" (in meinem Testprogramm einfach Sprites) mit einem willkürlichen Wert in den Stencilbuffer (Bei mir 125. Stencil Buffer ist übrigens 8 bit lang).
- Gehe nochmals durch alle Lichter und zeichne an die Stellen, an denen im Stencil Buffer eine 125 steht, eine 0 rein.
Das ist folgender Code-Teil:
GL11.glStencilFunc(GL11.GL_ALWAYS, 125, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
for(int i=0;i<drawables.size();++i)
{
drawables.get(i).render();
}
GL11.glStencilFunc(GL11.GL_EQUAL, 125, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_ZERO);
for(int i=0;i<lights.size();++i)
{
lights.get(i).render();
}
Das funktioniert aber aus irgendnem Grund nicht. Und ich hab keine Ahnung wieso. Wenn ich den Code wie oben so ausführe, sieht das so aus:
http://i.imgur.com/OVAtt.jpg
Dieses Rote Ding, was da rausguggt, ist einfach eins der beiden Sprites, das gezeichnet wird. Die Schwarzen Flächen darüber sind die (korrekt) berechneten Schattenformen, die eben wie schon gesagt teilweise mit den Formen überlappen, weswegen ich sie in dem letzten Schritt rausfiltern muss.
Doch das rausfiltern sollte so eigentlich definitiv funktioniert, oder nicht? Zunächst alle Drawables in Buffer malen mit glStencilFunc(GL_ALWAYS,125,125). (und GL_REPLACE in glStencilOp). Nun sollte an den Stellen der Sprites im Stencilbuffer eine 125 stehen.
Das tut es übrigens auch! Wenn ich den Code bei dem ich zum zweiten mal alle Lichter durchlaufe rauskommentiere, werden die Regionen wo die Sprites sind nicht gezeichnet (weil da eben 125 != 0 steht und somit Stencil Test beim zeichnen fehlschlägt.)
Demnach sollte der Fehler also irgendwie beim letzten Schritt (dem zweiten Durchlaufen aller Lichter) liegen:
GL11.glStencilFunc(GL11.GL_EQUAL, 125, 255);
GL11.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_ZERO);
for(int i=0;i<lights.size();++i)
{
lights.get(i).render();
}
Doch was soll da denn falsch sein? GL_EQUAL lässt den Test erfolgreich sein, wenn ref&mask == stencilvalue&mask , sprich hier: wenn 125&255 == wertimstencil & 255 , also konkret wenn wertimstencil == 125, was ja bei der Stelle der Sprites so sein sollte.
Und wenn der Test nicht scheitert, wird an die Stelle im Buffer 0 geschrieben (mit GL_ZERO).
Was ist hier falsch?