2016-12-18 11 views
1

J'essaie d'implémenter un moteur de lumière 2D simple sur mon jeu basé sur libGDX. L'idée est de créer ce moteur léger sans shaders. Je ne prévois pas d'ombre pour le moment. J'ai réussi à rendre une carte de lumière avec des triangles et des gradients, mais le problème est que lorsque plusieurs sources de lumière chevauche je suis arrivé un peu artefact comme dans cette image:artefact de carte diffuse de lumière 2D

enter image description here

la source de lumière jaune est producting sombre frontière lors du chevauchement des autres sources de lumière.

J'utilise la fonction de mélange ci-dessous pour rendre les lumières:

Gdx.gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE); 

est-il un moyen de se débarrasser de cette bordure noire?

Le dégradé passe de l'opacité totale du jaune au noir. Comme GL_ONE est supposé être additif, les couleurs devraient seulement être plus claires à droite?

Mise à jour 1:

utilisant shaders comme expliqué par Nico Schertler est certainement mieux, mais il y a encore quelques paramètres que je ne suis pas sûr.

enter image description here

ici est le fragment shader je suis venu avec

void main() { 
    float intensity = 0.02; 
    vec2 pos = vPosition; 
    float dist = distance(pos, u_origin)/u_radius; 
    vec4 color = vec4(intensity * (vColor.rgb/((dist * dist) + 0.01)), 1); 
    gl_FragColor = color; 
} 

le problème est moi qui ne suis pas sûr au sujet des constantes intensity = 0.02 et 0.01 j'ai ajoutés à la fonction pour le faire paraître belle . De plus, la variable radius est maintenant le maximum entre la hauteur et la largeur de l'écran.

Mise à jour 2:

J'ai finalement opté pour l'équation suivante:

void main() { 
    float dist = distance(vPosition, u_origin)/u_radius; 
    vec4 color = vec4((vColor.rgb)/(pow(dist, 2) + 0.01), vColor.a); 

    gl_FragColor = color; 
} 

ensuite combiné avec une carte d'occlusion (pour assombrir les endroits non éclairés) basé sur la même équation. Voici le résultat final:

ambient + occlusion

+2

Cette bande sombre est une illusion. Vous êtes invités à vérifier les valeurs avec n'importe quel éditeur graphique et voir qu'ils ne sont pas plus sombres :) actuellement, il semble que vous n'êtes pas rendu avec sRGB mais, vous devriez. D'autres choses, comme l'atténuation quadratique, vont probablement masquer cela. – ybungalobill

Répondre

2

Cela dépend beaucoup de la façon dont vous splat les lumières.

E.g. si vous utilisez une fonction quadratique tronquée comme la luminosité de la lumière (par rapport à la distance du centre), à ​​savoir quelque chose comme ça:

enter image description here

Si vous ajoutez deux feux, vous obtiendrez ce profil:

enter image description here

enter image description here

Dans ce profil, vous voyez une discontinuité claire. La raison de cette discontinuité est la troncature de la fonction d'origine.Donc, vous avez probablement une forme de fonction de lumière tronquée dans votre image (que ce soit quadratique, linéaire ou autre), ce qui provoque la zone lumineuse à l'intersection des deux lumières.

Alors, comment résoudre ce problème? Physiquement la distribution de la lumière correcte tombe avec la distance quadratique (en 2D, vous pouvez aussi faire valoir un falloff linéaire), x est la distance de la source lumineuse:

light = factor/x^2 

Il y a deux problèmes avec cette fonction. Premièrement, il n'est pas compacté. Cela signifie que vous devrez dessiner un splat infiniment grand (ou au moins aussi grand que l'écran). Cela pourrait ne pas être un gros problème. Vous pouvez également couper la lumière dès qu'elle devient très petite. Le deuxième problème est plus grave. Si x va à 0 (c'est-à-dire que vous êtes directement sur la position de la lumière), vous ne pouvez pas calculer cette valeur (elle tend vers l'infini car toute l'énergie lumineuse est concentrée sur un point sans zone). Cela dépend donc vraiment de ce que vous voulez faire avec la carte de lumière. Bien sûr, vous pouvez régulariser de manière similaire à

light = factor/((x)^2 + epsilon) 

, où epsilon est un très petit nombre. Si votre scène est quelque chose qui est vu d'en haut, cet epsilon pourrait être la hauteur de la lumière sur le sol (au carré). Ensuite, vous obtiendrez un profil comme le suivant:

enter image description here

Voila, sans discontinuité. Mais vous aurez probablement besoin d'un fragment shader pour y parvenir.

Si vous ne se soucient pas de correction physique, un floc gaussienne pourrait également donner des résultats de belle apparence:

light = factor * exp(-x^2/variance) 
+0

Je suppose que je suis obligé d'utiliser des shaders pour y parvenir, je vais essayer avec les maillages et les shaders pour voir si ça a l'air mieux –

+0

J'ai essayé d'utiliser les fonctions (voir ma mise à jour) que vous m'avez donné mais pouvez-vous expliquer 'factor',' variance' et 'espilon' sont appliqués aux paramètres que j'ai' radius' et 'distance'. Thx –

+0

'factor' est juste une échelle, généralement en corrélation avec l'intensité de la lumière. 'variance' est la variance de Gaussian, qui spécifie à quel point la lumière est focalisée. Vous devriez essayer quelques paramètres. Quelque chose dans la gamme «rayon^2/4» à «rayon^2/9» devrait donner de bons résultats. 'epsilon' est n'importe quel nombre. Comme je l'ai mentionné, vous pouvez le définir à la hauteur virtuelle de la lumière sur le sol. Il influence également la chute brutale de la luminosité. Je pense, j'ai utilisé 'epsilon = 1' dans l'exemple. –