Construisons un moteur graphique 3D éclairage dynamique

salut! Ceci est le dernier article de notre série sur les bases des systèmes graphiques logiciels 3D. Cette fois, nous allons nous intéresser à l’éclairage dynamique! Avant que vous ne deveniez trop excité ou trop inquiet de la difficulté d'une tâche telle que l'éclairage dynamique, détendez-vous. Pour le moment, nous ne couvrirons que la forme la plus élémentaire d'éclairage dynamique (car le sujet entier est énorme et que d'autres ont réussi à remplir des livres entiers sur le concept)..

Plus précisément, nous allons construire un système d’éclairage dynamique à point fixe, à une couleur et à rayon d’éclairage fixe, qui nous permettra de commencer à nous intéresser au sujet. Avant de commencer, jetons un coup d’œil à certaines de nos classes que nous utiliserons précédemment..


résumer

Notre éclairage dynamique va être traité point par point au fur et à mesure de leur préparation pour être dessiné à l'écran. Cela signifie que nous allons faire un usage intensif de deux de nos classes précédentes: le Point la classe et la Caméra classe. Voici à quoi ils ressemblent:

Classe de points Variables: num tuple [3]; // (x, y, z) Opérateurs: Point AddVectorToPoint (Vector); Point SubtractVectorFromPoint (Vector); Vecteur SubtractPointFromPoint (Point); NULL SetPointToPoint (Point); Fonctions: drawPoint; // dessine un point sur sa position Camera Class Vars: int minX, maxX; int minY, maxY; int minZ, maxZ; tableau objetsInWorld; // un tableau de tous les objets existants Fonctions: null drawScene (); // dessine tous les objets nécessaires à l'écran

En utilisant cette information, mettons en place notre classe d'éclairage de base.


Notre classe d'éclairage

Un exemple d'éclairage dynamique. Source: http://redeyeware.zxq.net

Notre classe d’éclairage va avoir besoin de quelques éléments pour la rendre fonctionnelle, à savoir une position, une couleur, un type et une intensité (ou rayon d’éclairage)..

Comme je l'ai dit plus tôt, notre éclairage sera calculé point par point avant que chaque point ne soit tracé. L'avantage de ceci est qu'il est plus simple d'organiser notre moteur et qu'il transfère une plus grande partie de la charge de notre programme vers le processeur du système. Si vous pré-calculiez votre éclairage, la charge serait transférée sur le disque dur de votre système et, selon la conception de votre moteur, pourrait s'avérer plus simple ou plus complexe..

Avec tout cela à l'esprit, notre classe pourrait ressembler à ceci:

Classe d'éclairage Variables: num position [3]; // (x, y, z) num rouge = 255; // ce qu'il faut ajouter à la valeur r d'un point à pleine intensité num green = 255; // ce qu'il faut ajouter à la valeur g d'un point à pleine intensité num blue = 255; // ce qu'il faut ajouter à la valeur b d'un point à une intensité maximale string lightType = "point"; // le type d'éclairage num radius = 50; // rayon de la lumière en pixels

Actuellement, nous allons laisser toutes ses valeurs codées en dur dans un souci de simplicité, mais si vous souhaitez développer la fonctionnalité des classes d'éclairage, vous pouvez facilement avoir chacune de ces valeurs modifiables via des fonctions, un constructeur, etc..

Cependant, tous les calculs importants pour notre éclairage dynamique vont se produire dans notre classe de caméra, alors jetons un coup d'œil à cela..


Lumières? Caméra? Moteur.

Un autre exemple d'éclairage dynamique. Source: http://blog.illuminatelabs.com/2010/04/hdr-and-baked-lighting.html

Nous allons maintenant ajouter une nouvelle variable à notre classe de caméras, que nous utiliserons pour stocker notre source de lumière. Pour l'instant, la variable ne stockera qu'une seule instance d'éclairage, mais elle pourrait facilement être agrandie pour permettre plus de points de lumière..

Juste avant qu'un point ne soit tracé, nous allons vérifier s'il se trouve dans le rayon de notre lumière. Une fois que nous savons qu'il se trouve dans la portée de la lumière, nous devons ensuite trouver la distance entre le point et la position de la lumière, puis nous devons ajuster la couleur du point en fonction de cette distance..

Avec tout cela à l'esprit, nous pouvons ajouter un code similaire à celui de notre caméra drawScene () une fonction:

if (currentPoint.x> = (light.x - light.radius)) // si le point est dans la limite gauche du voyant if (currentPoint.x <= (light.x + light.radius)) //if the point is within the light's right bound if(currentPoint.y >= (light.y - light.radius)) // si le point est dans la limite supérieure de la lumière if (currentPoint.y <= (light.y + light.radius)) //if the point is within the light's bottom bound //calculate distance between point and light (distance) //calculate percentage of light to apply (percentage = distance / radius) point.red += (light.red * percentage); //add the light's red, scaled to distance point.green += (light.green * percentage); //add the light's green, scaled to distance point.blue += (light.blue * percentage); //add the light's blue, scaled to distance    

Comme vous pouvez le constater, notre méthode de réglage de la couleur d’un point n’est actuellement pas très avancée (il y en a beaucoup qui le sont, si vous souhaitez les utiliser à la place). En fonction de la distance entre un point et le centre de la lumière, nous éclairons sa couleur d’un pourcentage. Actuellement, notre méthode d'éclairage ne prend pas du tout en compte les ombres. Ainsi, les zones éloignées de la lumière ne s'assombrissent pas et les objets ne bloquent pas la lumière des autres objets pouvant se trouver derrière eux..


Suivre la lumière

Pour notre programme cette fois-ci, nous allons avoir quelques formes pré-rendues à l'écran. Celles-ci peuvent être ce que vous voulez, mais pour notre exemple, je vais simplement utiliser quelques points simples. Désormais, lorsqu'un utilisateur clique n'importe où sur l'écran, nous allons créer une source de lumière à ce stade. La prochaine fois qu'ils cliquent, nous allons déplacer le point sur cette position, et ainsi de suite. Cela nous permettra de voir notre éclairage dynamique en action!

Voici à quoi votre programme pourrait ressembler:

main // configuration pour votre API graphique préférée ici // configuration pour la saisie au clavier (peut ne pas être nécessaire) ici var camera = new Camera (); // crée une instance de la classe camera // définit l'espace d'affichage de la caméra camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; // dessine les objets initiaux et les définit dans l'espace de la caméra while (key! = esc) if (mouseClick) if (firstClick) // crée l'objet lumineux initial à la position de la souris else // modifie la position de l'objet lumineux  camera.drawScene (); 

Maintenant, vous devriez pouvoir faire l'expérience de votre éclairage dynamique en action et, espérons-le, voir combien de profondeur il peut ajouter à un moteur de jeu. Regardez ma démo ici - utilisez le UNE et S les clés à l’échelle, et la Y, H, U, J, je et K clés pour faire pivoter.


Conclusion

Bien que notre éclairage dynamique soit simple, il peut certainement être amélioré si vous vous sentez enclin à le faire. Certaines choses qui seraient très cool, et aussi assez simple à ajouter sont:

  • rayon d'éclairage réglable
  • couleur d'éclairage réglable (au lieu d'éclairer uniformément une couleur, éclaircissez-la d'une fraction de la couleur définie)
  • empêche la lumière de traverser des objets solides
  • gérer plusieurs points de lumière
  • ajoute une ombre à tous les points en dehors du rayon de la lumière
  • expérimenter avec d'autres formes de lumière (directionnelle, cône, etc.)

Merci de consulter notre série Construisons un moteur de jeu 3D. C’est formidable d’écrire ces articles et, si vous avez des questions, n'hésitez pas à les poser dans les commentaires ci-dessous.!

Vous pouvez également obtenir une aide supplémentaire sur Envato Studio, où vous trouverez de nombreux services de conception et de modélisation 3D fantastiques à des prix abordables.. 

Services de conception et de modélisation 3D sur Envato Studio