Szukaj…


Model oświetlenia Phong

UWAGA: Ten przykład to WIP, zostanie zaktualizowany o diagramy, obrazy, więcej przykładów itp.

Co to jest Phong?

Phong jest bardzo prostym, ale prawdziwie wyglądającym modelem świetlnym dla powierzchni składających się z trzech części: oświetlenia otoczenia, rozproszonego i lustrzanego.

Otaczające światło:

Oświetlenie otoczenia jest najprostszą z trzech części do zrozumienia i obliczenia. Oświetlenie otoczenia to światło, które zalewa scenę i równomiernie oświetla obiekt we wszystkich kierunkach.

Dwie zmienne w oświetleniu otoczenia to siła otoczenia i kolor otoczenia. W module cieniującym fragmenty następujące opcje będą działać w przypadku ambient:

in vec3 objColor;

out vec3 finalColor;

uniform vec3 lightColor;

void main() {
   float ambientStrength = 0.3f;
   vec3 ambient = lightColor * ambientStrength;
   finalColor = ambient * objColor;
}

Oświetlenie rozproszone:

Oświetlenie rozproszone jest nieco bardziej złożone niż otoczenie. Oświetlenie rozproszone jest światłem kierunkowym, co oznacza, że twarze zwrócone w stronę źródła światła będą lepiej oświetlone, a twarze skierowane w stronę przeciwną będą ciemniejsze ze względu na sposób, w jaki światło je uderza.

Uwaga: rozproszone oświetlenie będzie wymagało użycia normalnych dla każdej twarzy, której nie pokażę tutaj, jak obliczyć. Jeśli chcesz dowiedzieć się, jak to zrobić, sprawdź stronę matematyczną 3D.

Do modelowania odbicia światła w grafice komputerowej wykorzystuje się dwukierunkową funkcję dystrybucji odbicia (BRDF). BRDF to funkcja, która podaje zależność między światłem odbijanym wzdłuż kierunku wychodzącego a światłem padającym z kierunku przychodzącego.

Idealna powierzchnia rozproszona ma BRDF, który ma tę samą wartość dla wszystkich kierunków zdarzeń i wyjazdów. To znacznie zmniejsza obliczenia i dlatego jest powszechnie stosowane do modelowania powierzchni rozproszonych, ponieważ jest to fizycznie możliwe, nawet jeśli w prawdziwym świecie nie ma czystych materiałów rozproszonych. Ten BRDF nazywa się refleksją Lambertowską, ponieważ jest zgodny z prawem cosinusowym Lamberta.

Odbicie lambertowskie jest często stosowane jako model odbicia rozproszonego. Ta technika powoduje, że wszystkie zamknięte wielokąty (takie jak trójkąt w siatce 3D) odbijają światło równomiernie we wszystkich kierunkach podczas renderowania Współczynnik dyfuzji jest obliczany na podstawie kąta między wektorem normalnym a wektorem światła.

f_Lambertian = max( 0.0, dot( N, L )

gdzie N jest normalnym wektorem powierzchni, a L jest wektorem w kierunku źródła światła.

Jak to działa

Na ogół iloczyn skalarny 2 wektorów jest równa cosinusa kąta między 2 wektorów pomnożony przez wielkość (długość) obu wektorów.

dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B ) 

Wynika z tego, że iloczyn punktowy 2 wektorów jednostkowych jest równy cosinus kąta między 2 wektorami, ponieważ długość wektora jednostkowego wynosi 1.

uA = normalize( A )
uB = normalize( B )
cos( angle_A_B ) == dot( uA, uB )

wprowadź opis zdjęcia tutaj

Jeśli spojrzymy na funkcję cos (x) między kątami -90 ° i 90 °, wówczas możemy zauważyć, że ma ona maksymalnie 1 pod kątem 0 ° i spada do 0 pod kątem 90 ° i -90 °.

wprowadź opis zdjęcia tutaj

Takie zachowanie jest dokładnie tym, czego chcemy dla modelu odbicia. Kiedy nromalny vetor powierzchni i kierunek do źródła światła są w tym samym kierunku (kąt między 0 °), to chcemy maksymalnego odbicia. Natomiast jeśli wektory są ortonormalizowane (kąt pomiędzy 90 °), to chcemy minimalnego odbicia i chcemy płynnego i ciągłego działania między dwiema granicami 0 ° i 90 °.

wprowadź opis zdjęcia tutaj

Jeśli światło jest obliczane dla wierzchołka, odbicie jest obliczane dla każdego rogu prymitywu. Pomiędzy prymitywami odbicia są interpolowane zgodnie ze współrzędnymi barycentrycznymi. Zobacz powstałe odbicia na kulistej powierzchni:

wprowadź opis zdjęcia tutaj

Ok, więc aby zacząć od naszego shadera fragmentów, potrzebujemy czterech danych wejściowych.

  • Normalne wierzchołki (powinny być w buforze i określone przez wskaźniki atrybutów wierzchołków)
  • Pozycja fragmentu (powinna być wyprowadzana z shadera wierzchołków do shadera fragów)
  • Pozycja źródła światła (jednolita)
  • Barwa światła (jednolita)
in vec3 normal;
in vec3 fragPos;
    
out vec3 finalColor;
    
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 objColor;

Wewnątrz głównego jest miejsce, w którym musimy zrobić matematykę. Cała koncepcja rozproszonego oświetlenia opiera się na kącie między normalnym a kierunkiem światła. Im większy kąt, tym mniej światła dochodzi do 90 °, gdzie nie ma światła.

Zanim zaczniemy obliczać ilość światła, potrzebujemy wektora kierunku światła. Można to odzyskać, po prostu odejmując pozycję światła od pozycji fragmentu, która zwraca wektor z pozycji światła wskazującej pozycję fragmentu.

vec3 lightDir = lightPos-fragPos;

Idź dalej i znormalizuj wektory normal i lightDir aby miały taką samą długość do pracy.

normal  = normalize(normal);
lightDir = normalize(lightDir);

Teraz, gdy mamy już nasze wektory, możemy obliczyć różnicę między nimi. W tym celu wykorzystamy funkcję iloczynu punktowego. Zasadniczo bierze to 2 wektory i zwraca cos () utworzonego kąta. Jest to idealne, ponieważ przy 90 stopniach da 0, a przy 0 stopniach da 1. W rezultacie, gdy światło skierowane jest bezpośrednio na obiekt, będzie w pełni oświetlone i odwrotnie.

float diff = dot(normal, lightDir);

Jest jeszcze jedna rzecz, którą musimy zrobić z obliczoną liczbą, musimy upewnić się, że jest ona zawsze dodatnia. Jeśli się nad tym zastanowić, liczba ujemna nie ma sensu w kontekście, ponieważ oznacza to, że światło znajduje się za twarzą. Możemy użyć instrukcji if lub możemy użyć funkcji max() która zwraca maksymalnie dwa dane wejściowe.

diff = max(diff, 0.0);

Po wykonaniu tej czynności jesteśmy teraz gotowi obliczyć ostateczny kolor wyjściowy dla fragmentu.

vec3 diffuse = diff * lightColor;
finalColor = diffuse * objColor;

To powinno wyglądać tak: wprowadź opis zdjęcia tutaj

Oświetlenie lustrzane:

Pracuj w toku, sprawdź później.

Łączny

Prace w toku, sprawdź później.

Poniższy kod i zdjęcie pokazują te trzy koncepcje oświetlenia łącznie.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow