Octobre 2017
LunMarMerJeuVenSamDim
      1
2345678
9101112131415
16171819202122
23242526272829
3031     

Calendrier Calendrier

TEAM SPEAK

Journal de développement

Voir le sujet précédent Voir le sujet suivant Aller en bas

Journal de développement

Message  Cortano le Jeu 19 Sep - 16:24

Salut à tous,

Je vous avais déjà fait part des balbutiements de ce qui était à l'origine un projet universitaire sur le "Lancer de rayons" et que j'ai récemment repris pour l'étendre à mesure que des idées me venaient. Comme en général quand je m'investis dans quelque chose j'aime bien en parler, ça ne me suffit pas d'en parler à mon entourage direct et j'ai donc décidé de faire de ce topic ma tribune, pour votre plus grand plaisir (ou pas) ! Je le fais sans prétention : je développe seul et sans moyen particulier (aucun outil, aucun logiciel, seulement l'IDE Eclipse pour simplifier la compilation et l'exécution de mon code), ce que je montrerai ne sera donc pas forcément très impressionnant et n'est pas supposé l'être, il s'agit simplement de raconter le parcours du développement. Le langage que j'utilise est Java, un langage dit "orienté objet".

Je mettrai tout à jour dans les premiers posts (un par grand chapitre) de sorte que les autres servent de commentaires, si vous en avez !

PS : si vous êtes découragés par le texte, regardez juste les images !
---------------------------------------------------------------------------------------

Sommaire :

I) Lancer de rayons
1) Principe
2) Difficultés

II) Interface, fonctionnalités

III) Extensions notables
1) Textures avancées
2) A la conquête des cylindres


Dernière édition par Cortano le Mar 24 Sep - 22:39, édité 3 fois
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Jeu 19 Sep - 17:29

I) Lancer de rayons

Ici ça sera malheureusement beaucoup de blabla car ça remonte à plusieurs mois et que je n'ai que peu gardé trace des brouillons.

1) Principe

Pour faire court, le lancer de rayons est un algorithme qui permet d'aboutir à des images de synthèse. Le principe de base est très intuitif : on se munit d'un écran (c'est-à-dire d'un ensemble de points appartenant à un même plan et stockés dans une matrice), d'un point de vue (un simple point), d'un ensemble d'objets (sphères, plans, objets à facettes) et d'un ensemble de sources (des points associés à un triplet de couleur au format RGB).

En général je place mon point de vue sur une droite perpendiculaire à l'écran passant par son centre. Cela revient à peu près à considérer que l'écran est une lentille convergente de distance focale la distance entre le centre de l'écran et le point de vue, mais ce n'est concrètement pas le cas vu qu'on ne fait aucun calcul de cette sorte. D'ailleurs, je désaxe parfois le point de vue vers le haut pour donner une vue plus "surplombante".

Composante ambiante

Bref, on part du principe que l'observateur ne voit que ce qu'il y a sur l'écran, il faut donc qu'il existe un rayon qui soit passé à la fois par un point de l'écran et par le point de vue. On va donc "lancer" un rayon partant du point de vue et successivement par chacun des points de l'écran. Ensuite, on parcours notre liste d'objets pour chercher un objet intersectant ce rayon. S'il n'y en a pas, le point de l'écran associé à ce rayon reçoit la couleur noire (choix arbitraire), s'il existe au moins un objet intersecté on choisit celui dont l'intersection est la plus proche de l'écran. On "ajoute" alors au point de l'écran associé au rayon la couleur intrinsèque de l'objet en lumière blanche, caractérisée par son Ka (coefficient d'absorption). C'est la composante ambiante.

Composantes spéculaire et diffuse

On reprend le point d'intersection qu'on avait trouvé (et qu'on nommera I), et on lance un rayon partant de ce point vers chacune des sources présentes dans la liste. Si le rayon partant de I et allant vers la source S est intersecté par un des objets, alors I n'est pas éclairé par S. Sinon, on calcule par des savantes formules les composantes spéculaire (va déterminer l'aspect brillant de l'objet et notamment la taille des taches lumineuses à sa surface aux alentours des points directement éclairés par la source) et diffuse (va déterminer la réponse de l'objet à l'éclairement sur toute la surface éclairée). C'est sûrement pas très rigoureux physiquement ce que je dis, mais c'est pas tellement le problème, j'ai pas inventé les formules et je sais qu'elles ont un fondement physique.

Composantes réfractée et réfléchie

Cependant, un rayon lumineux ne se contente pas de s'arrêter tout net dès qu'il rencontre un objet. Sauf cas particulier, un rayon frappant un objet va à la fois poursuivre sa route à l'intérieur de l'objet (rayon réfracté) et à l'extérieur, après avoir rebondi dessus (rayon réfléchi). Les seules limites que je connais pour ça : quelques métaux ou alliages qui sont, il me semble, opaques au rayonnement électromagnétique (ça ne traverse que quelques micromètres avant que l'amplitude ne devienne complètement négligeable) et qui donc sont des réflecteurs purs. Autre limite, plus courante, c'est quand on fait varier l'angle sous lequel on regarde l'objet, il arrivera un moment où le rayon réfracté ne pourra plus exister et où on parlera de réflexion totale.

En principe, lorsque le rayon se scinde en deux, chacun des deux rayons possède une énergie inférieure au rayon d'origine (la somme des deux plus l'énergie absorbée par l'objet est égale à l'énergie du rayon incident) mais dans le lancer de rayons ça ne sera pas traité.

Pour rendre compte de ces deux composantes, on va simplement calculer le rayon réfléchi et le rayon réfracté (quand il existe) à partir de la connaissance du point I et du rayon incident, et relancer tout l'algorithme sur ces deux rayons !

Cela en fait donc un algorithme récursif, à savoir un algorithme qui fait appel à lui-même. Mais du coup, il faut bien que l'exécution se termine un jour car si à chaque tour d'algorithme je dois faire deux tours de plus, au tour suivant j'en aurai 4 de plus etc. On va donc faire une entorse à la réalité où ces réflexions/réfractions se produisent à l'infini et fixer arbitrairement une profondeur de calcul p. Un rayon d'ordre k est un rayon qui a été réfléchi/réfracté (de façon indifférenciée) k fois, et on décrète que lorsqu'un rayon atteint l'ordre p, l'algorithme prend fin. Plus p est grand, plus le réalisme est poussé mais plus le temps de calcul est long. La complexité du calcul est 2-exponentielle donc grosso modo en passant de p à p+1 on double le temps de calcul...


2) Difficultés


a) Temps de calcul et optimisations

Le temps de calcul, dont on a déjà parlé, est un problème majeur. Un algorithme de complexité exponentielle est problématique car la vitesse d'exécution n'est quasiment pas améliorée par la puissance de la machine qui fait tourner le programme. Le problème réside dans le nombre de calculs d'intersection qu'on va faire. Pour chaque rayon on calcule son intersection avec chaque objet, on cherche ensuite une intersection avec chacun des objets pour voir si la source éclaire le point (enfin, dans ce cas-là on peut s'arrêter à la première intersection trouvée) et en plus on relance deux rayons à chaque fois.

Le but, c'est donc de limiter le nombre d'intersections. A cet effet, je suis parti du principe que certains objets demandaient plus de calculs d'intersection que d'autres (un cube est par exemple formé de 12 facettes triangulaires car ça simplifie beaucoup le point de vue de l'intersection d'un point de vue géométrique, donc calculer l'intersection avec un cube peut engendrer jusqu'à 12 calculs d'intersection). De plus, certains objets ont "plus de chances" d'être intersectés que d'autres comme par exemple le plan infini ; étant donné qu'il est infini il comporte plus de points qu'un objet fini et a plus de chances d'être intersecté.

Ainsi, si on définit pour chaque objet qu'on introduit une priorité et qu'on trie la liste des objets par priorité décroissante, on va améliorer le temps de calcul sur la phase de recherche d'intersection avec les rayons issus des sources puisqu'on aura de meilleures chances de tomber sur les objets moins gourmands en calculs que sur les autres. On évitera donc des calculs inutiles.

Autre solution qui existe et à laquelle je n'ai pas eu à penser moi-même : les objets englobants. Mettez un cube dans une sphère (la plus petite possible mais contenant le cube) : un rayon intersecte le cube seulement s'il intersecte aussi la sphère. Dans le meilleur des cas, le rayon n'intersecte pas la sphère et on sait donc qu'il n'intersecte pas le cube avec un seul calcul au lieu de 12. Dans le pire des cas, le rayon intersecte la sphère mais pas le cube et ça nous coûte 13 calculs au lieu de 12. A moins que le cube occupe toute la scène, on est largement gagnants.

b) Détails d'implantation

Il y a des trucs auxquels faire gaffe et qui sont très difficiles à débuguer quand on n'a jamais expérimenté ce genre de choses. Par exemple, quand on lance un rayon réfléchi partant de I où I est un point de l'objet O, mathématiquement ce rayon intersecte l'objet O mais dans le cadre de l'algorithme il faut penser à exclure ce point sinon tout se passera comme si l'objet se cachait lui-même étant donné que le point d'intersection le plus proche de I, c'est I, donc la couleur réfléchie serait toujours celle de l'objet lui-même !

D'autres erreurs qui s'étaient glissées au tout début et que j'ai eu un mal fou à trouver : les erreurs dues à l'imprécision des calculs. En maths, 10^-15 c'est différent de 0, en informatique... ça dépend ! Selon la précision avec laquelle est codé le nombre (précision nécessairement finie sinon il faudrait avoir des mémoires infinies et pire, des quantités de mémoire non dénombrables) ça peut très bien être égal. Du coup, il faut faire toutes les comparaisons entre nombres réels avec une précision fixe epsilon (arbitraire et moins fine que la précision des nombres "double" en Java). Aux quelques endroits où j'avais oublié de mettre ça, on arrivait parfois à des aberrations où le programme ne trouvait pas d'intersection parce que le point qu'il avait trouvé était à une distance infime de l'objet, mais non nulle.
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Jeu 19 Sep - 17:30

II) Interface, fonctionnalités



