Ich implementiere Punktlichter in meiner Voxel-Engine und habe wirklich Mühe, einen guten Lichtfluss zu erzielen, von 100% in der Nähe der Lichtquelle bis 0% im Lichtradius.
Ich habe 5 Argumente für die Funktion:
- Lichtfarbe (Vec3)
- Lichtintensität (Abstand vom Licht bis zu einem Abstand von 100%)
- Entfernung vom Licht zum Fragment
- Der Winkel vom Fragment normal zum Licht
- Die Position des Lichts
Kann jemand mich in die richtige Richtung treiben, um eine Funktion für die Berechnung der Fragmentfarbe zu erstellen?
Bild von einem meiner Experimente:
Bearbeiten (aktueller Code wird von Byte angefordert) Beachten Sie, dass dies nur ein experimenteller Code von meiner Seite ist. Ich habe das float att von einer Website bekommen, und es funktioniert, aber alles andere als perfekt. :
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)
? Alternativ können Sie berechnenatt
mit einer Funktion , die den Wert 1 zurück , wenn der Abstand 0 und 0 , wenn der Abstand 9. Egmix(1.0, 0.0, dist / 9.0)
Antworten:
Die Dämpfungsfunktion, die Sie haben,
ist in der Computergrafik ziemlich verbreitet - oder allgemeiner
1.0 / (1.0 + a*dist + b*dist*dist))
für einige einstellbare Parametera
undb
. Um zu verstehen, wie diese Kurve funktioniert, ist es hilfreich, interaktiv mit den Parametern zu spielen . Diese Kurve ist schön, weil sie sich bei großen Entfernungen dem physikalisch korrekten Gesetz des umgekehrten Quadrats annähert, aber bei kurzen Entfernungen nicht bis ins Unendliche schießt. Tatsächlich ista = 0
es ein ziemlich gutes Modell einer Kugelflächenleuchte.Ein Nachteil ist jedoch, dass das Licht in keiner endlichen Entfernung ganz gegen Null geht. Für praktische Zwecke in Echtzeit-CG müssen wir im Allgemeinen die Lichter in einem begrenzten Abstand abschalten, wie Sie es mit der
if (dist < 9)
Klausel tun . Der Radius von 9 ist jedoch zu kurz - mit Ihren Einstellungen in der Dämpfungsfunktion kommt das Licht erst bei einem Abstand von etwa 100 gegen Null.Sie können den Radius des Lichts aus dem
b
Parameter in der Dämpfungsfunktion berechnen (da der quadratische Term bei großen Entfernungen dominiert). Angenommen, Sie möchten das Licht ausschalten, wenn die Dämpfung einen WertminLight
wie 0,01 erreicht. Dann setzenDas ergibt einen Radius von 100 für
b = 0.01
undminLight = 0.01
. Alternativ können Sie den Radius festlegen und entsprechend berechnenb
:Für
radius = 9
undminLight = 0.01
, das gibtb = 1.23
. Sie können es so oder so einstellen, aber der Schlüssel ist, dass der Radius und die Dämpfungsfunktion übereinstimmen, damit Sie das Licht nicht ausschalten, bis die Dämpfungsfunktion bereits sehr niedrig ist, sodass Sie keine scharfe Kante sehen.Trotzdem gibt es alternative Dämpfungsfunktionen, die Sie verwenden können. Ein weiteres ziemlich verbreitetes ist:
oder der etwas schickere:
Spielen Sie auch bei diesen mit den Parametern . Diese Kurven haben den Vorteil, dass sie beim gegebenen Radius genau auf Null gehen und dennoch dem natürlichen Gesetz des umgekehrten Quadrats ähneln.
quelle
max
überclamp
nur aus Leistungsgründen.