Rendering wolumetryczny

20.12.2010 - Adam Błaszkiewicz
TrudnośćTrudnośćTrudność

Krok 4 - Budowanie mapy głębokości

Mając do dyspozycji funkcje śledzące promienie, możemy zbudować mapę głębokości. Powie ona nam, jak daleko od kamery są punkty widoczne na poszczególnych pikselach. Aby obraz miał lepszą jakość, można śledzić więcej niż 1 promień na 1 piksel (ang. supersampling), ale nie będziemy rozważać takiego rozwiązania w tym artykule. Ciekawostka - mapę głębokości możemy załadować do programu typu ZBrush i za jego pomocą wyrenderować nasz obiekt. Równie dobrze możemy utworzyć płaski prostokąt, np. w 3ds Maksie, i nałożyć na niego teksturę z naszą mapą głębokości jako displacement map. Wtedy uzyskujemy niemal nieograniczone możliwości renderowania.

Oprócz głębokości, będziemy też zapisywać punkty w przestrzeni (ich współrzędne), które widoczne są na poszczególnych pikselach. Informacje o nich przydadzą nam się później, przy obliczaniu normalnych. Jeśli dla danego piksela uda nam się znaleźć przecięcie promienia z renderowanym obiektem, zapisujemy do tablicy odpowiednie wartości. W przeciwnym wypadku, ustawiamy „prawie nieskończoną” głębokość piksela i bardzo odległy punkt w przestrzeni (leżący na drodze śledzonego promienia).

Mapa głębokości - im jaśniejszy kolor, tym bliżej kamery.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Obliczanie głębokości pikseli
for (int y = 0; y < sizeY+2; ++y)
{
    for (int x = 0; x < sizeX+2; ++x)
    {
        // Obliczanie wektora od kamery do danego piksela
        DirectionVector ray = new DirectionVector();
        ray.z =  1.0;
        ray.x =  (2.0 * x / sizeX - 1.0) * fovXTan;
        ray.y = -(2.0 * y / sizeY - 1.0) * fovYTan;
        ray *= transformation;
        ray.Normalize();
 
        pixels[x, y] = new Pixel();
        pixels[x, y].ray = ray;
 
        // Śledzenie promienia od kamery w stronę danego piksela
        Vector collision = CollisionPoint(cameraPos, ray, true);
 
        // Zapisanie wyniku - głębokości piksela
        if (Double.IsNaN(collision.x))
        {
            // Przecięcie nie zostało znalezione,
            // ustawiamy "prawie nieskończoną" głębokość
            pixels[x, y].depth = double.MaxValue;
            pixels[x, y].worldPoint = cameraPos + 1000000 * ray;
        }
        else
        {
            // Przecięcie zostało znalezione
            pixels[x, y].depth = (collision - cameraPos).Length;
            pixels[x, y].worldPoint = collision;
 
            // (...)
        }
 
        // (...)
    }
 
    // (...)
}
5
Twoja ocena: Brak Ocena: 5 (1 ocena)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com