Wdrażam światła punktowe w silniku Voxel i naprawdę bardzo staram się uzyskać dobry przepływ światła, od 100% w pobliżu źródła światła do 0% w promieniu światła.
Mam 5 argumentów dla funkcji:
- Barwa światła (Vec3)
- Intensywność światła (odległość od światła do odległości, w której spadek wynosi 100%)
- Odległość od światła do fragmentu
- Kąt od fragmentu normalny do światła
- Pozycja światła
Czy ktoś może popchnąć mnie we właściwym kierunku, aby stworzyć funkcję do obliczania koloru fragmentu?
Zdjęcie jednego z moich eksperymentów:
Edycja (aktualny kod wymagany przez Byte) Zauważ, że to tylko część kodu eksperymentu z mojej strony. Mam float att ze strony internetowej i to działa, ale dalekie od ideału. :
void main()
{
// Light color
vec3 torchColor = vec3(1.0f, 1.0f, 1.0f);
float lightAdd = 0.0f;
for (int i=0; i<5; i++) {
vec3 pos = lights[i];
if (pos.x == 0.0f) continue;
float dist = distance(vertex_pos, pos);
if (dist < 9) {
float att=1.0/(1.0+0.1*dist+0.01*dist*dist);
vec3 surf2light = normalize(pos - vertex_pos);
vec3 norm = normalize(normal);
float dcont=max(0.0,dot(norm,surf2light));
lightAdd += att*(dcont+0.4);
}
}
vec3 textureColor = texture2D(texture, texture_coordinate).rgb;
vec3 torch_output = lightAdd * torchColor;
vec3 final_color = ((0.1+torch_output) * textureColor);
gl_FragColor = vec4(final_color, 1.0f);
}
if (dist < 9)
? Alternatywnie można obliczyćatt
za pomocą funkcji, która zwraca 1, gdy odległość wynosi 0, a 0, gdy odległość wynosi 9. Np.mix(1.0, 0.0, dist / 9.0)
Odpowiedzi:
Masz funkcję tłumienia,
jest dość powszechny w grafice komputerowej - lub, bardziej ogólnie, w
1.0 / (1.0 + a*dist + b*dist*dist))
przypadku niektórych modyfikowalnych parametrówa
ib
. Aby zrozumieć, jak działa ta krzywa, pomocne jest interaktywne granie z parametrami . Ta krzywa jest dobra, ponieważ zbliża się do fizycznie poprawnego odwrotnego prawa kwadratu na dużych odległościach, ale nie strzela do nieskończoności na krótkich odległościach. W rzeczywistościa = 0
jest to całkiem dobry model sferycznego światła obszarowego.Jednak jedną z jego wad jest to, że światło nigdy nie osiąga zera w żadnej skończonej odległości. Ze względów praktycznych w grze komputerowej w czasie rzeczywistym zazwyczaj musimy odcinać światła w ograniczonej odległości, tak jak robisz to z
if (dist < 9)
klauzulą. Jednak promień 9 jest zbyt krótki - przy ustawieniach funkcji tłumienia światło nie zbliża się do zera, dopóki dist nie osiągnie około 100.Promień światła można obliczyć na podstawie
b
parametru w funkcji tłumienia (ponieważ element kwadratowy dominuje na dużych odległościach). Powiedzmy, że chcesz odciąć światło, gdy tłumienie osiągnie pewną wartośćminLight
, na przykład 0,01. Następnie ustawTo daje promień 100 dla
b = 0.01
iminLight = 0.01
. Alternatywnie możesz ustawić promień i obliczyć,b
aby dopasować:Za
radius = 9
iminLight = 0.01
to dajeb = 1.23
. Możesz to ustawić w dowolny sposób, ale kluczem jest dopasowanie promienia i funkcji tłumienia, aby nie odcinać światła, dopóki funkcja tłumienia nie będzie już bardzo niska, aby nie zobaczyć ostrej krawędzi.To powiedziawszy, istnieją alternatywne funkcje tłumienia, których można użyć. Innym dość powszechnym jest:
lub nieco bardziej fantazyjny:
Graj też z parametrami dla tych. Krzywe te mają tę zaletę, że idą dokładnie do zera przy danym promieniu, a jednocześnie wyglądają jak naturalne odwrotne prawo kwadratowe.
źródło
max
ciąguclamp
tylko ze względu na wydajność.