Forums Casio - Projets de programmation

Index du Forum > Projets de programmation > Windmill : moteur graphique 3D
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Posté le 30/09/2016 00:44

Windmill : moteur graphique 3D :

Windmill



Bonjour, bonsoir !

Windmill est un moteur graphique 3D pour calculatrices CASIO monochromes.
Ce topic est le journal de bord du projet, il décrit l'avancée étape par étape, jour par jour, depuis la création du projet à aujourd'hui.

Début du projet : juillet 2016
Dernière mise à jour : septembre 2018
Dernière démo : jour 17

Un petit brief d'abord :
Windmill est un moteur graphique 3D, il est capable d'afficher des objets définis en trois dimensions.
Le principe de base du moteur graphique est de décomposer en triangles un modèle 3D puis d'appliquer des textures sur ces triangles en gérant l'occlusion.
Sur calculatrice, il n'existe aucune libairie dédiée à le 3D, donc Windmill a été écrit à partir d'une feuille blanche, tout à été réalisé de A à Z.

Jour 1
Cliquez pour recouvrir

Dans la vidéo, j'ai optimisé le moteur graphique pour les murs verticaux. c'est à dire qu'il ne dessine plus des triangles mais des trapèzes, j'ai commencé l'optimisation pour les murs horizontaux récemment.
La bonne nouvelle c'est qu'il reste une grosse marge de progression pour optimiser ces cas particuliers : éviter les flottants, gérer un peu mieux le clipping, le back face culling et éviter un calcul redondant dans la boucle principale.


Jour 2
Cliquez pour recouvrir

Principalement un gros travail sur l'optimisation des murs : la plupart des calculs flottants sont désormais avec des entiers, le clipping est géré (on affiche pas les pixels en dehors de l'écran), des calculs sont simplifiés, et même pour gagner encore quelques fps les textures doivent être tournées de 90°.
Désormais les murs horizontaux peuvent être affichés, et même le plafond noir (avant c'était de la triche juste pour la vidéo...), des textures peuvent être appliquées sur le sol, et on peux construire des objets telle que la caisse ici présente.
Les textures peuvent être changées pendant le jeu, ainsi cela permettra d'afficher des textures animées comme de l'eau par exemple !
Il y a trois types d'objets affichable :
- les murs. De face ou de coté.
- les étages. Il s'agit d'objets plats, par exemple le sol, le paillasson, le haut de la caisse.
- le plafond. C'est un étage optimisé pour le noir.
Tous les objets sont paramètrables, de la taille, la hauteur, la texture que l'on veut.


Jour 3
Cliquez pour recouvrir

Simplement un aperçu de la vue de coté, en fil de fer cette fois parce que je n'ai pas terminé l'algo pour afficher les textures sur les murs.
J'ai déjà la structure de l'algo pour appliquer mes textures, il me reste plus qu'a l'implémenter. Il ressemble à celui que j'ai déjà mais avec une variante. Cependant je vais le reprendre de zéro pour être certain d'optimiser au mieux.
Parce que avec cette vue il y a beaucoup de chose qui changent :
- les textures appliquées sur le sol, au plafond ne sont plus des sprites classiques, elles sont maintenant déformées ce qui implique d'utiliser l'algo "lourd" et pas un simple affichage de sprite zoomé (cf la lib ML_zoom)
- les murs orientés vers le "sud" ne sont plus visible car toujours vu par "derrière" donc plus besoin d'être géré. Ça c'est une bonne nouvelle, mais je ne pense pas que ça puisse compenser le point du dessus.

Donc en conclusion, j'ai peur quand aux performances de l'ensemble fini. Il va arriver un moment où ça risque de coincer.


Jour 4
Cliquez pour recouvrir

GROSSE GROSSE nouveauté ! Comme promis le moteur gère la vue de coté !!
Pour cela j'ai totalement repris mon algo de base pour appliquer les textures sur des triangles avec un bon passage à la moulinette de l'optimisation, et j'ai ainsi multiplié par 11 les performances ! C'est énorme !

La prochaine étape est d'implémenter le Z-buffer pour ne pas voir à travers les murs, et encore un tas d'optimisations...
Et maintenant il n'y a pas de cas particuliers dans l'algo, c'est à dire que je peux tourner la caméra dans tous les sens, afficher des formes dans n'importe quelle position (mais ça ce sera pour une prochaine vidéo )


Jour 5
Cliquez pour recouvrir
Et voilà encore du nouveau ! (Oui ça avance vite )
Maintenant j'ai rajouté le z_buffer qui permet de ne pas afficher les murs sensé ne pas être visible.
Et j'ai rajouté un degré de liberté pour la caméra, ce qui permet de tourner sur soi-même.
Il reste encore un tas de choses à améliorer (meilleur rendu des textures, déplacement de la caméra selon différents repères) et d'optimisations (accès à la vram plus intelligent pour éviter de dessiner du banc si c'était déjà blanc, passage des calculs pour les rotations, les projections et les produits vectoriels en nombres entiers).
Je vais mixer un peu le rendu avec le mode fil de fer pour les murs vu par derrière (qui sont transparents actuellement). J'ai déjà fait quelques test et on se rend mieux compte des volumes !


