Rendering wolumetryczny - cz. II

20.12.2010 - Adam Błaszkiewicz
TrudnośćTrudnośćTrudność
Krok 5 - Budowanie mapy normalnych

W tym kroku zbudujemy mapę normalnych, czyli obliczymy normalne powierzchni odkrytych w punktach widocznych w poszczególnych pikselach. Oczywiście, ze względu na naturę naszego świata opisanego funkcją zwracającą wartość boolowską dla podanego punktu w przestrzeni, możemy jedynie przewidywać, że powierzchnie takie naprawdę istnieją i w pewnym stopniu je aproksymować. Nie wiemy nawet, czy materia w naszym świecie jest w każdym miejscu ciągła (fakt, w prawdziwym świecie też nie jest, ale to całkiem inna bajka). Mając mapę normalnych, będziemy mogli prosto wykonać różnego rodzaju obliczenia oświetlenia.

Mapa normalnych - wektory normalnych zostały zmapowane na kolor: x - czerwony, y - zielony, z - niebieski.

Prostym sposobem aproksymowania płaszczyzny stycznej do powierzchni naszego obiektu w punkcie widocznym w danym pikselu jest prześledzenie dwóch promieni wystrzelonych z kamery, w kierunku prawie identycznym, co promień główny wystrzelony w stronę badanego piksela. Naturalnym i dającym dobry efekt sposobem jest użycie w tym celu promieni głównych sąsiednich pikseli i tak też postępujemy w przedstawionym programie. Jeśli wzięlibyśmy promienie wystrzelone gęściej (w sensie kąta), obraz sprawiałby wrażenie zbyt ostrego, ponieważ wyznaczona płaszczyzna byłaby zbyt dokładna - uwzględniałaby mikronierówności naszego obiektu, których nie widać na pojedynczym pikselu. Jeśli natomiast weźmiemy zbyt odległe (znowu w sensie kąta) promienie, kształty wyznaczone przez normalne będą rozmyte. Gdy znamy już 2 bliskie punkty na powierzchni renderowanego obiektu, budujemy wektory left i up, które definiują płaszczyznę. Na końcu pozostaje już tylko obliczenie iloczynu wektorowego (ang. cross product) wektorów left i up - wynikiem jest normalna powierzchni w rozpatrywanym punkcie.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for (int y = 1; y < sizeY + 1; ++y)
{
    for (int x = 1; x < sizeX + 1; ++x)
    {
        // Nie rozważamy pikseli, na których nie widać żadnego punktu świata
        if (pixels[x, y].depth > farClipping)
            continue;
 
        // Obliczanie normalnej
        Vector left = pixels[x - 1, y].worldPoint - pixels[x, y].worldPoint;
        Vector up = pixels[x, y - 1].worldPoint - pixels[x, y].worldPoint;
        pixels[x, y].normal = Vector.Cross(left, up);
        pixels[x, y].normal.Normalize();
        // (...)
    }
 
    // (...)
}
5
Twoja ocena: Brak Ocena: 5 (2 ocen)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com