Dernière édition par Cortano le Jeu 19 Sep - 21:28, édité 2 fois
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Jeu 19 Sep - 17:32

III) Extensions notables

1) Textures avancées, UV-mapping

Jusqu'à présent, les textures étaient représentées par :

- un triplet RGB noté Ka (absorption)
- un triplet RGB noté Kr (réflexion)
- un triplet RGB noté Kt (transmission ou réfraction)
- un triplet RGB noté reflectance (pour la composante diffuse)
- un triplet RGB noté brillance (pour la composante spéculaire)
- un indice de réflexion en précision "double" (en Java il y a deux façons majeures de représenter les réels : précision float et précision double, plus précise. Un indice de réflexion n'a pas à être très précis mais cette valeur intervient dans le calcul des rayons réfractés donc si je le mettais en précision float il se mélangerait à des calculs en précision double et ferait donc baisser la précision au point que des tests d'égalité à epsilon près finiraient par échouer à tort !)

On avait donc la même texture appliquée sur l'ensemble de l'objet et ce qui donnait un aspect non uniforme c'était uniquement la position des sources et des autres objets (ombres, réflexions, réfractions). Mais... et si on était plus gourmand et qu'on décidait de prendre une belle image 2D et de la plaquer à la surface de l'objet ?

Principe

Par le passé, quand on faisait référence à la couleur intrinsèque de l'objet obj, on appelait la méthode obj.Ka() qui renvoyait toujours la même chose puisqu'il n'y a pas d'argument. Désormais, rajoutons la méthode obj.Ka(Point p). Cette méthode (ou fonction) va renvoyer un triplet RGB dépendant du point p. Mais voilà, le point p est un point de l'espace donc est défini par 3 coordonnées, tandis qu'un pixel d'une image 2D n'est défini que par 2 coordonnées.

On va donc devoir créer une fonction de transformation qui à p=(x,y,z) triplet de réels appartenant à obj associe (u,v) couple d'entiers désignant un pixel de l'image 2D qu'on veut coller sur notre objet. Évidemment, cette transformation est entièrement dépendante de la nature géométrique de l'objet. Après avoir gratté des pages de papier dans le vent, je suis allé voir sur Wikipédia la formule de l'UV mapping pour une sphère... Ca a donné ça (j'ai volontairement sélectionné les ratages qui m'ont orienté vers de meilleures solutions, y'avait aussi d'autres images de meilleure qualité) :

[Vous devez être inscrit et connecté pour voir ce lien]

Effet bois sur les deux sphères, mais on remarque un défaut assez visible sur la droite, on voit bien la différence de couleur entre les deux bords de l'image qui se rejoignent à cet endroit. C'est comme si j'emballais avec du papier cadeau un objet sphérique : à un endroit, les deux bords vont se rejoindre et on mettra du scotch.

[Vous devez être inscrit et connecté pour voir ce lien]

Autre illustration de cet effet, sous un autre angle. L'image idéale, c'est donc celle pour laquelle, si j'en fais des copies et les dispose en mosaïque, on ne verra pas la transition entre une copie de l'image et sa voisine car le motif est régulier. Cela dit si j'ai cette contrainte, je ne vais pas aller bien loin.

Ce que j'essaierai donc, c'est de faire déterminer à l'objet quels pixels de l'image afficher suivant l'angle sous lequel il est vu. Un peu comme si vous présentiez toujours votre meilleur profil  aux autres, en vous déplaçant en même temps qu'eux de sorte qu'ils ne voient jamais que ce profil.

[Vous devez être inscrit et connecté pour voir ce lien]

