J'implémente des lumières ponctuelles dans mon moteur Voxel et j'ai vraiment du mal à obtenir un bon flux de lumière, de 100% près de la source lumineuse à 0% au rayon lumineux.
J'ai 5 arguments pour la fonction:
- Couleur claire (Vec3)
- Intensité lumineuse (distance de la lumière jusqu'à la distance où la chute est de 100%)
- Distance de la lumière au fragment
- L'angle du fragment normal à la lumière
- La position de la lumière
Quelqu'un peut-il me pousser dans la bonne direction pour créer une fonction pour le calcul de la couleur du fragment?
Image d'une de mes expériences:
Edit (code actuel demandé par Byte) Notez que ce n'est qu'un code d'expérience de mon côté. J'ai obtenu le float att sur un site Web, et ça marche, mais loin d'être parfait. :
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)
? Alternativement, vous pouvez calculeratt
avec une fonction qui renvoie 1 lorsque la distance est 0 et 0 lorsque la distance est 9. Par exemplemix(1.0, 0.0, dist / 9.0)
Réponses:
La fonction d'atténuation que vous avez,
est assez courant en infographie - ou, plus généralement,
1.0 / (1.0 + a*dist + b*dist*dist))
pour certains paramètres modifiablesa
etb
. Pour comprendre le fonctionnement de cette courbe, il est utile de jouer avec les paramètres de manière interactive . Cette courbe est agréable car elle s'approche de la loi du carré inverse physiquement correcte à grande distance, mais elle ne tire pas à l'infini à courte distance. En fait, aveca = 0
c'est un assez bon modèle de lumière sphérique.Cependant, un inconvénient est que la lumière n'atteint jamais complètement à zéro à une distance finie. Pour des raisons pratiques de CG en temps réel, nous devons généralement couper les lumières à une distance finie, comme vous le faites avec le
if (dist < 9)
clause. Cependant, le rayon de 9 est trop court - avec vos paramètres dans la fonction d'atténuation, la lumière ne se rapproche de zéro que lorsque la distance est d'environ 100.Vous pouvez calculer le rayon de la lumière à partir du
b
paramètre dans la fonction d'atténuation (puisque le terme quadratique domine à de grandes distances). Disons que vous voulez couper la lumière lorsque l'atténuation atteint une valeurminLight
, comme 0,01. Puis réglezCela donne un rayon de 100 pour
b = 0.01
etminLight = 0.01
. Alternativement, vous pouvez définir le rayon et calculerb
pour correspondre:Pour
radius = 9
etminLight = 0.01
, cela donneb = 1.23
. Vous pouvez le configurer dans les deux sens, mais la clé est de faire correspondre le rayon et la fonction d'atténuation afin de ne pas couper la lumière jusqu'à ce que la fonction d'atténuation soit déjà très faible, de sorte que vous ne verrez pas d'arête vive.Cela dit, il existe d'autres fonctions d'atténuation que vous pouvez utiliser. Un autre assez courant est:
ou le légèrement plus chic:
Jouez avec les paramètres de ceux-ci aussi. Ces courbes ont l'avantage d'aller exactement à zéro au rayon donné, tout en ressemblant un peu à la loi carrée inverse naturelle.
la source
max
overclamp
pour des raisons de performances uniquement.