Jour 6
Cliquez pour recouvrir
J'ai amélioré la qualité du rendu général en jouant sur les décalages de bits de façon plus astucieuse, en simplifiant des opérations et en arrondissant les nombres flottants. Résultat moins de perte à cause d'arrondi et de troncature, les textures sont moins déformées et plus précises.
J'ai encore optimisé mon algorithme pour appliquer les textures, j'étais passé à côté de quelque chose d'énorme, résultat j'ai pu simplifier encore mes calculs pour gagner 35% de performances. Je suis passé de 10 décalages de bit, 17 mults, 9 additions à 7 décalages, 12 mults et 10 additions.

J'ai apporté quelques modifications au z-buffer (qui permet de ne pas afficher les objets caché par d'autres), l'initialisation est plus rapide et il est plus stable car il ne risque pas de d'overflow. Et je ne dessine plus de pixel blanc si c'est la première fois que je dessine sur un pixel puisqu'il était forcement blanc avant.

J'ai rajouté la gestion des viewport, c'est à dire que le rendu peu être dans une fenêtre définie par le programmeur et plus forcement sur l'écran entier. C'est utile si on utilise un ATH qui prend une partie de l'écran ou dans un menu pour afficher un objet 3D dans un coin facilement. Je n'ai pas testé, mais il est théoriquement possible d'afficher deux rendus différents en même temps, un écran splitté pour le multijoueur par exemple


Jour 7
Cliquez pour recouvrir
Il n'y a pas grand chose de nouveau visuellement donc je sors pas de vidéo, mais maintenant que j'ai fini d'opimisé le rendu des textures, j'ai optimisé la transformation des points dans l'espace 3D. J'ai gagné 71% de rapidité depuis le jour 6 ! Entre autres, j'ai précalculé les cos et sin, les coefficients de la matrice de rotation, le tout avec des nombre entiers.
Ce qui me prend du temps en ce moment c'est la structure de mes données, comment faire quelque chose d'efficace et qui permette d'écrire les modèle 3D rapidement à la main. Donc je gère des mini structures toutes faites, des triangles, des rectangles, et peut être d'autres plus tard comme des cylindres.

De plus, j'ai ajouté une fonctionalité qui permet d'appliquer une texture des deux cotés d'un triangles. Mais un problème est apparu, quand deux textures sont trop prochent l'une de l'autre, elle on tendance à se chevaucher, c'est à dire que la texture qui est derrière est affichée par dessus celle de devant...Ici on voit la texture blanche qui passe par dessus le mur de brique (frame 2 à 7)

Ça fait une journée que je cherche le problème. Il vient evidemment du z-buffer, mais la raison du problème est assez floue


Jour 8
Cliquez pour recouvrir
J'ai réussi à repérer l'origine de mon problème après plusieurs longues séances de documentation et de débeugage.
L'utilisation des matrices de projection perspective m'a permis de remapper la coordonnée z de mes points dans l'espace caméra, c'est à dire que maintenant leur coordonnée z à une valeur logique : elle est définie à 0 quand le point est sur le near clipping plane et à 1 sur le far clipping plane. Deux plans que je définie moi même.

Ceci m'a permis de mettre au jour une relation très vicieuse entre mes triangles que je n'avais pas remarqué jusqu'à présent. Je m'explique : dans ma phase de simplification, j'ai remarqué qu'une division était inutile puisque qu'elle se simplifiait dans une multiplication un peu plus loin. Dans le même genre que (A / B) x (C x B) = A x C
Cela n'a pas posé de problème de simplifier, j'ai obtenu exactement le même rendu.
Cependant, et c'est là que c'est vicieux, c'est que, plus tard, en rajoutant mon z-buffer (qui permet de connaître la distance entre mon point et la caméra afin d'afficher uniquement le plus proche), j'ai fabriqué une relation cachée entre mes triangles. En effet ils ne sont plus dessinés independamment puisqu'ils partagent le même z-buffer.
Et comme j'ai utilisé uniquement A et pas A / B et que B varie d'un triangle à l'autre, les données que je rentrais dans mon z-buffer étaient faussent.
Mais comme B varie peu, le problème ne s'est pas montré au premier abort, mais il était bien là !

Maintenant que je comprends l'origine du problème, je vais pouvoir le résoudre. En tout cas, c'était bien tordu et ça m'a bien pris la tête.
Désolé pour ce passage assez technique, mais expliquer l'origine du problème ne peut pas se faire sans


Jour 9
Cliquez pour recouvrir

Et voilà problème réglé ! Enfin, ça m'a pris une journée complète. (j'ai bien perdu 1h sur un copier coller raté et 3h parce que j'avais pas mon café...)
Maintenant le z-buffer est ultra propre ! je maitrise vraiment tout se qui passe. Un bon point pour la stabilité et éviter l'apparition d'artéfactes visuels


Jour 10
Cliquez pour recouvrir