Là, un autre soucis. L'image de j'ai utilisée pour ça est celle d'un mur de briques, et elle est bien plus grande que toutes les autres textures que j'ai testées. Résultat, c'est comme si j'emballais mon cadeau avec plusieurs épaisseurs, donc je repasse à des endroits où il ne faudrait pas et ça donne ça. Du moins c'est pour l'instant comme ça que j'interprète cet aspect en cercles concentriques, que je n'ai pas encore corrigé pour cette texture.

Malgré ces petits soucis, j'ai décidé de me lancer sur les autres objets à ma dispositions : les cubes, les plans et les cônes (non encore traité). Le truc classique pour les plans, c'est de faire un damier. Alors j'y vais gaiement et naïvement, je dessine un petit damier sous Paint en forme de 5 (un 5 sur un dé) :

[Vous devez être inscrit et connecté pour voir ce lien]

C'est assez moche, et pour cause, c'était idiot de faire un 5 car ça ne respecte pas "la règle de la mosaïque" dont j'ai parlé. Une fois l'erreur vue, je refais un truc sous Paint, en contractant également l'image comme expliqué plus loin pour que les carreaux soient plus nombreux et leurs défauts plus petits :

[Vous devez être inscrit et connecté pour voir ce lien]

C'est beaucoup mieux ! On voit tout de même qu'à l'horizon, la qualité se dégrade énormément, je n'ai pas encore trouvé de solution à ça. De là, je me sentais d'attaque ! Essayons de mettre une texture un peu plus complexe sur le plan...

[Vous devez être inscrit et connecté pour voir ce lien]

Là, c'est le drame. Quand j'avais opéré sur les sphères, je n'avais pas eu de soucis de pixellisation. En fait, la fonction de transformation u,v utilisée pour les sphères contracte naturellement l'image de base, du coup les pixels sont suffisamment proches les uns des autres pour que ça reste joli. Sur un plan, ma première approche était de déterminer une base orthonormale du plan, et de mettre un pixel dans chaque carré unité (c'est-à-dire de côté 1). Sauf qu'un carré unité par pixel, c'est beaucoup trop gros ! Solution : chaque carré unité contiendra plusieurs pixels de l'image. De toute façon, l'image sera répétée plusieurs fois alors on aura pas de problème à recouvrir la surface même en contractant l'image. Le nombre de pixels par carré unité doit pouvoir être choisi par l'utilisateur en fonction de la taille de l'image et de l'objet à recouvrir. Sur la même texture, ça donne ça en contractant l'image par un facteur 4 :

[Vous devez être inscrit et connecté pour voir ce lien]

On retrouve le problème du clivage entre les répétitions du motif, mais c'est déjà bien plus net.

Par la suite j'ai un peu bossé sur tout ça, je n'ai pas tout réglé et j'ai encore certains rendus pas terribles, mais j'ai quand même réussi à pondre ça :

[Vous devez être inscrit et connecté pour voir ce lien]

Si cette image est à ce point meilleure que les autres, c'est que j'ai ajouté à tous les objets des propriétés de réflexion (ça joue énormément dans le réalisme du rendu) et que j'ai arrêté de mélanger texture uniforme et texture "avancée". Pour l'instant je suis pas allé plus loin sur ce point, j'espère que ça aura plus aux rares courageux qui auront lu ça !
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Ylie le Jeu 19 Sep - 22:36

Sympatoche ça me change de mon informatique bancaire de tous les jours.
avatar
Ylie

Messages : 437
Date d'inscription : 07/01/2012
Age : 34

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Mar 24 Sep - 22:57

2) A la conquête des cylindres

Ajouter un type d'objet dans un raytracer, c'est un peu comme préparer la naissance d'un bébé. Il faut lui acheter des biberons, des vêtements pour enfants, un lit. Là c'est pareil, sauf qu'il faut plutôt lui écrire une méthode calculant l'intersection avec une droite définie par un point et un vecteur directeur, une méthode permettant de connaître la normale (sortante) à la surface en un point quelconque de l'objet, une méthode de mapping de texture (transformation bijective - ou bijective sur une restriction de la surface, pour le reste le motif sera répété autant de fois que nécessaire - des coordonnées réelles (x,y,z) d'un point de la surface en coordonnées (u,v) entières). Il faudra également lui rajouter tout un tas de méthode permettant de la faire tourner dans l'espace, la translater, l'enregistrer au format XML, la cloner etc. Ces dernières méthodes ne sont pas directement nécessaires à l'affichage mais font partie des fonctionnalités pratiques disponibles par l'interface.

Au départ, j'ai voulu rajouter à mon raytracer les quadriques (c'est une famille d'objets géométriques). Les calculs géométriques m'ont rapidement fait pleurer même si maintenant je vois mieux comment il faudrait s'y prendre, mais bref j'ai choisi plus simple : le cylindre.

