<TeXmacs|1.99.11>

<style|<tuple|base|french>>

<\body>
  <\hide-preamble>
    \;

    <assign|by-text|<macro|>>

    <assign|verbatim|<macro|body|<with|color|darker
    grey|<with|font-family|tt|language|verbatim|<arg|body>>>>>
  </hide-preamble>

  <doc-data|<doc-title|Projet <verbatim|C++> : Moteur d'optique géométrique
  <name|2d>>|<doc-author|<author-data|<author-name|Félix Faisant>>>>

  <em|Le code nécessite la bibliothèque SFML pour l'affichage (paquet
  <verbatim|libsfml-dev> sur Mint ou Debian).>

  <subsection|Objectifs et méthodes>

  Le but de ce projet est de simuler les lois de l'optique géométrique sur
  une scène <name|2d>, et ainsi de construire un moteur d'illumination de
  scènes <name|2d>. Le principe est simple :

  <\itemize-arrow>
    <item>Les <strong|sources> envoient des rayons lumineux, par exemple dans
    toutes les directions pour une source isotrope, ou dans une seule
    direction et de façon étendue pour une source de type "soleil".

    <item>Les rayons sont interceptés par les <strong|objets> de la scène.
    Suivant l'objet, le rayon peut être réfléchi, réfracté, diffusé, filtré,
    absorbé<text-dots> L'objet ré-émet alors zéro, un ou plusieurs rayons.

    <item>Des <strong|écrans> accumulent l'intensité des rayons qu'ils
    interceptent sur une matrice de pixels.

    <item>Le processus d'interception - ré-émission est répété jusqu'à ce que
    le rayon soit totalement absorbé.
  </itemize-arrow>

  On peut alors se servir des pixels des écrans comme image, comme un
  <name|ccd> de caméra (<name|1d> !) si on a placé une lentille devant, ou
  comme la luminosité qu'aurait un mur à cet endroit (par exemple pour
  illuminer une scène d'un jeu de plateforme). Plutôt qu'un long discours,
  mieux vaut regarder les exemples page 2.

  On peut voir ça comme une méthode de Monte-Carlo. C'est très inefficace
  pour construire des images (on appelle ça alors le <em|pathtracing>) car
  une toute petite fraction des rayons émis arrivent au "<name|ccd>" (comme
  pour une caméra réelle)<\footnote>
    Pour faire du rendu d'image réaliste performant, les rayons sont lancés
    depuis l'écran et sont propagés dans le sens inverse (on appelle ça alors
    le <em|raytracing>). C'est beaucoup moins simple à implémenter pour les
    processus irréversibles (diffusion<text-dots>).
  </footnote>. C'est par contre adapté pour faire une illumination
  physiquement réaliste (on appelle ça alors l'illumination par
  <em|radiosité>).

  <\compact>
    Les différents objets implémentés ici sont :

    <\itemize-dot>
      <item>Des lignes ou des arcs de cercles, dont les calculs
      d'interception sont détaillés dans <verbatim|lois.pdf>.

      <item>Des dioptres (lois de Snell-Descartes et coefficients de Fresnel,
      détaillées dans <verbatim|lois.pdf>), des miroirs, des objets
      diffusants (<hlink|diffusion lambertienne|https://fr.wikipedia.org/wiki/Loi_de_Lambert>
      ou plus sophistiqué), des écrans, des filtres<text-dots>

      <item>Ou bien des objets non localisés, comme du brouillard.
    </itemize-dot>
  </compact>

  Pour implémenter les couleurs, on choisit de rester proche des lois
  physiques en attribuant un <strong|spectre> discret à chaque rayon (ici 4
  longueurs d'onde). De plus, il faut prendre en compte la polarisation
  <math|><name|te> / <name|tm>, qui se comportent différemment pour la
  réflexion/réfraction<\footnote>
    Le plan d'incidence des rayons est toujours le même : le plan où vivent
    les objets <name|2d>. Ainsi, les polarisations <math|><name|te> et
    <name|tm> (relatives au plan d'incidence) sont toujours les mêmes, on
    peut donc séparer la lumière de façon globale en composantes <name|te> et
    <name|tm>, et les traiter séparément.
  </footnote>. Ainsi, chaque rayon possède <em|8 composantes>. De plus, on
  oublie tout phénomène de nature ondulatoire. On travaille alors directement
  en <em|intensité lumineuse>, plutôt qu'en amplitude, et on les additionne
  simplement. Cela simplifie largement l'implémentation.

  <subsection|Structure du code>

  Les fichiers <verbatim|Util.h>/<verbatim|Util.cpp> implémentent des
  structures et fonctions utilitaires classiques : un vecteur <name|2d>
  <verbatim|vec_t> et un point <name|2d> <verbatim|point_t> avec les
  surcharges d'opérateurs usuelles, les rotations/translations/homothéties,
  une structure <verbatim|angle_interv_t> qui implémente un intervalle
  angulaire dans <math|\<bbb-R\>> modulo <math|2\<pi\>><text-dots> Le fichier
  <verbatim|sfml_c01.hpp> contient des fonctions utilitaires pour l'affichage
  avec SFML, notamment pour convertir les coordonnées
  <math|<around*|[|0,1|]>\<times\><around*|[|0,1|]>> en coordonnées
  fenêtre.<new-page>

  <new-page>

  La structure <verbatim|Rayon> est implémentée dans
  <verbatim|Rayon.h>/<verbatim|Rayon.cpp>. Un rayon est défini par son point
  d'origine, sa direction (angle par rapport à l'horizontale), et son spectre
  de couleur/polarisation en intensité. La structure <verbatim|Specte>
  contient les 8 composantes ainsi que des routines de manipulation des
  composantes.

  <subsubsection|Objets>

  Pour décrire le contenu de la scène, on utilise un arbre de classes (voir
  diagramme page 4), pensé pour être facilement extensible, éviter toute
  duplication de code, et utiliser le polymorphisme au maximum.

  On distingue les sources, qui ne font qu'émettre des rayons, de tous les
  autres objets de la scène. Tous les types de sources dérivent de la classe
  virtuelle <verbatim|Source>, et implémentent la méthode
  <verbatim|genere_rayons> qui renvoie un
  <verbatim|vector\<less\>Rayon\<gtr\>>. On pourra regarder la classe
  <verbatim|Source_SecteurDisqueLambertien> (<verbatim|Source.h:127>), qui
  implémente une source étendue lambertienne en forme de secteur.

  Tous les autres objets de la scène dérivent de la classe virtuelle de base
  <verbatim|Objet>, qui déclare l'interface commune utilisée lors de la
  propagation (interception puis ré-émission) des rayons, et pour
  l'affichage. Un objet est capable de <strong|tester l'interception d'un
  rayon> avec la méthode <verbatim|essai_intercept(rayon)>, et, le cas
  échéant, de <strong|ré-émettre le rayon> avec <verbatim|re_emit(rayon,
  intercept)> (où <verbatim|intercept> est une structure opaque renvoyée par
  <verbatim|essai_intercept>, conservant les informations de l'interception)
  :

  <\big-figure|<image|<tuple|<#[encoded data, 25448 characters]>|pdf>|0.65par|||>>
    Scénario typique (celui de <verbatim|Scene::interception_re_emission>)
    d'utilisation des objets.
  </big-figure>

  Cela semble compliqué, mais l'interception et la ré-émission sont séparés
  pour des raisons de performance : les calculs de ré-émission peuvent être
  lourds (e.g.<nbsp>lois de Fresnel) et ne sont pas nécessaires à chaque
  interception (par exemple si le rayon a été intercepté plus en amont par un
  autre objet). <verbatim|essai_intercept> renvoie aussi la distance entre le
  point d'émission du rayon et l'interception, qui sert à déterminer quel est
  l'objet le plus proche sur la trajectoire du rayon (voir plus loin pour
  l'utilisation de ces méthodes).

  D'un côté, on définit alors des classes (virtuelles) qui s'occupent
  uniquement de la <strong|géométrie> et de l'interception des rayons.
  <verbatim|ObjetCourbe> décrit une courbe/interface bien définie, et la
  structure opaque renvoyée par <verbatim|essai_intercept> contient le point
  d'incidence, l'angle d'incidence dans le repère de la scène, l'angle à la
  normale de la courbe, et le côté sur lequel le rayon est intercepté.
  L'interception est enfin implémentée pour deux géométries particulières :
  <verbatim|ObjetLigne> décrit un segment, et <verbatim|ObjetArc> décrit un
  arc de cercle. On pourra regarder le header <verbatim|ObjetsCourbes.h> et
  les méthodes <verbatim|ObjetArc::essai_intercept_courbe>
  (<verbatim|ObjetsCourbes.cpp:100>) et <verbatim|ObjetCourbe::essai_intercept>
  (<verbatim|ObjetsCourbes.cpp:10>).

  D'un autre côté, on implémente la <strong|physique> et la
  <strong|ré-émission> des rayons dans des classes virtuelles indépendantes
  de la géométrie : <verbatim|ObjetCourbe_Milieux> pour la
  réflexion/réfraction sur un dioptre, <verbatim|ObjetCourbe_Diffusant> pour
  une surface diffusante, <verbatim|ObjetCourbe_Miroir> pour les
  miroirs<text-dots> Ces classes implémentent, elles, la méthode
  <verbatim|re_emit()>. On pourra regarder
  <verbatim|ObjetCourbe_Milieux::re_emit> (<verbatim|ObjetMilieux.cpp:20>),
  qui implémente les fameuses lois

  <\equation*>
    \<theta\><rsub|<text|r>>=\<theta\><rsub|<text|i>>,<space|1em>n<rsub|2>*sin<around*|(|\<theta\><rsub|<text|t>>|)>=n<rsub|1>*sin<around*|(|\<theta\><rsub|<text|i>>|)>,<space|1em><with|math-display|false|R<rsub|<text|TE>><separating-space|0.2em>=<separating-space|0.2em><around*|\||<frac|n<rsub|1>*cos
    \<theta\><rsub|<text|i>>-n<rsub|2>*cos
    \<theta\><rsub|<text|t>>|n<rsub|1>*cos
    \<theta\><rsub|<text|i>>+n<rsub|2>*cos
    \<theta\><rsub|<text|t>>>|\|><rsup|2>,<space|1em>R<rsub|<text|TM>><separating-space|0.2em>=<separating-space|0.2em><around*|\||<frac|n<rsub|2>*cos
    \<theta\><rsub|<text|i>>-n<rsub|1>*cos
    \<theta\><rsub|<text|t>>|n<rsub|2>*cos
    \<theta\><rsub|<text|i>>+n<rsub|1>*cos
    \<theta\><rsub|<text|t>>>|\|><rsup|2>>
  </equation*>

  Enfin, comme illustré sur le diagramme, on combine ces classes pour en
  faire des objets complètements définis : par exemple
  <verbatim|ObjetLigne_Milieux>, qui est un dioptre plan, hérite des classes
  <verbatim|ObjetCourbe_Milieux> et <verbatim|ObjetLigne>.<new-dpage>

  Les écrans (définis dans <verbatim|Ecran.h>) accumulent les rayons
  incidents et calculent une intensité moyenne pour afficher ou enregistrer
  le résultat. On utilise surtout <verbatim|EcranLigne_Multi>, qui est une
  matrice (<name|1d>) de pixels et qui hérite de <verbatim|ObjetLigne>.

  <subsubsection|Scène>

  La logique de la propagation des rayons est implémentée dans la classe
  <verbatim|Scene> (<verbatim|Scene.h>/<verbatim|Scene.cpp>), qui stocke les
  sources et les objets de façon polymorphique
  (<verbatim|std::vector\<less\>std::shared_ptr\<less\>Objet\<gtr\>\<gtr\>>).
  Pour illuminer / former une image, on appelle la méthode
  <verbatim|emission_propagation()> qui lance les rayons à partir des
  sources. Pour chaque rayon, la méthode <verbatim|propagation_recur(Rayon)>
  est appelée. Cette méthode effectue les tests d'interception et la
  ré-émission de façon récursive. Schématiquement, on a

  <\indent>
    <\wide-tabular>
      <tformat|<cwith|1|1|1|1|cell-tborder|0ln>|<cwith|1|1|1|1|cell-bborder|0ln>|<cwith|1|1|1|1|cell-lborder|1ln>|<cwith|1|1|1|1|cell-rborder|0ln>|<cwith|1|1|1|1|cell-lsep|10pt>|<cwith|1|1|1|1|cell-background|#F5F5F5>|<table|<row|<\cell>
        <\compact>
          <\verbatim>
            <\small>
              void Scene::propagation_recur (rayon) {

              \ \ \ \ rayons_re_emis = interception_re_emission(rayon);

              \ \ \ \ for (ray : rayons_re_emis)\ 

              \ \ \ \ \ \ \ \ propagation_recur(ray);

              }

              std::vector\<less\>Rayon\<gtr\> Scene::interception_re_emission
              (ray) {

              \ \ \ \ <samp|Teste <verbatim|objet-\<gtr\>essai_intercept(ray)>
              sur tous les objets de la scène et sélectionne le premier>

              \ \ \ \ \ \ <samp|objet sur le chemin du rayon.>

              \ \ \ \ objet_le_plus_proche-\<gtr\>re_emit(ray,
              intercept_struct);

              }
            </small>
          </verbatim>
        </compact>
      </cell>>>>
    </wide-tabular>
  </indent>

  (cf.<nbsp>figure page 3). Les rayons sont ainsi propagés sur la scène
  jusqu'à ce qu'ils soient absorbés par un écran ou qu'ils soient d'intensité
  négligeable (<verbatim|Scene::intens_cutoff>). Une limite est fixée pour
  éviter les récursion infinies (par exemple avec une réflexion interne
  totale dans une lame).

  Enfin, la méthode <verbatim|dessiner_scene()> est appelée pour afficher
  tous les objets de la scène dans la fenêtre. Tant que rien ne bouge dans la
  scène, on répète ce processus (une <em|frame>) autant que possible pour
  avoir un résultat de moins en moins bruité sur les écrans (merci au
  théorème central limite).

  <subsubsection|Divers>

  La classe <verbatim|SceneTest> étend <verbatim|Scene> et regroupe tout le
  code indépendant du reste et qu'on trouverait typiquement dans les
  <verbatim|main()>, mais pas assez générique pour être dans la classe
  <verbatim|Scène> : création des fenêtres <name|sfml>, de quelques objets
  courants, d'une lentille et d'un écran pour former une image, <text-dots>

  Le code est fourni avec 4 scènes démonstratives utilisant
  <verbatim|SceneTest> : <verbatim|main_milieux.cpp> (qu'on pourra regarder),
  <verbatim|main_brouillard.cpp>, <verbatim|main_store.cpp>,
  <verbatim|main_diffus_test.cpp>, et qu'on peut faire tourner avec
  <verbatim|make milieux>, <verbatim|make brouillard>, <verbatim|make store>,
  et <verbatim|make diffus_test> respectivement.

  <\compact>
    Quelques remarques finales :

    <\itemize-dot>
      <item>Tous les attributs de classes qui ne sont pas associés à des
      contraintes/invariants et qui sont susceptibles d'être utiles à
      l'utilisateur de la classe sont publiques. L'encapsulation, ce n'est
      pas embêter l'utilisateur avec des getters, c'est protéger
      l'utilisateur contre des bêtises.

      <item>L'extensibilité et la clarté a été préférée à la performance
      quand le choix se posait.

      <item>Lorsque les constructeurs par copie et d'affectation ne sont pas
      déclarés, c'est qu'on laisse le compilateur générer celui par défaut,
      ou, lorsque marqué <em|deleted> dans une classe parent, aucun.
    </itemize-dot>
  </compact>

  <\wide-tabular>
    <tformat|<cwith|1|-1|1|-1|cell-valign|t>|<cwith|1|1|2|2|cell-lsep|10pt>|<cwith|1|1|1|1|cell-tsep|10pt>|<table|<row|<\cell>
      <subsection|Conclusion>

      On reproduit tout à fait de nombreux effets d'optique géométrique que
      l'on connait bien : lentilles épaisses pas tout à fait stigmatiques et
      avec des aberrations chromatiques, fibres optiques<text-dots>

      On obtient une illumination réaliste (toutefois gourmande en
      <name|cpu>) d'une scène <name|2d>. La formation d'images <name|1d> (par
      exemple, à droite, un surface bleue diffusante avec reflet de la source
      ponctuelle l'éclairant) sont correctes mais un peu ennuyeuses. Cela
      donne envie d'étendre le programme à une scène <name|3d> (ce qui ne
      serait pas difficile) pour obtenir de vraies images <name|2d>.
    </cell>|<\cell>
      <image|<tuple|<#[encoded data, 20556 characters]>|png>||120pt||>
    </cell>>>>
  </wide-tabular>
</body>

<\initial>
  <\collection>
    <associate|page-medium|paper>
  </collection>
</initial>

<\references>
  <\collection>
    <associate|auto-1|<tuple|1|1>>
    <associate|auto-2|<tuple|2|1>>
    <associate|auto-3|<tuple|2.1|3>>
    <associate|auto-4|<tuple|1|3>>
    <associate|auto-5|<tuple|2.2|5>>
    <associate|auto-6|<tuple|2.3|5>>
    <associate|auto-7|<tuple|3|5>>
    <associate|footnote-1|<tuple|1|1>>
    <associate|footnote-2|<tuple|2|1>>
    <associate|footnr-1|<tuple|1|1>>
    <associate|footnr-2|<tuple|2|1>>
  </collection>
</references>

<\auxiliary>
  <\collection>
    <\associate|figure>
      <tuple|normal|<\surround|<hidden-binding|<tuple>|1>|>
        Scénario typique (celui de <with|font-family|<quote|tt>|language|<quote|verbatim>|Scene::interception_re_emission>)
        d'utilisation des objets.
      </surround>|<pageref|auto-4>>
    </associate>
    <\associate|toc>
      <with|par-left|<quote|1tab>|1.<space|2spc>Objectifs et méthodes
      <datoms|<macro|x|<repeat|<arg|x>|<with|font-series|medium|<with|font-size|1|<space|0.2fn>.<space|0.2fn>>>>>|<htab|5mm>>
      <no-break><pageref|auto-1>>

      <with|par-left|<quote|1tab>|2.<space|2spc>Structure du code
      <datoms|<macro|x|<repeat|<arg|x>|<with|font-series|medium|<with|font-size|1|<space|0.2fn>.<space|0.2fn>>>>>|<htab|5mm>>
      <no-break><pageref|auto-2>>

      <with|par-left|<quote|2tab>|2.1.<space|2spc>Objets
      <datoms|<macro|x|<repeat|<arg|x>|<with|font-series|medium|<with|font-size|1|<space|0.2fn>.<space|0.2fn>>>>>|<htab|5mm>>
      <no-break><pageref|auto-3>>

      <with|par-left|<quote|2tab>|2.2.<space|2spc>Scène
      <datoms|<macro|x|<repeat|<arg|x>|<with|font-series|medium|<with|font-size|1|<space|0.2fn>.<space|0.2fn>>>>>|<htab|5mm>>
      <no-break><pageref|auto-5>>

      <with|par-left|<quote|2tab>|2.3.<space|2spc>Divers
      <datoms|<macro|x|<repeat|<arg|x>|<with|font-series|medium|<with|font-size|1|<space|0.2fn>.<space|0.2fn>>>>>|<htab|5mm>>
      <no-break><pageref|auto-6>>

      <with|par-left|<quote|1tab>|3.<space|2spc>Conclusion
      <datoms|<macro|x|<repeat|<arg|x>|<with|font-series|medium|<with|font-size|1|<space|0.2fn>.<space|0.2fn>>>>>|<htab|5mm>>
      <no-break><pageref|auto-7>>
    </associate>
  </collection>
</auxiliary>