J'ai commencé à modéliser des vrais objets pour voir ce que mon moteur a dans le ventre, et le résultat est renversant !
En définissant toutes les faces du moulin à vent, j'ai pu créer avec une relative simplicité un résultat plus que correct.
D'un point de vue technique, j'ai de nouveau optimisé depuis le jour précédent, en effet j'avais tout "désoptimisé" pour résoudre mon problème. Les fps en temps réel sont affichés dans le coin de l'écran, on voit que pour un modèle aussi riche (30 triangles) la vitesse du rendu est plus que convenable ce qui démontre que ce projet est viable. De plus il me reste quelques points à optimiser, sur le calcul des coordonnées de textures je peux grater pas mal, j'ai deux divisions que je peux transformer en une seule, et quelques autres idées. Donc j'ai encore de la marge, l'objectif étant qu'a terme le rendu soit le plus véloce possible

Sinon on peut remarquer que j'applique des textures sur des triangles dans des positions quelconques (le toit et les pales) et que j'ai ajouté l'option pour afficher une texture différentes de chaque côté d'un triangle (le toit vu par en dessous est noir) et j'ai rajouté un paramètre pour une bonne utilisation des textures sur les triangles (en effet le sprite est un carré à la base).

La prochaine étape est une réorganisation du code, j'ai deux fichiers que je vais réunir en un seul et je vais revoir comment le moteur recoit les objets à afficher. Dans la prochaine vidéo, les pales du moulin tourneront (enfin je l'espère bien )


Jour 11
Cliquer pour enrouler
Jour 11


Maintenant le moteur peut afficher plusieurs objets différents et les objets dynamiques ! J'ai revu totalement la façon de fournir les objets à afficher au moteur. Maintenant on peut afficher plusieurs objets simultanément, et on peut définir des mouvements pour les objets.


Jour 12
Cliquer pour enrouler
Jour 12

Après une grande pause, le projet reprend, en fonction de ma disponibilté, plus faible qu'avant, mais toujours présente
Comme je l'avais annoncé, la reprise de mes travaux portent sur l'optimisation, la résolution de bugs, et des changements internes pour les nouveautés à venir.

- nettoyage du fov, la valeur qui correspond à l'angle de vision, c'était un peu au pif avant.

- mise en const des variables de la map : les textures, les objets, les triangles et les rectangles.

- j'ai clarifié la précision des fixed (des nombres entiers utilisés comme des nombres à virgules) pour éviter les débordements, c'est surtout problématique pour les objets lointains, ou très proches car des variables s'approchent des limites d'un int.
Maintenant je suis certain qu'afficher un objet à la taille minimale (de taille 1) ne pose aucuns problèmes.
un cube de côté 1 :


un cube de coté 10, avec à sa droite le cube de coté 1.


(On voit le sol à partir de cette échelle, la distance entre les points est de 10)
L'histoire d'échelle est d'ailleurs très subjective, à combien correspond une taille de 10 si on veut la comparer au monde réel ? J'ai fait la proposition suivante : 1 = 10cm

- j'ai ajouté un repère 3D dans un coin de l'écran, c'est utile pour le debug.

- j'ai sorti la camera de la scène, c'est à dire que j'ai crée une classe juste pour la caméra.

- correction d'un problème dans le z-buffer (un tableau de la taille de l'écran enregistrant la distance des pixels par rapport à l'écran), j'avais un overflow, maintenant c'est tout propre !

- nettoyage divers dans le code


Jour 13
Cliquer pour enrouler
Jour 13

J'avance lentement, j'ai assez peu de disponibilité depuis 2 semaines...
MAIS ! Windmill avec encore et toujours
J'ai ajouté une fonctionnalité qui manquait depuis un long moment mais qui est pourtant essentielle : l'affichage des triangles devant le plan de clipping...
Explication :
Je parlais plus haut des plans de clipping, le proche et le lointain. Ces deux plans parralèles forment une pyramide avec à son sommet la caméra. Tout ce qui est entre ces plans est affiché. Le problème c'est si un point du triangle est avant le plan proche, jusqu'à présent si un des points avaient une coordonnée en z négative je n'affichais tout simplement pas le triangle.
Pour résoudre celà je tronque ou divise, en fonction des cas (1 ou 2 points devant le plan)

Desormais il n'y a presque plus de cas où des triangles disparaissent


Jour 14
Cliquer pour enrouler
Jour 14

Le problème de clipping que j'exposais en jour 13 est résolu !
Voici un petit rendu que comment c'était avant et comment c'est maintenant, le triangle (qui est la brique essentielle de tout le reste) est maintenant affichable avec beaucoup plus d'angle. Même quand on est presque dans le mur, il s'affiche correctement.
La texture se déforme légèrement quand on est vraiment proche, c'est dû aux erreurs d'arrondi.
Bonne vidéo


Jour 15
Cliquer pour enrouler
Jour 15

Une grosse surprise se prépare. Encore quelques soucis en train d'être corrigés et vous allez en prendre plein les yeux promis
En attendant cette semaine j'ai corrigé quelques bêtes erreurs comme un 1204 au lieu d'un 1024.
Changé un tas de chose en interne pour homogénéiser mon code
Les ajouts depuis le jour 13 :

Ajouté une ligne d'horizon (c'est tout bête mais ça rend bien mieux)