J'attaque donc gaiement (et naïvement) l'implémentation de ce nouvel objet. Je mets relativement peu de temps pour écrire toutes les méthodes requises, mais tout le monde sait qu'écrire un programme prend 10 fois moins de temps que le débuguer. Je n'ai donc pas été très surpris en voyant ça :

[Vous devez être inscrit et connecté pour voir ce lien]

Quand je vois un rendu aussi moche, je commence à limiter les facteurs variants pour trouver la source du problème. Je vire donc toutes les sources de lumière :

[Vous devez être inscrit et connecté pour voir ce lien]

La forme a l'air bonne, on va donc s'intéresser à la principale méthode qui intervient pour déterminer l'éclairement en un point de la surface : le calcul de la normale en ce même point. Là, après des tests à s'en arracher les cheveux, je finis par comprendre qu'un grand nombre de points renvoyés par ma méthode d'intersection n'appartiennent pas en réalité au cylindre, or la méthode de calcul de la normale échoue quand le point n'est pas sur la surface du cylindre, d'où ces zones totalement buguées.

Je vous passe les détails mais en gros l'erreur provenait du repère dans lequel j'effectuais les calculs. Pour me simplifier la tâche, je travaillais en effet dans un repère dans lequel l'équation du cylindre est simple, mais quand je renvoyais mon point d'intersection je transformais mal ses coordonnées dans le repère "global" auxquels se réfèrent les autres méthodes. Ainsi même si le calcul d'intersection était exact, le résultat renvoyé après transformation était un point qui pouvait ne pas appartenir au cylindre. J'ai corrigé ça, mais ça n'a pas tout réglé. J'ai eu un des bugs les plus exaspérants à corriger depuis que je m'applique au lancer de rayons. Exemples en images :

[Vous devez être inscrit et connecté pour voir ce lien]

Une vue de côté.

[Vous devez être inscrit et connecté pour voir ce lien]

Une vue de face, éclairée de face également. On voit que les zones non éclairées sont totalement aberrantes, mon objet est éclairé en pleine face et il est à moitié ombragé. Le plus troublant, c'est que ces zones d'ombres semblent venir de derrière (imaginez un cylindre transparent, les zones que vous verrez par transparence s'apparentent beaucoup aux zones d'ombre de la deuxième image).

C'était une erreur ridicule, mais j'ai mis énormément de temps à la comprendre car elle portait sur du code pré-existant, qui fonctionnait depuis des mois. C'est le risque : quand on écrit du nouveau code et que quelque chose ne marche pas, on a tendance à croire que ça vient du nouveau code et pas de l'ancien. Et pourtant, il se peut très bien que du code qui a fonctionné dans certains contextes pendant des mois montre finalement ses erreurs dans un contexte nouveau. C'est ce qui s'est passé !

En fait c'est tout bête : à un moment de l'algorithme, on détermine si un point P de la surface de l'objet est éclairé ou non par une source S donnée. Pour ça, on regarde s'il existe, entre la source et le point, un objet intersectant en I le rayon allant du point vers la source. Mon code recherchait l'existence d'un tel point et comparait la distance de P à I et la distance de P à S. Si I était plus proche de P que S, j'en déduisais que P n'était pas éclairé par S. Et c'est... faux. On sait que P, I et S sont sur le parcours d'un même rayon donc ils sont alignés, mais rien dans ce que j'ai dit ne renseigne sur l'ordre de cet alignement. Ainsi, il est très bien possible que P soit très proche de I mais que l'ordre des points soit I, P, S auquel cas P est quand même éclairé par S. D'ailleurs, ça confirme bien que ce qu'on voyait en zone d'ombre c'était des points "derrière" les points qui devraient être éclairés !

Cette erreur est évidente et stupide, mais du fait de la géométrie des autres objets, ça devait être une situation soit impossible (par exemple pour un plan) soit rare (pour une sphère ou un cube) à tel point que même quand ça arrivait, ça n'impactait que quelques pixels donc passait inaperçu. Et je le répète, penser à aller modifier du code qui marche depuis 2 mois, ça demande du temps.

Le résultat après cette révélation :

[Vous devez être inscrit et connecté pour voir ce lien]

Mieux ! Mais je suis un gourmand... maintenant que j'ai implanté des textures mappées pour tous mes objets existants, je ne me vois pas laisser le cylindre tout nu. J'attaque donc le mapping du cylindre... A priori, c'est facile : un cylindre, ce n'est rien de plus qu'un rectangle qui se referme sur lui-même, avec deux bases circulaires pour fermer. Pour les bases je n'ai pas encore de solution complètement satisfaisante (si j'applique une texture abstraite ça fait joli mais si c'est un motif plus rigoureux on voit trop le "collage"), mais pour la surface latérale ça marche impec.

J'ai eu un seul soucis, et il est particulièrement honteux pour quelqu'un qui n'a fini sa prépa qu'il y a deux ans !

[Vous devez être inscrit et connecté pour voir ce lien]

Ce n'est pas si laid, mais ce n'est pas l'effet escompté et quand on fait tourner le cylindre autour de son axe, on voit apparaître des sortes de paraboles "imbriquées" (pas d'images dispo) car plus on s'écarte de la zone visible sur l'image précédente, plus la distorsion du motif devient importante. J'ai bien dû passer 1h30 à comprendre pourquoi ça marchait pas... Le principe était assez simple : j'ai un point p en paramètre dont je sais qu'il appartient au cylindre (si tout va bien), je détermine s'il appartient à une base ou non - très facile avec mon repère lié au cylindre - si c'est le cas je fais un traitement particulier, sinon je détermine l'angle de ce point en coordonnées cylindriques. Et c'est là qu'est le soucis !

En dimension 2 (sur un plan), si on fait le produit scalaire de deux vecteurs, c'est égal au produit des normes (leur longueur) et du cosinus de l'angle entre les vecteurs. En dimension 3, ba... l'angle qu'on obtiendra de cette façon sera l'angle entre ces deux vecteurs dans le plan qu'ils forment. Ma bourde a tout simplement été de prendre cet angle plutôt que celui entre les projections des vecteurs sur la base du cylindre et c'était exact uniquement quand le point p était dans le plan formé par mes deux premiers vecteurs de base (le 3eme étant l'axe du cylindre). Comme le centre de mon repère est le centre de la base qui est à gauche sur l'image, la formule que j'avais était "presque vraie" à proximité de la base gauche mais devenait "de plus en plus fausse" en s'en écartant, d'où la distorsion vers la droite.

En réalité, le cosinus de l'angle se trouvait en projetant d'abord le vecteur (c,b) - où c est le centre du repère - dans le plan formé des deux premiers vecteurs de la base PUIS seulement en calculant le produit scalaire. Le truc, c'est que c'est tellement un réflexe de calculer des angles avec un produit scalaire (surtout en physique) que j'ai eu tendance à le faire à l'arrache sans même penser que ça ne s'appliquait pas ici. A la place, j'ai passé des plombes à me demander si je ne faisais pas des erreurs sur le domaine de l'arccos (il faut faire gaffe au signe du sinus, ça change la façon de récupérer l'angle à partir du cosinus de l'angle), si ceci, si cela... Bref, le résultat une fois corrigé :

[Vous devez être inscrit et connecté pour voir ce lien]

L'épreuve redoutable de la texture à carreaux est passée ! C'est un bon test car c'est une texture très régulière, on s'aperçoit donc immédiatement quand quelque chose ne colle pas alors qu'avec une texture abstraite ça peut tout à fait être magnifique bien que complètement faux.

Il persiste des petits soucis avec la réflexion sur les cylindres (y'a des effets parfois étranges que je comprends pas encore bien), mais après quelques modifications mineures j'ai décidé que j'avais assez avancé pour me faire plaisir :

[Vous devez être inscrit et connecté pour voir ce lien]

Voilà, merci d'être toujours plus nombreux à me suivre (je plaisante bien sûr, je sais très bien que même au sein de mon école je suis vu comme un taré de continuer ce projet 2 mois et demi après la fin), et j'espère qu'au moins si vous passez voir les images, elles vous plairont !


Dernière édition par Cortano le Ven 27 Sep - 7:22, édité 1 fois
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Ylie le Mer 25 Sep - 9:44

Sympatoche Smile si ce n'est l'effet de la sphère coupée en deux par l'ombre trop nette. Surement a cause de l emplacement de ta "source de lumière"
avatar
Ylie

Messages : 437
Date d'inscription : 07/01/2012
Age : 34

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Ylie le Mer 25 Sep - 10:02

Ta source de lumière est différente pour chacun de tes objet c est un peu incoherent du coup.
avatar
Ylie

Messages : 437
Date d'inscription : 07/01/2012
Age : 34

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Mer 25 Sep - 10:23

De mémoire il y avait une seule source mais c'est vrai qu'on voit que les ombres des deux cylindres partent dans deux directions distinctes. Les cylindres sont symétriques par rapport au plan y=0 (z est ici la hauteur et l'axe des x est orienté vers l'observateur), et la source se situe dans ce plan à distance relativement faible des objets, ce qui explique à mon avis ces ombres. D'ailleurs, les ombres convergent effectivement vers un point proche, en direction de l'observateur.

Je ne pense pas que ça soit incohérent dans ce contexte (source ponctuelle, donc en principe artificielle) mais c'est vrai qu'en lumière naturelle les ombres seraient parallèles, ce qui se modélise par une source à très grande distance. Pour la sphère je suis d'accord, le seul moyen d'y remédier est de baisser son coefficient de réflexion, ou alors l'écarter d'avantage du plan.
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Ylie le Jeu 26 Sep - 9:29

j'avais identifié la source ponctuelle pour les cylindres mais c'était incohérent avec la sphère et les cubes Smile qui réagissent comme si la source était différente pour eux, en gros ca me donne une impression de collage Wink .
Après je ne serais pas capable de le faire moi-même. je met juste en "lumière" ce qui me saute au yeux, pour les prochaines améliorations que tu pourrais y apporter.

à ce soir pour l'opé !
avatar
Ylie

Messages : 437
Date d'inscription : 07/01/2012
Age : 34

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Ven 27 Sep - 7:36

Ylie a écrit:j'avais identifié la source ponctuelle pour les cylindres mais c'était incohérent avec la sphère et les cubes :)qui réagissent comme si la source était différente pour eux, en gros ca me donne une impression de collage Wink.
Après je ne serais pas capable de le faire moi-même. je met juste en "lumière" ce qui me saute au yeux, pour les prochaines améliorations que tu pourrais y apporter.

à ce soir pour l'opé !
T'inquiète je prenais pas la mouche je suis déjà flatté que tu prennes quelques minutes pour consulter ce topic ! Sinon, pour la sphère, j'ai identifié un peu plus tard que l'effet "coupée en deux" était simplement dû au fait que quand la texture finit d'englober l'objet, les deux bords se rejoignent et si la texture n'est pas à symétrie sphérique ça fait effet collage. J'aurais donc dû faire tourner la sphère pour qu'elle montre sa meilleure face !

Enfin, je lance un petit teaser (même si j'ai aucune idée de quand je commencerai, et encore moins de quand j'y arriverai) : j'ai déjà présenté un monde de cubes, de plans, de cylindres, de cônes et de sphères. J'ai déjà montré comment étendre cet univers pour le complexifier, mais on a pu voir que chaque objet a sa géométrie et qu'il peut être compliqué de rajouter les objets un par un en réécrivant toutes ses méthodes. Imaginez un monde où il suffirait de combiner deux objets pour en créer un nouveau, un monde où il n'y aurait qu'à définir des opérations ensemblistes (union, intersection, exclusion...) une bonne fois pour toutes et s'en servir ensuite pour créer à partir de deux objets un objet nouveau. Et après tout, si on peut combiner deux objets en un troisième, pourquoi ne pas combiner deux objets combinés en un troisième ? Au final, on représenterait les objets par des arbres binaires dont les noeuds seraient des opérations ensemblistes et les feuilles des objets élémentaires. Ca va être un challenge...
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Lun 30 Sep - 18:40

Je me suis un peu emballé en fait... Je pensais pouvoir faire toute une nouvelle variété d'objets avec des intersections, exclusions et unions mais c'était sans compter que toute la géométrie qui a été mise en place ne traite que des surfaces et non des volumes, or des intersections entre surfaces c'est tout de suite moins intéressant que sur des volumes ! Ca serait très dur d'adapter ce que j'ai fait pour gérer ce genre de choses.

J'essaierai donc de m'attaquer aux quadriques quand j'aurai le temps et l'envie, sachant que c'est pas gagné car ça m'oblige à implémenter une ou plusieurs classes pour représenter des polynômes à plusieurs variables et les dériver. Je pourrais faire des classes ultra-spécifiques juste à cet usage mais j'ai décidé que si je le faisais ça devrait être plus général. Voilà, je reposterai sûrement pas avant un moment pour votre plus grand désespoir...
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Asoka le Mar 1 Oct - 13:07

Et avec tout ça tout pourrai nous pondre un logo de ouf pour la guilde ? :p
avatar
Asoka

Messages : 33
Date d'inscription : 08/03/2013

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Ylie le Mar 1 Oct - 20:26

avec des cylindres et des sphères :p
avatar
Ylie

Messages : 437
Date d'inscription : 07/01/2012
Age : 34

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Nulhyedbrick le Jeu 3 Oct - 13:04

Nous créer un tabard de guilde:P 

Nulhyedbrick

Messages : 141
Date d'inscription : 14/01/2012

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Ylie le Jeu 3 Oct - 14:46

Quoi une distinction visuelle pour les membres de guilde ! Tu veux pas aussi qu on investisse dans des uniformes !
avatar
Ylie

Messages : 437
Date d'inscription : 07/01/2012
Age : 34

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Nulhyedbrick le Ven 4 Oct - 7:25

Cela pourrait etre marrant, tous en tenue d'esclave et le gm en cuir avec un gros fouet Laughing 

Nulhyedbrick

Messages : 141
Date d'inscription : 14/01/2012

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cortano le Sam 5 Oct - 14:24

Jpourrais penser à un logo mais c'est pas tellement adapté ^^ A la limite si j'avais des screens de 4-5 membres je pourrais les coller sur des objets et faire une petite animation où on voit défiler les objets-portraits, ça serait un peu long à faire (pour paramétrer les déplacements de la caméra puis pour attendre que ça calcule) et le fichier final serait assez lourd (gif...) mais c'est faisable :p

D'autant que j'ai pensé à un truc tout bête pour corriger les soucis de l'effet collage : peu d'images sont à symétrie sphérique (chacun des bords correspond au bord opposé), mais à partir d'une image on peut toujours créer une image deux fois plus grande qui l'est :

[Image]--------------------------[Image inversée horizontalement]
[Image inversée verticalement]----[Image inversée verticalement et horizontalement]

ça nous fait une image qui est à symétrie sphérique. Ca introduit des symétries factices mais au moins je n'ai plus aucun soucis avec les images qui ont des bords très différents. Le mieux, c'est que ça ne m'a coûté qu'une quinzaine de lignes de code.

Enfin, en ce moment je m'en occupe plus trop car j'ai constaté de nouveaux bugs liés aux réflexions sur des cylindres et des cônes que j'arrive pas à comprendre et qui m'ont soulé et surtout parce que mes tentatives d'accélérer le calcul en introduisant du calcul parallèle ont échoué.

Un topo rapide là-dessus : ça doit vous arriver de faire plusieurs choses à la fois, comme répondre au téléphone tout en surveillant la cuisson de quelque chose. Si vous faisiez soit l'un, soit l'autre, ça prendrait beaucoup plus de temps (il faudrait terminer l'appel puis seulement allumer le feu). En informatique c'est pareil, depuis que les ordinateurs ont plusieurs processeurs ou au moins plusieurs coeurs, on peut faire s'exécuter plusieurs processus en parallèle. Malgré tout, il faut les synchroniser et ça passe souvent par le bloquage volontaire de certains processus pour éviter des cafouillages (par exemple si le poulet est en train de cramer vous devez interrompre votre discussion, et bien d'autres soucis impossibles à "métaphoriser") ce qui limite un peu le facteur d'accélération qu'on peut obtenir avec ce parallélisme.

Dans certains cas, on a de l'interblocage. Il y a plusieurs façons d'y arriver, par exemple si vous marchez dans la rue et que vous êtes sur la même trajectoire que quelqu'un qui vient de face, vous allez le contourner par la gauche mais la personne en fait autant au même moment. Vous partez à droite mais elle en fait autant etc... Une autre situation : si vous êtes galants, vous voulez laisser passer une femme dans le bus avant vous mais elle est très féministe et veut être traitée à l'égal d'un homme alors elle vous intime de rentrer en premier, et aucun des deux ne flanche. Il y a des tonnes de situation où une erreur dans la synchronisation (nécessaire) des processus peut conduire à des situations où l'exécution se retrouve bloquée. Eh ben c'est ce qui m'arrive quand j'essaie de le faire, l'exécution se bloque assez tôt et le calcul ne finit jamais. J'ai très peu d'expérience en synchronisation et c'est horrible à débuguer (si vous avez n processus exécutant chacun k instructions, il faut envisager n'importe quel ordre d'exécution de ces n.k instructions, si vous rajoutez des contraintes de synchronisation, c'est infernal de suivre l'exécution et surtout ça ne sera pas deux fois pareil, ça peut très bien marcher dans 99 cas sur 100 et planter dans le dernier), donc j'ai abandonné pour le moment !

A dimanche tous Smile
avatar
Cortano

Messages : 75
Date d'inscription : 07/06/2012
Age : 26
Localisation : Toulouse

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Cassandre le Mer 9 Oct - 13:01

Sérieux ?

Montre..
avatar
Cassandre

Messages : 87
Date d'inscription : 12/01/2012
Age : 52
Localisation : Region parisienne

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

J'aimerai savoir faire.

Message  Cliodna le Dim 29 Déc - 10:56

Sympa la 3D.

Je ne m'y suis toujours pas mise.

Je me contente de réaliser des logos 2D pour entreprises.


Pas le temps de me mettre sur un programme type Blender.

Cliodna

Messages : 11
Date d'inscription : 23/12/2013
Age : 36

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Journal de développement

Message  Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum