# Shadow Mapping: Schatten perspektivisch korrekt platzieren



## cman (20. Jun 2016)

Hallo Leute,

hoffe ich bin hier mit meinem Problem im richtigen (Sub)-Forum gelandet. Es tummeln sich hier hoffentliche einige 3D-Cracks die mir helfen können.

Ich bin dabei eine 3D-Engine inkl. Rasterisierung zu schreiben und zwar alles schön in Software gemacht. Quasi the oldschool-way 

Jedenfalls habe ich eine Menge Spass und es lief auch bisher ganz gut:
- phong shading: check
- perspective correct texure mapping: check
- normal mapping: check

Als nächstes wollte ich mich an Shadow Mapping ranmachen. Lief auch ganz gut an, nur leider bin ich dann ziemlich schnell auf ein hartnäckiges Problem gestossen, bei dem ich nicht weiter komme. Zur Veranschaulichung habe ich anbei zwei Screenshots.

Die Szene: dunkelblaue Fläche mit drei dunkelblauen Würfeln. Den Schatten habe ich zu besseren Testung mal rot eingefärbt. Den Bereich ausserhalb des Lichtkegels wollte ich auch verdunkeln und habe ihn hier mal grün gemacht. Wenn man mit der Kamera aus der Szene rauszoomt, so sind die roten Schatten korrekt platziert. Fährt man die Kamera jedoch näher ran, so verrutschen sie zunehemend. Es scheint mir hier ein Problem mit der perspektivisch korrekten Umrechnung zwischen "Lichtkamera" und echter Kamera. Auch wenn man sich die Ränder der Schatten anschaut, kommt dieser Eindruck auf. Diese werden ganz verzerrt dargestellt.


Hier ist mein Code der die Schatten letztendlich produziert:


```
// Shadow mapping: anhand der world space coordinaten noch den punkt im light space bestimmen
             // TODO: Coordinaten nicht jedesmal berechnen sondern pro vertex und dann ebenfalls interpolieren!
             if(shadowMap!=null){
               float[] lightCoords = inverseDirectionalLightMatrix.transform(world_x - directionalLightOrigin.x, world_y - directionalLightOrigin.y, world_z - directionalLightOrigin.z);
               // perspektiven korrektur
               float zf = 1024f / lightCoords[2];
               lightCoords[0] = lightCoords[0] * zf;
               lightCoords[1] = lightCoords[1] * zf;
               
               // to screenspace (weil ja auf diese weise auch die werte beim eintragen in die shadow map berechnet wurden)                             
               int light_x = xoffset + (int) Math.floor(lightCoords[0] + 0.5f);
               int light_y = yoffset - (int) Math.floor(lightCoords[1] + 0.5f);
               int light_z = (int) Math.floor(lightCoords[2] + 0.5f);
               
               if(light_x<0 || light_x>=frameX || light_y<0 || light_y>=frameY){ // alles ausserhalb des lichtkegels ist im schatten
                 colorBuffer.setPixel(draw_x, draw_y, Color.green.getRGB());
                 continue; // TODO: schatten-info an den shader weiter geben und ihn machen lassen
               }
               
               int distToLight = light_z;                                                     
               int distToLightFromShadowMap = shadowMap.getPixel(light_x, light_y);
               int bias = 1; // gegen schatten akne
               
               if(distToLightFromShadowMap<distToLight-bias){ // etwas anderes war näher dran -> wir sind im schatten
                 colorBuffer.setPixel(draw_x, draw_y, shadowColorRGB);
                 continue; // TODO: schatten-info an den shader weiter geben und ihn machen lassen
               }
             }
```



Ist mir klar das das ein sehr spezielles Problem ist aber vielleicht hat ja jemand ne Idee oder ist schonmal an ähnlichem verzweifelt und weiß Rat?

Grüße!


----------



## cman (3. Jul 2016)

Boah, nach langem Rätselraten habe ich heute endlich die Lösung gefunden.

Und zwar gehören die Weltkoordinaten für den gerade auszurechnenden Pixel auch nochmal perspektivenkorrigiert, ausgehend von der Kamera, bevor man sie in den Lichtraum transformiert.


----------



## cman (5. Jul 2016)

Anbei nochmal ein Screenshot mit Schatten und Menger-Sponge Texturen. 
Das mit den Schatten sieht schon ganz nett aus. Leider sind meine zBuffer-Werte noch auf ganze Zahlen beschränkt wodurch es zu unschönen Artefakten kommt. Aber ich bin dran und es wird langsam. Muss nur immer drauf achten, dass die FPS nicht in den Keller gehen. Auf Hardware-Unterstützung beim Rendern soll hier nämlich komplett verzichtet werden


----------