Changé les coordonnées des textures, maintenant on définit la taille en pixel en la texture, et la taille dans le monde.
Par exemple un texture de 32x32 peut correspondre à un carré de taille 20x20 (soit 2m carré), ou plus, ou moins c'est au choix.
- En affichant cette texture sur un rectangle de taille 40x40, la texture va automatiquement boucler.
- En renseignant 0x0 en taille réelle, la texture va s'étirer sur son support au lieu de boucler.
C'est très pratique pour répéter des motifs sans avoir à créer un autre rectangle, ou alors pour appliquer une texture sur n'importe quelle surface.

Actuellement j'ai un problème de serpent qui se mort la queue, clipping() doit être executé avant afficher() et afficher() doit être executé avant clipping() sinon j'ai des triangles qui s'effacent à certains moment. Je suis en train de corriger ça, mais c'est un peu casse tête

j'ai une grosse piste d'optimisation, si ça fonctionne j'estime à +30% de fps !



Jour 16

Désolé si tu es venu sur ce topic en pensant que j'ai enfin lancé LA démo ultime que j'ai vendu au jour 15.
Aujourd'hui c'est résolution de bugs.
J'ai résolu le problème du serpent qui se mort la queue en créant une fonction dédié plus rapide. Le problème était de savoir quelle face du triangle afficher, pour rentrer les dimensions de la textures dans les points.

Le problème que j'ai maintenant est une erreur d'overflow, lorsque la surface du triangle à afficher est trop importante, les nombres prennent des valeurs qui dépassent les limites d'un int (+- 2 milliards) et provoquent des bugs terribles sur l'affichage des textures.

J'ai bien ciblé le problème, je sais exactement quand, comment et pourquoi il se produit, je ne sais juste pas comment le résoudre simplement.
Après 3 soirées gachées à essayer de bricoler un truc, j'ai décidé de faire une autre fonction de clipping.
Cette fois l'objectif n'est pas découpe en plusieurs triangles ceux qui passent derrière la caméra (comme au jour14), mais découper pour n'avoir que les pixel qui sont à l'écran.
Le petit triangle s'affiche sans procblème, le grand à une aire qui overflow et bug visuellement



Jour 17


Le problème de clipping est résolu !
Pour récapituler, j'ai intégré du clipping sur l'axe devant-derrière pour couper les triangles passant derrière la caméra. Puis j'ai créé une nouvelle fonction pour découper les triangles sur l'axe haut-bas/droite-gauche, c'est à dire les bord de l'écran pour régler des problèmes d'overflow (cf jour 16). Le résultat est que le moteur est capable d'afficher des triangles dans n'importe quelle position, même la plus tordue sans bug, ou déformation du triangle.

A cette occasion j'ai revu toute la structure interne pour gérer l'affichage des objets. Je commence avec 1 triangle, et le clipping peux me renvoyer 1 à 10 triangles. Au lieu de gérer chaque point individuellement et avec des conditions à n'en plus finir, j'ai tout inséré dans un tableau que j'envoie à mes fonctions, et tout roule tout seul. c'est beaucoup plus léger et propre.

J'ai rajouté une synchronisation de la caméra avec le rendu. Le déplacement de la caméra (gestion du clavier) est appelé par un timer à interval régulier, ce qui peut tomber pendant le rendu d'une frame. Du coup je commence à dessiner un objet en regardant sous un angle X, la caméra se mets à jour et je termine de dessiner l'objet sous un angle Y. Ça provoquait des secousses et bugs visuels.

Résolution d'un bug sur le z-buffer.

Correction des quelques soucis avec le rendu du sol.

Un peu d'optimisation sur quelques variables.

Le moteur est super stable et il n'y a plus d'artéfactes visuels majeurs !!
C'est un vrai plaisir à regarder Pour ça rien de mieux qu'une vidéo !
Je teste ici sur émulateur et sur la machine, c'est quand même suffisament fluide, environ 10 fps, sachant que cette valeur est doublée avec de l'overcloacking



Jour 18


Windmill avance toujours, bien que la dernière vidéo soit impressionnante, il reste beaucoup de choses à faire.
Voici les nouveautés de la semaine :
- Réorganisation du code. J'ai ajouté une class Player et une class Engine avec un tas de petites modifications. Maintenant on peut créer son propre moteur physique et de gestion du jeu totalement indépendant du rendu 3D.
On peut même créer des moteurs physiques différents. Je suis en train d'en coder 2 :
>> Moteur de déplacement d'un personnage. En vue classique style FPS, on peut courrir, sauter, regarder dans toutes les direction (@Lephé : tout est fluide), interagir avec les objets (porte, trappe, ...)
>> Moteur de création de map. En vue de haut uniquement, on peut selectionner un objet, le déplacer, le tourner et observer ses coordonnées en temps réel. Une fois au bon endroit, il suffit d'écrire les coordonnées en dur dans le code. Très pratique pour créer une map.

- Ajout des billboard. Ce sont des sprites qui font toujours face au joueur. Il tournent sur l'axe vertical pour toujours faire face à la caméra. J'ai crée des arbres avec et des personnages avec.

- Ajout des masques alpha. Chaque texture doit avoir un sprite, et peut avoir un masque. La texture est dessinée que si le pixel du masque est noir.

- Ajout des sphere englobantes. Au chargement d'une nouvelle map, Windmill calcule automatiquement une sphere englobante pour chaque objet. Ceci permet de faire un test rapide. Si la sphere n'est pas à l'écran, aucune utilisté de vérifier si tous les triangles à l'intérieur sont à l'écran. Pour l'instant j'ai fais l'algo pour créer le spheres, il me reste l'algo pour savoir si elles sont à l'écran. J'ai mesuré les fps avant pour faire la comparaison.

- Ajout d'un tas de petites modifications.

- J'ai commencé à rédiger un manuel complet pour utiliser Windmill

Donc voilà, pas mal de nouveautés, c'est à chaque fois de plus en plus impressionnant


Jour 19


Le jour 19 arrive rapidement après le jour 18 car il y a une bonne nouveauté qui fera sans aucun doute plaisir à entendre !
J'ai terminé l'algo des sphères englobantes pour ne pas "chercher" à afficher les objets qui ne sont pas à l'écran.
Une petite explication plus détaillée
Lors du chargement de la map, un premier algorithme génère pour chaque objet une sphère qui englobe tous ses points. Lors du rendu, un second algorithme test pour chaque objet, si sa sphère est intersecte ou est incluse dans le champ de vision de la caméra. Si c'est le cas, on dessine l'objet, dans le cas contraire l'objet est ignoré.

Soit N le nombre de point d'un objet composant un objet, au lieu de calculer à chaque fois N points, on calcule au pire N+1 (N+centre de la sphère) ou au mieux 1 point. C'est très rentable !
Voici une animation représentant 2 sphères. La rouge est hors du champs de vision, la verte est dans le champs de vision.
Le gain en fps est d'autant plus important que le nombre d'objet hors du champs de vision est important. Donc impossible d'exprimer un gain fixe en fps.
Voici un comparatif :
Cas n°1, la map est peu chargée (celle en exterieur)
                                          avant   après
Tous les objets hors du champs de vision :  67       85
La moitié des objets dans le champs :       28       32

Cas n°1, la map est fort chargée (j'ai ajouté 15 moulins sur la map)
                                          avant   après
Tous les objets hors du champs de vision :  35       83
La moitié des objets dans le champs :       22       32

On remarque qu'avec cette méthode, les objets hors ne baisse pas (ou très peu) les performances.
En plus de cela, ça m'ouvre des opportunités pour de nouvelles foncionnalités


Jour 20

Une petite nouveauté dont je parlais précédemment : le trie des objets en fonction de la distance à la caméra.
Windmill trie en continue les objets pour afficher ceux qui sont les plus près en premier. En vérité Il trie les sphères englobantes.

Par exemple, j'ai placé 7 "murs" les uns derrière les autres.

Quand les objets sont dessinés du plus loin au plus proche : 10 fps
Quand les objets sont dessinés du plus proche au plus loin : 17 fps
Le trie permet garantir le second cas.
Cette fonctionnalité permet d'ajouter encore des objets sans perte majeure de performances



Utilisez vous même Windmill ! (dernière maj : jour 17)
Le fichier G1A est maintenant disponible en téléchargement ⇩⇩⇩

Infos démo
Cliquer pour enrouler
Touches 4,5,6,2 pour se déplacer
Replay pour tourner la vue
x et ÷ pour monter et descendre
EXE pour interagir

Actions possibles : entrer/sortir dans la maison
ouvrir/fermer la trappe

Pour fermer l'appli, il faut retirer les piles, c'est pas une blague haha


Fichier joint



Drakalex007
Hors ligne
Membre
Points: 607
Défis: 0
Message
Dernier message de la page précédente :Posté le 21/10/2016 18:36 |
entre 14 et 25 sans overclock ??
C'est bien plus que mon moteur raycasting qui tourne entre 12 et 16 fps sans overclock
Je sais pas comment c'est possible mais combiné avec de l'overclock ça peut donner destrucs vachement fluide ton moteur pour l'instant !
----------------------------------
Jouez dès maintenant à Jetpack Joyride sur votre calculatrice !
Pour les curieux
Cliquer pour enrouler
Un très bon Monopoly : Monopoly 2.0 !
Vous aimez Minecraft ? Venez voir ma chaîne ! (même si je fais plus de vidéos dessus)



Pages: Précédente | 1, 2, 3, 4, 5, 6, 7, 8, ... 19 | Suivante

Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 21/10/2016 20:17 | #
Je n'étais pas au courant pour ton moteur de ray casting
J'ai beaucoup beaucoup optimisé, que ce soit le principe même des algorithmes, la gestion des types de variable pour supprimer totalement les flottants, un maximum de valeurs pré calculées, jusqu'à regarder le code en assembleur pour voir ce qui prend ou pas du temps dans mes algos.
Depuis le début j'ai bien multiplié par 15 au moins la vitesse d'excution de moteur de rendu. Il suffit de voir la première vidéo et la dernière. J'aurai dû afficher les fps en temps réel sur les vidéos. C'est ce que je vais faire pour les prochaines vidéo

----------------------------------
Drakalex007
Hors ligne
Membre
Points: 607
Défis: 0
Message
Citer : Posté le 21/10/2016 23:52 | #
C'est vraiment génial !

Tu utilises les fixed ?
----------------------------------
Jouez dès maintenant à Jetpack Joyride sur votre calculatrice !
Pour les curieux
Cliquer pour enrouler
Un très bon Monopoly : Monopoly 2.0 !
Vous aimez Minecraft ? Venez voir ma chaîne ! (même si je fais plus de vidéos dessus)
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 23/10/2016 23:14 | #
Non, j'utilise au cas par cas des "changements d'échelle" de mes variables. Par exemple une variables qui évolue d'habitude entre 0 et 1 (donc un flottant) je la multiplie par 1024 pour qu'elle évolue entre 0 et 1024 (donc un entier). Et en jouant comme ça sur plusieurs variables je retombe sur mes pas.
Le défi étant de perdre un minimum de précision et de ne pas dépasser la valeur maximal autorisée par le type de la variable (2 milliard pour un int signé).
Le principe ne doit pas être si différents des fixed, mais je ne les utilise pas, j'ai fait mon propre système afin de l'optimiser au cas par cas
----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 24/10/2016 18:25 | #
Les fixed c'est strictement identique. En fait tu adoptes une convention pour la position du 1 (la position du point décimal, qui est fixe), par exemple 16 bits, et tu décides que le 17ème bit vaut 1, le 18ème 2, alors que le 16ème vaut 1/2, le 15ème 1/4, et ainsi de suite. Ça revient typiquement à tout multiplier par 2^16 dans mon exemple.

Après si tu veux manipuler les fixed aisément faut utiliser la même convention partout, ce qui est un peu restrictif
----------------------------------
Rise.
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 24/10/2016 20:16 | #
C'est bien ce que j'ai dis, j'utilise des fixed avec une convention au cas par cas en somme

Jour 7
Il n'y a pas grand chose de nouveau visuellement donc je sors pas de vidéo, mais maintenant que j'ai fini d'opimisé le rendu des textures, j'ai optimisé la transformation des points dans l'espace 3D. J'ai gagné 71% de rapidité depuis le jour 6 ! Entre autres, j'ai précalculé les cos et sin, les coefficients de la matrice de rotation, le tout avec des nombre entiers.
Ce qui me prend du temps en ce moment c'est la structure de mes données, comment faire quelque chose d'efficace et qui permette d'écrire les modèle 3D rapidement à la main. Donc je gère des mini structures toutes faites, des triangles, des rectangles, et peut être d'autres plus tard comme des cylindres.

De plus, j'ai ajouté une fonctionalité qui permet d'appliquer une texture des deux cotés d'un triangles. Mais un problème est apparu, quand deux textures sont trop prochent l'une de l'autre, elle on tendance à se chevaucher, c'est à dire que la texture qui est derrière est affichée par dessus celle de devant...Ici on voit la texture blanche qui passe par dessus le mur de brique (frame 2 à 7)
Ça fait une journée que je cherche le problème. Il vient evidemment du z-buffer, mais la raison du problème est assez floue
----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 24/10/2016 21:31 | #
Encore des bons gains de vitesse a priori ! Bien joué, c'est des beaux résultats en termes d'optimisation

(Désolé pour la répétition sur l'histoire des fixed, j'ai été trompé par ton « le principe ne doit pas être si différent »)
----------------------------------
Rise.
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 24/10/2016 21:52 | #
Merci, pas de soucis t'inquiète

Je viens de trouver le nom de mon mon problème. C'est un problème qui existe aussi dans les jeux professionnels. Il s'appelle le z fighting. C'est dû à la non linéarité du z-buffer, aux erreurs de precision et d'arrondies.
Une vidéo de skyrim qui montre mon problème : on voit les textures dans les montagnes qui se chevauchent
----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 24/10/2016 22:17 | #
Autant dire que c'est pas un problème trivial... ^^'
Y'a moyen d'améliorer ça en modifiant la précision de tes fixed ?
----------------------------------
Rise.
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 25/10/2016 00:02 | #
C'est ce que je suis en train de regarder.
Le problème principal c'est surtout la non linéarité du z-buffer et pas tant la precision de mes fixed. Pour donner un ordre d'idée, quand je suis proche d'un mur, si je me déplace de 1 (arbitraire juste pour l'exemple) ma valeur de z passe de 30000 à 25000. Quand je suis à mi distance de mon mur, la valeur de z passe de 8 à 7...
Et à ce moment une simple erreur d'arrondi/troncature et le 8 devient un 7 ou inversement.
D'une part si je multiplie tout par 1024 par exemple, pour les longues distances je suis bon, mais pour les courtes distances j'overflow à coup sûr. Et d'autre part les erreurs d'arrondi sont aussi multipliées, ce qui ne résoud pas grand chose. C'est pas évident.

Je suis en train de m'informer sur un moyen de contourner le problème en encadrant mon z dans un intervalle à l'aide des matrices de projection perspective, donc plus de tangeance vers l'infini pour les points proches. Je vais voir ce que ça donne.
----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 25/10/2016 00:05 | #
La solution qui semble un peu compliquée quand même ! ^^'

J'ai jamais utilisé de z-buffer, mais je comprends le problème (ton exemple est assez clair). Si le problème vient des points proches, tu ne pourrais pas user de cas particuliers dans ta détection de faces pour ne pas avoir à les gérer ? Si tu minores la distance qui te sépare de toutes les faces présentes dans le z-buffer, tu te débarrasses aussi de la divergence.
----------------------------------
Rise.
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 06/11/2016 17:57 | #
lephenixnoir a écrit :
tu ne pourrais pas user de cas particuliers dans ta détection de faces pour ne pas avoir à les gérer ?
Non ce n'est pas possible, puisque je ne "détecte pas les faces", je dessine c'est tout. Je veux dire par là que l'algorithme est stupide et se contente déssiner les pixelss de ma texture. La seule forme "d'intelligence" est de ne pas dessiner mon pixel si j'avais déjà dessiné un pixel plus proche.
Je ne peux pas ajouter de cas particuliers puisque l'algorithme ne sait pas ce qu'il dessine.

Minorer peut être une solution pour éviter l'overflow, mais ne résoud pas le problème. Je veux une solution plus propre

Sinon, peu de nouvelles en ce moment. Je sors d'une période d'exams et en ce moment je préfère jouer que créer des jeux !

Ajouté le 08/11/2016 à 20:02 :
Jour 8

J'ai réussi à repérer l'origine de mon problème après plusieurs longues séances de documentation et de débeugage.
L'utilisation des matrices de projection perspective m'a permis de remapper la coordonnée z de mes points dans l'espace caméra, c'est à dire que maintenant leur coordonnée z à une valeur logique : elle est définie à 0 quand le point est sur le near clipping plane et à 1 sur le far clipping plane. Deux plans que je définie moi même.

Ceci m'a permis de mettre au jour une relation très vicieuse entre mes triangles que je n'avais pas remarqué jusqu'à présent. Je m'explique : dans ma phase de simplification, j'ai remarqué qu'une division était inutile puisque qu'elle se simplifiait dans une multiplication un peu plus loin. Dans le même genre que (A / B) x (C x B) = A x C
Cela n'a pas posé de problème de simplifier, j'ai obtenu exactement le même rendu.
Cependant, et c'est là que c'est vicieux, c'est que, plus tard, en rajoutant mon z-buffer (qui permet de connaître la distance entre mon point et la caméra afin d'afficher uniquement le plus proche), j'ai fabriqué une relation cachée entre mes triangles. En effet ils ne sont plus dessinés independamment puisqu'ils partagent le même z-buffer.
Et comme j'ai utilisé uniquement A et pas A / B et que B varie d'un triangle à l'autre, les données que je rentrais dans mon z-buffer étaient faussent.
Mais comme B varie peu, le problème ne s'est pas montré au premier abort, mais il était bien là !

Maintenant que je comprends l'origine du problème, je vais pouvoir le résoudre. En tout cas, c'était bien tordu et ça m'a bien pris la tête.
Désolé pour ce passage assez technique, mais expliquer l'origine du problème ne peut pas se faire sans
----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 08/11/2016 20:11 | #
Ah oui c'était vicieux en effet !
Donc en fait il y avait vraiment un bug, pas juste des problèmes de calcul !
----------------------------------
Rise.
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 08/11/2016 21:00 | #
Vraiment très vicieux L'effet est léger et la cause subtile, ça m'a guidé sur une mauvaise voie.
----------------------------------
Dark storm
Hors ligne
Membre d'honneur
Points: 10670
Défis: 174
Message
Citer : Posté le 08/11/2016 21:08 | #
En soit un bug n'est jamais qu'un problème de calcul
Exception faite de ceux dus à l’électronique (hein Lephe, ça te connaît ça) x)

Ceci dit, ça fait longtemps qu'on a pas eu de petite vidéo, mais ça a l'air d'avancer
----------------------------------
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Páranÿe quetë Quendya
Nemhardy
Hors ligne
Grand maître des Traits d'Esprit
Points: 1232
Défis: 54
Message
Citer : Posté le 08/11/2016 21:26 | #
Envoie un mail à Bethesda, ils avaient peut être le même problème que toi en fin de compte.

La roadmap ressemble à quoi pour la suite du coup ?
----------------------------------
N'attendez pas qu'il n'y ait plus de miel : スススススススススススススススススススススススススス養蜂家スススススススススススススススススススススススススススススススススススス蜂家
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 08/11/2016 22:16 | #
L'ordinateur fait ce que je lui demande, il faut juste que je lui fasse faire des choses correctes
C'est vrai étant donné que visuellement, il n'a pas grand chose de neuf. Enfin si j'ai créé une nouvelle map avec des formes plus complexes que je voulais montrer mais j'avais ce fichu bug. Enfin je l'ai toujours puisque le problème n'est pas encore résolu...

Premièrement je suis en train de corriger le problème et j'ajoute aussi des fonctionnalitées pour personnaliser le rendu, la FOV notamment. Ensuite je vais ajouter les objets dynamiques (translation et rotation). Je compte faire une vidéo d'un moulin à vent avec les pales qui tournent quand ça sera prêt.
Ajouter des sprites ancrés (comme les arbres qui nous font toujours face dans les anciens jeux)


Ajouté le 09/11/2016 à 19:38 :
Jour 9


Et voilà problème réglé ! Enfin, ça m'a pris une journée complète. (j'ai bien perdu 1h sur un copier coller raté et 3h parce que j'avais pas mon café...)
Maintenant le z-buffer est ultra propre ! je maitrise vraiment tout se qui passe. Un bon point pour la stabilité et éviter l'apparition d'artéfactes visuels
----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 09/11/2016 20:17 | #
Plus rien ne t'arrête alors ! Honnêtement, je ne crois pas qu'il y ait déjà eu de travail aussi poussé jusqu'à présent sur nos chères machines

Maintenant, t'en es où au niveau perfs ? Sans vouloir spoiler un peu tout, t'as quel type de structure pour la représentation de ton espace par ailleurs ? Parce que bon, un moteur graphique ne vaut pas moitié moins si on ne peut pas implémenter un moteur physique par-dessus : et des objets animés, et...

À propos de l'interface du programme cette fois : as-tu bien pensé à utiliser des fonctions non-bloquantes comme display(world_t world, view_t view) au lieu de run_game(world_t world) ? Ça aura son importance pour les devs' qui utiliseront ton moteur

Dark storm a écrit :
Exception faite de ceux dus à l’électronique (hein Lephe, ça te connaît ça) x)

Pff, les bugs insolubles sont toujours les moins drôles x)
----------------------------------
Rise.
Cakeisalie5
Hors ligne
Membre de CreativeCalc
Points: 1663
Défis: 10
Message
Citer : Posté le 09/11/2016 20:19 | #
Pourquoi non-bloquantes ? Une fois que les mécanismes sont en place, avec éventuellement quelques callbacks, pourquoi empêcher le moteur de prendre possession du fil d'exécution ?
----------------------------------
Promotion ordinaire sur les inscriptions sur Planète Casio : en ce moment, c'est gratuit !
Besoin d'utilitaires de transfert vers et depuis la calculatrice sous GNU/Linux ?
Ninestars
Hors ligne
Membre
Points: 2121
Défis: 22
Message
Citer : Posté le 09/11/2016 20:42 | #
Merci, en effet je suis sur une bonne route là !

J'ai beaucoup perdu, j'ai tout repassé en flottant pour debug plus facilement. Dans le gif juste au dessus, je tourne à 5 fps. C'est nettement moins rapide. Là je suis en train de repasser tout en entier et d'optimiser et j'ai trouvé une astuce très très prométeuse

Voilà comment s'enregistre les différents objets de mon espace 3D
On défini les sprites, puis les textures(sprite, x, y, largeur, hauteur, largeur_sprite, hauteur_sprite) et on rentre 3 points qui forme un rectangle(x0,y0,z0, x1,y1,z1, x2,y2,z2, texture_avant, texture_arrière) (le quatrième point est calculé automatiquement et la texture arrière est implémentée mais en coulisse ) ou alors des triangles(x0,y0,z0, x1,y1,z1, x2,y2,z2, texture_avant, texture_arrière).

Au final le moteur ne va pas prendre en entrée des rectangles/triangles, mais des objets(x, y, z, rectangle_array, triangle_array ...)
Ainsi pour afficher 2 maisons il suffit d'en créer une seule liste de rectangles/triangles représentant une maison et de créer deux objets "maison" reprenant cette liste.

Désolé mais il n'y aura pas de moteur physique, ça sera à gérer au cas par cas pour les jeux. La plupart du temps une matrice/tableau pour gérer les colisions sera suffisant. En tout cas c'est pas en projet, la physique en 3D c'est hardcore


En effet, le moteur de rendu n'est pas bloquant. (enfin qu'est-ce que tu appelles bloquant ?)
Il faut d'abort créer une scène (qui comprend les coordonnées de la caméra, du viewport et quelques autres trucs) et on lance le rendu sur la scène
Scene scene1;
scene1.set(30, 10.5, 10, 0, 90, 80, 0, 0, 127, 63)
render_draw(&scene1);
Pour l'instant la map (ce qui est en screen juste au dessus) est un .h inclus dans le render



----------------------------------
Lephenixnoir
Hors ligne
Administrateur
Points: 13069
Défis: 136
Message
Citer : Posté le 09/11/2016 21:11 | #
Cake :
On peut autoriser le moteur à piquer le flux (je me suis peut-être mal exprimé), mais il faut une interface non-bloquante sinon les possibilités sont restreintes

Ninestars :
Non-bloquant, c'est "le moteur ne prend pas le contrôle du flux d'exécution du programme".

Oh, donc basiquement tu as un tableau d'objets. Je sais pas trop ce que ça donnera avec des gros objets, mais c'est déjà pas mal. Ça a des inconvénients aussi, encore.
----------------------------------
Rise.

Pages: Précédente | 1, 2, 3, 4, 5, 6, 7, 8, ... 19 | Suivante

Index du Forum > Projets de programmation > Windmill : moteur graphique 3D

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2018 | Il y a 22 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire indépendant, géré bénévolement et n'est donc pas affilié à Casio | Toute reproduction de Planète Casio, même partielle, est interdite
Les fichiers, programmes et autres publications présents sur Planète Casio restent la propriété de leurs auteurs respectifs et peuvent être soumis à des licences ou des copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd