Tout les jeux devrais avoir l'interpolation de base, de plus puisque le framerate n'est jamais égale d'un système à l'autre, il est mieux de basé le mouvement par rapport temps. Ce que l'on voie souvent c'est l'interpolation linéaire, mais pour faire de beau jeux, rien de mieux que du easing, mon algo permet d'en faire peu-importe la position de départ et d'arrivé de l'objet.
Ça ressemble un peu à ce que l'on peu trouvé ici :
Donc le easing est de rapide à lent, j'ai aussi intégrer le easing lent à rapide, pour son utilisation tu peux regardé le premier post de la page précédente.
- Edité par Maeiky 8 février 2015 à 17:56:14
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
je me suis remis recemment au C++, et je dois te dire juste bravo pour tout le boulot que tu as fait là !!
par contre, je suis aussi sur un projet avec des amis, en C++, et on part sur la creation d'une architecture libre pour (MMO)RPG, donc pas mal de trucs deja fait de base pour simplifier la vie au prog'.
et on aimerait intégrer Qt + opengl dans le "projet", dans des sous class bien sûr qui géreront pas mal de choses de bases.
mais en voyant ton projet, je me suis dit : "Opengl, niveau perf c'est pas top top à ce que je vois, pourquoi pas changer de moteur (on a pas commencer à coder cette partie en +) ?" et j'ai pensé à ton moteur.
un petit featuring, ca te tenterais ?
ps : bien sûr, apres tout ca, on se servira de l'architecture pour faire un mini (mmo)rpg pour montrer les possibiltiés données par l'architecture.
En ce moment je travaille sur la refonte de plusieurs choses pour être plus propre. Je refais complètement la partie String qui va travailler directement en UTF8, ça va augmenté la portabilité en plus de simplifier l'utilisiation, je passe de 3 types différent 8,16,32 bits à un seul, UTF8.
Ensuite je vais m'attaquer aux pointeur intelligents, ça va minimisé les erreurs de fuite de mémoire possible et je vais faire en sorte que ça compile sur ArmCC en créant une version des shared_ptr simplifié.
Utilisation des namspaces, statique const, etc.
Il faut faire attention pour la partie OpenGL, j'ai dans l'idée de garder la portabilité au maximum, ça doit pouvoir fonctionner sur mobile, donc OpenGL ES2 qui limite pas mal de fonctions. Plusieurs techniques sont tout de même possible, le but est de faire le plus de batching pour améliorer les performances.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Désolé pour l'attente, je travaille actuellement sur une partie délicate du moteur qui n’est pas la plus motivante. Mais même si ça n’en a pas l’air, il y a des progrès :
- Les strings UTF8 sont maintenant fonctionnelle, c’est ainsi beaucoup plus simple à utiliser, il y a un seul type au lieu d’avoir 3 versions de strings, ce qui devenait ingérable (8bit / 16bit/ 32bit). De plus les compilateurs supporte mal les String Literal qui sont parfois 16bit et parfois 32bit et augment les incompatibilités possibles. Le tout est donc parfaitement Unicode et l’on peut ainsi afficher tous les caractères possibles.
- Elles possèdent une tête de lecture directement dans le pointeur, ce qui simplifie grandement la manipulation et évite toute gestion de retour/passage en paramètre d'index (tête de lecture), les recherches de caractères et textes au sein d’une string survivent à la portée du scope.
-Elles suivent maintenant le principe du Copy-On-Write (COW) qui est parfaitement adapté pour les strings, combinés à mon propre système de comptage par référence. Pour ces objets de base, il est inutile d’utilisé un comptage de type Shared_ptr qui serait très lourd et inadapté, car lors des additions de chaines, on ne veut pas modifier la chaine source quelque part ailleurs, on en veut une copie pour ne pas tout altérer n'importe où.
De plus le COW permet de travailler de façon optimale avec les strings Read-Only car la source n’est jamais modifier. Aussi, pour les String Litteral, j'arrive à obtenir leur size à la compilation, ce qui évite de perde des performances à compter chaque caractère pour chaque nouvelle string. Elles ne sont donc pas récréer sur le tas (heap) ce qui accélère grandement le tout.
-Intégration des Shared_ptr/Weak_ptr custom à GZE. Et oui, je suis parvenue à extraire ces 2 pointeurs ultra complexe de Boost, ce qui est un exploit en soit (quelques millions de templates à extraire :p). Je les aie simplifiés au maximum et optimisés, surtout dans le sens que j’ai enlevé des opérations inutiles, comme le comptage atomique et les spin lock, pour le multi- thread, qui sont totalement inutile lorsque l’on programme par tâche. Ce sont donc des pointeurs sous un différend nom, j’ai enlevé toutes dépendances, c’est très léger et rapides à compiler. Donc ces pointeurs servent aux objets complexe qui peuvent avoir des références cycliques, d’où l’obligation d’avoir le Weak_ptr. Ces pointeurs intelligents sont maintenant essentiel pour programmer proprement et évité tout problème de mémoire non-libéré ou corrompu.
-Intégration d’un système pour détecter toutes fuites de mémoire. En mode debug, tout allocation qui n’a pas été libérer à la fin d’exécution du programme sont listés. Même si les Shared_ptr sauve la mise, on n’est pas à l’abri de fuites. Ce qui permet de faire des programmes propres, de qualité et détecter de graves erreurs.
-Optimisation du temps de compilation au maximum, en utilisant le plus possible les déclarations anticipées (forward declaration), ça réduit le nombre de fichiers à compiler lors d’une modification, mais aussi la compilation de l’ensemble du projet.
- Possibilité de faire un fichier cpp contenant d’autre fichier cpp, donc un .cpp peut contenir tous les autres. À quoi ça peut servir? Eh bien, la bibliothèque est maintenant aussi simple à linker qu’une DLL, car il n’y a qu’un seul fichier à compiler, le tout en gardant la propriété universelle d’exportation sur différente plateforme et l’accès au code source en tout temps. De plus, le temps de compilation en est accéléré, car les headers ne sont lue qu’une fois.
C’est en voie de devenir la bibliothèque la plus efficace ever , le projet en entier prend maintenant que 2 secondes à compiler :
-Utilisation des namespaces, la librairie est maintenant écrite de façon propre et pratique, utilisation de variable static const au lieu de #define, qui est utilisable dans les namespace et plus strict.
-Plus de tearing en mode Windowed avec OpenGL, tout en gardant un niveau d’utilisations CPU/GPU très bas, normalement pour corriger ce problème le monde génère des centaines de frame inutilement. Ma philosophie est tout le contraire, sauf que le tearing est ma bête noir. Ma première idée était d’utiliser glFinish pour synchroniser le CPU/GPU, sauf que j’ai découvert que cette fonction est le mal absolue, car parfois OpenGL se perd et freeze complètement le CPU de façon complètement aléatoire.
Ceux qui ont conçue OpenGL ont créé le VSync que pour le mode plein écran : « In case of applications in window mode we emulate vsync using sleep. » Il est donc pratiquement impossible d’avoir quelques chose de jolie pour des applications fenêtré, mais j’y suis enfin parvenue et non sans difficulté en me synchronisant sur une autre fenêtre plein écran qui est invisible
Je n'ai pas encore updater le Git, mais aussitôt que j'aurai fini les parties délicates, bas niveau, qui joue sur la façon d'utiliser le moteur, je vais mettre le tout à jour
- Edité par Maeiky 4 avril 2015 à 5:09:50
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
De plus les compilateurs supporte mal les String Literal qui sont parfois 16bit et parfois 32bit.
Les wide string litteral dans ce cas*
Maeiky a écrit:
Elles possèdent une tête de lecture directement dans le pointeur, ce qui simplifie grandement la manipulation et évite toute gestion de retour/passage en paramètre d'index (tête de lecture), les recherches de caractères et textes au sein d’une string survivent à la portée du scope.
Tu veux dire que ton indice part directement du tableau interne ? Parce que si tu parles de pointeurs dans l'interface, ils seront invalidés lors du changement de capacité.
Maeiky a écrit:
Pour ces objets de base, il est inutile d’utilisé un comptage de type Shared_ptr qui serait très lourd et inadapté, car lors des additions de chaines, on ne veut pas modifier la chaine source quelque part ailleurs, on en veut une copie pour ne pas tout altérer n'importe où.
Et en quoi le shared_ptr force la modification de la chaîne source ?
Maeiky a écrit:
De plus le COW permet de travailler de façon optimale avec les strings Read-Only car la source n’est jamais modifier. Aussi, pour les String Litteral, j'arrive à obtenir leur size à la compilation, ce qui évite de perde des performances à compter chaque caractère pour chaque nouvelle string.
Oserais-je dire merci Lynix ? Je dis ça parce que je sais que tu suis Nazara et que j'ai implémenté un template qui récupère la taille d'un tableau de chaîne de caractère il y a une semaine ou deux.
Cependant, comme le disent les gars de Qt, c'est une optimisation déjà effectuée par les compilateurs (un strlen("blah") sera calculé à la compilation sur les compilos modernes) si inlining. Attention que je pense que c'est quand même utile ! Mais ça a certainement moins d'impact du coup que ce que tu imagines.
Maeiky a écrit:
-Intégration des Shared_ptr/Weak_ptr custom à GZE. Et oui, je suis parvenue à extraire ces 2 pointeurs ultra complexe de Boost, ce qui est un exploit en soit (quelques millions de templates à extraire :p). Je les aie simplifiés au maximum et optimisés, surtout dans le sens que j’ai enlevé des opérations inutiles, comme le comptage atomique et les spin lock, pour le multi- thread, qui sont totalement inutile lorsque l’on programme par tâche. Ce sont donc des pointeurs sous un différend nom, j’ai enlevé toutes dépendances, c’est très léger et rapides à compiler. Donc ces pointeurs servent aux objets complexe qui peuvent avoir des références cycliques, d’où l’obligation d’avoir le Weak_ptr. Ces pointeurs intelligents sont maintenant essentiel pour programmer proprement et évité tout problème de mémoire non-libéré ou corrompu.
J'espère que tu respectes la licence de Boost dans ce cas, mais pourquoi ne pas avoir recréé une classe (quitte à réinventer la roue/dupliquer le code) ? (Les shared_ptr/weak_ptr n'étant pas des classes compliquées dans le principe, et je t'avais refilé une implémentation libre il y a un mois).
Maeiky a écrit:
-Intégration d’un système pour détecter toutes fuites de mémoire. En mode debug, tout allocation qui n’a pas été libérer à la fin d’exécution du programme sont listés. Même si les Shared_ptr sauve la mise, on n’est pas à l’abri de fuites. Ce qui permet de faire des programmes propres, de qualité et détecter de graves erreurs.
Merci Lynix aussi ?
Maeiky a écrit:
Possibilité de faire un fichier cpp contenant d’autre fichier cpp, donc un .cpp peut contenir tous les autres. À quoi ça peut servir? Eh bien, la bibliothèque est maintenant aussi simple à linker qu’une DLL, car il n’y a qu’un seul fichier à compiler, le tout en gardant la propriété universelle d’exportation sur différente plateforme et l’accès au code source en tout temps. De plus, le temps de compilation en est accéléré, car les headers ne sont lue qu’une fois.
Ton projet mets déjà quinze secondes à effectuer une recompilation COMPLÈTE, pourquoi es-tu aussi à cheval sur le temps de compilation qui est ridiculement court ? Nazara mets plus de deux minutes à être recompilé complètement, mais je n'effectue quasiment jamais de recompilation complète, je change deux ou trois fichiers, et je dois en recompiler le double, et ça dure trois secondes.
Ton idée de regrouper tous les .cpp en un peut sembler bonne quand tu n'as qu'un petit projet, mais en réalité tu ne fais que forcer une recompilation complète à chaque changement, ce qui va prendre plus de temps une fois que ton projet sera plus imposant.
Et ne pas avoir de bibliothèque dynamique, je maintiens que c'est une mauvaise idée.
Maeiky a écrit:
C’est en voie de devenir la bibliothèque la plus efficace ever , le projet en entier prend maintenant que 2 secondes à compiler
Le temps de compilation est un paramètre extrêmement peu influent pour une bibliothèque (temps de compilation), regarde Qt, UnrealEngine, Linux.. Leur temps de compilation est énorme (plusieurs heures minimum), mais une fois que c'est compilé, c'est compilé.
Quelqu'un qui utilise ton moteur n'aura pas à le recompiler si tu distribues les binaires, ou au pire, il n'aura qu'à le compiler une fois. Le temps de compilation n'est un problème que pour les développeurs du moteur.
Maeiky a écrit:
Ceux qui ont conçue OpenGL ont créé le VSync que pour le mode plein écran :
« In case of applications in window mode we emulate vsync using sleep. » Il est donc pratiquement impossible d’avoir quelques chose de jolie pour des applications fenêtré, mais j’y suis enfin parvenue et non sans difficulté en me synchronisant sur une autre fenêtre plein écran qui est invisible
Euh ouais, OpenGL n'est qu'une spécification sans implémentation, le fait que Sleep soit utilisé n'est qu'un détail d'implémentation, pire, d'une seule implémentation (celle d'Intel en l'occurence).
C'est un détail donc, on s'en fiche pas mal. Je n'ai jamais eu de souci une fois que la V-Sync était activé.
Tu veux dire que ton indice part directement du tableau interne ? Parce que si tu parles de pointeurs dans l'interface, ils seront invalidés lors du changement de capacité.
Dans l'interface, au même niveau que le "String Holder". Il n'y a pas de changement de capacité dans le COW, que de nouvelles strings, dans ce cas, sa position est copier.
Lynix a écrit:
Et en quoi le shared_ptr force la modification de la chaîne source ?
Le principe du Shared_ptr est très différent du COW, au final il faut gérer manuellement la mémoire pour rendre ça efficace. Par exemple s' il n'y a qu'une instance de la string, on peut la modifier directement, sinon on en fait une copie. Peut-être que ce serait quand même possible avec un Shared_ptr, mais les strings sont déjà un conteneur qui permet une gestion automatique de sa destruction. Avoir un autre conteneur dedans serait inutile.
Lynix a écrit:
Oserais-je dire merci Lynix ? Je dis ça parce que je sais que tu suis Nazara et que j'ai implémenté un template qui récupère la taille d'un tableau de chaîne de caractère il y a une semaine ou deux.
Cependant, comme le disent les gars de Qt, c'est une optimisation déjà effectuée par les compilateurs (un strlen("blah") sera calculé à la compilation sur les compilos modernes) si inlining. Attention que je pense que c'est quand même utile ! Mais ça a certainement moins d'impact du coup que ce que tu imagines.
Non pas pour ça, en fais je te remercie, car la plupart des modification que je présente sont grâce à nos discutions. Mais je suis ton projet de loin, entre autre pour ne pas être tenté de copier du code. J'ai survoler le code sans plus, mais j'avais justement remarqué que tu utilisais strlen. Il est impossible de savoir la longueur des strings à partir d'un pointeur sans compter tout les caractères. As tu au moins testé l'optimisation dont tu parle? Car en réalité le compilateur va changer la ligne de code strlen("blah") par sizeof ("blah"), donc pourquoi ne pas utilisé sizeof directement? C'est une optimisation aveugle, car lorsque ça devient un pointeur tu oblige le compte, croire que le compilateur va réussi à l'optimiser quand même, c'est un coup de dés.
Lynix a écrit:
J'espère que tu respectes la licence de Boost dans ce cas, mais pourquoi ne pas avoir recréé une classe (quitte à réinventer la roue/dupliquer le code) ? (Les shared_ptr/weak_ptr n'étant pas des classes compliquées dans le principe, et je t'avais refilé une implémentation libre il y a un mois).
Oui, la licence de Boost est très permissive, je respect toujours les licences.
Lynix a écrit:
Maeiky a écrit:
-Intégration d’un système pour détecter toutes fuites de mémoire. En mode debug, tout allocation qui n’a pas été libérer à la fin d’exécution du programme sont listés. Même si les Shared_ptr sauve la mise, on n’est pas à l’abri de fuites. Ce qui permet de faire des programmes propres, de qualité et détecter de graves erreurs.
Merci Lynix aussi ?
Tu as implémenté une détection de fuite de mémoire? J'ai utilisé stb_leakcheck, simple et pratique.
Lynix a écrit:
Ton idée de regrouper tous les .cpp en un peut sembler bonne quand tu n'as qu'un petit projet, mais en réalité tu ne fais que forcer une recompilation complète à chaque changement, ce qui va prendre plus de temps une fois que ton projet sera plus imposant.
Non, pour ceux qui développe GZE (moi :P) il a un projet Code::Blocks, qui inclue les fichier cpp séparer. Pour ceux qui veulent se simplifier la vie, pour inclure la lib, peuvent simplement compiler un seul fichier qui inclue les autres, ils n’orront pas vraiment de modification à faire dans la lib, mais ils le peuvent tout de même.
Lynix a écrit:
Et ne pas avoir de bibliothèque dynamique, je maintiens que c'est une mauvaise idée.
Je n'ai pas dis que ma lib ne pourra pas s'exporter en DLL. Je suis tout de même rétrécissant à sortir chaque fois une version différente pour chacune des plateformes, x86 x64, release/debug, donc ça va plus être à l'utilisateur de la générer. Mais je trouve cela un peu inutile, car je crois que c'est un peu de la faute de l'IDE si l'option recompiler tout, recompile par erreur ma lib, ce qui va ajouter quelques secondes au tout.
Lynix a écrit:
Ton projet mets déjà quinze secondes à effectuer une recompilation COMPLÈTE, pourquoi es-tu aussi à cheval sur le temps de compilation qui est ridiculement court ?
Pour la raison précédente, recompiler tout va ajouter la compilation de GZE pour certain IDE. Aussi pour ceux qui développe GZE et surtout pour mon autre projet en parallèle, qui est de réaliser un langage de programmation, donc les fichiers sont générer de la même façon, il doivent compiler rapidement.
Lynix a écrit:
Quelqu'un qui utilise ton moteur n'aura pas à le recompiler si tu distribues les binaires, ou au pire, il n'aura qu'à le compiler une fois. Le temps de compilation n'est un problème que pour les développeurs du moteur.
Pour certain ça ne cause pas de problème, mais du code pure c'est exportable sur n'importe quel plateforme, c'est universelle, ça compile selon ses besoins, avec seulement le code nécessaire et plusieurs optimisation sont possible grâce à cette étape, avec macro ou autre.
Lynix a écrit:
Euh ouais, OpenGL n'est qu'une spécification sans implémentation, le fait que Sleep soit utilisé n'est qu'un détail d'implémentation, pire, d'une seule implémentation (celle d'Intel en l'occurence).
C'est un détail donc, on s'en fiche pas mal. Je n'ai jamais eu de souci une fois que la V-Sync était activé.
Moi je m'en moque pas, ça parait d'avantage pour la GUI et la 2d, avec des mouvements uniformes, par exemple une image qui tourne, c'est horrible sans VSync.
- Edité par Maeiky 6 avril 2015 à 4:35:54
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Dans l'interface, au même niveau que le "String Holder". Il n'y a pas de changement de capacité dans le COW, que de nouvelles strings, dans ce cas, sa position est copier.
Ah si, une String COW peut changer de capacité, le COW n'est qu'un "détail d'implémentation". D'ailleurs std::string (qui dispose d'un système de capacité) possédait (et possède même toujours) une implémentation usant du COW sous GCC.
D'ailleurs, une String COW possède un cas supplémentaire d'invalidation: la modification sans changement de capacité d'une String partagée.
(Par invalidation j'entends: allocation d'un nouveau buffer).
Maeiky a écrit:
Le principe du Shared_ptr est très différent du COW, au final il faut gérer manuellement la mémoire pour rendre ça efficace. Par exemple s' il n'y a qu'une instance de la string, on peut la modifier directement, sinon on en fait une copie. Peut-être que ce serait quand même possible avec un Shared_ptr, mais les strings sont déjà un conteneur qui permet une gestion automatique de sa destruction. Avoir un autre conteneur dedans serait inutile.
En fait le shared_ptr simplifie la tâche, l'idée serait de l'utiliser pour contenir la structure "Shared_String". Quand on veut modifier un String, on appelle la méthode "unique" de shared_ptr pour s'assurer qu'on est le seul propriétaire, sinon on copie.
Mais je ne te parlais pas de shared_ptr sans l'interface, c'est un détail d'implémentation.
Maeiky a écrit:
Il est impossible de savoir la longueur des strings à partir d'un pointeur sans compter tout les caractères. As tu au moins testé l'optimisation dont tu parle? Car en réalité le compilateur va changer la ligne de code strlen("blah") par sizeof ("blah"), donc pourquoi ne pas utilisé sizeof directement? C'est une optimisation aveugle, car lorsque ça devient un pointeur tu oblige le compte, croire que le compilateur va réussi à l'optimiser quand même, c'est un coup de dés.
L'optimisation dont je te parle existe bien, ce qu'il va se passer c'est que lors de l'inlining le compilateur va suivre les pointeurs de chaîne en question et remplacer les appels à strlen par la valeur connue.
Clang et GCC effectuent cette optimisation, GCC de façon plus limitée cependant (il ne peut le faire que depuis une même unité de compilation).
Mais ça veut quand même dire que même en passant par un pointeur dans ton interface, un strlen peut être optimisé par le compilateur, et ça c'est pas mal.
Maeiky a écrit:
Tu as implémenté une détection de fuite de mémoire? J'ai utilisé stb_leakcheck, simple et pratique.
Oui j'en ai une, qui s'active en debug (d'où ma méprise), elle intercepte toutes les allocations dynamiques du C++ (y compris celles de la STL) pour détecter les leaks.
Elle fonctionne selon le même principe (suivre chaque bloc d'allocation et y ajouter des informations).
Maeiky a écrit:
Non, pour ceux qui développe GZE (moi :P) il a un projet Code::Blocks, qui inclue les fichier cpp séparer. Pour ceux qui veulent se simplifier la vie, pour inclure la lib, peuvent simplement compiler un seul fichier qui inclue les autres, ils n’orront pas vraiment de modification à faire dans la lib, mais ils le peuvent tout de même.
Je n'ai pas dis que ma lib ne pourra pas s'exporter en DLL. Je suis tout de même rétrécissant à sortir chaque fois une version différente pour chacune des plateformes, x86 x64, release/debug, donc ça va plus être à l'utilisateur de la générer. Mais je trouve cela un peu inutile, car je crois que c'est un peu de la faute de l'IDE si l'option recompiler tout, recompile par erreur ma lib, ce qui va ajouter quelques secondes au tout.
Je comprends l'idée de laisser l'utilisateur recompiler ta bibliothèque, mais pourquoi ne passes-tu pas alors par Premake ou *profonde inspiration* CMake ? De cette façon l'utilisateur peut compiler sa propre bibliothèque dynamique et l'utiliser dans ses projets.
Ce qu'il faut bien comprendre c'est que ta solution (intégrer de base la lib dans le projet de l'utilisateur) est une solution qui va rebuter je pense les utilisateurs avancés (et ne faciliter la vie aux débutants qui devront de toute façon apprendre à linker des bibliothèque plus tard).
Maeiky a écrit:
Pour la raison précédente, recompiler tout va ajouter la compilation de GZE pour certain IDE. Aussi pour ceux qui développe GZE et surtout pour mon autre projet en parallèle, qui est de réaliser un langage de programmation, donc les fichiers sont générer de la même façon, il doivent compiler rapidement.
Quels IDE recompilent les fichiers déjà compilés ? Des IDE à ne pas utiliser, voilà tout.
Non sincèrement, des bibliothèques prenant des plombes à compiler, c'est pas ce qui est le moins utilisé, bien au contraire.
Maeiky a écrit:
Moi je m'en moque pas, ça parait d'avantage pour la GUI et la 2d, avec des mouvements uniformes, par exemple une image qui tourne, c'est horrible sans VSync.
Attention que je n'ai pas dit qu'on se moquait de ne pas avoir de V-Sync, je pense juste qu'on se moque de la façon dont le driver l'implémente, tant qu'il fait le travail qu'on lui demande.
J'ai énormément de respect pour le travaille de Lynix, mais on est déjà bien avancé dans nos moteurs chacun de nos coté et on suis des voies bien différentes.
D'un coté Lynix présente un moteur 3D avec des techniques très avancé, avec un ECS et éventuellement faire compétition à UDK
Moi je présente une base légerte et le plus portable possible, spécialisé pour faire des application GUI, des jeux 2D, le tout est pensé éventuellement faire de la 3D. Je commence donc par le début, faire un moteur solide pour la 2D, ensuite lorsque ça aura fait ses preuves, ça pourra évoluer tranquillement vers des jeux 3D.
Je préfère avoir quelque chose de spécialement conçu pour le moteur pour que ce sois bien intégré, donc quelque chose qui n'est pas déjà créé. De plus ça ne dois pas affecté la portabilité, entre autre je suis déjà très limité pour pouvoir utilisé OpenGL ES2.
Je ne dirais pas non à ce que Lynix rejoigne ma team, mais il n’abonnera pas son projet et si je n'aurais pas de projet en cours j'aiderai bien Lynix.
Je pense que l'on a simplement 2 projets originaux, chacun ayant leur forces.
@Lynix,
Ce que tu dis pour les strings est vrai, le changement de capacité n'a lieu que lorsque l'on a une instance unique. Il y a plusieurs façon de le faire, je l'ai conçue à ma manière, de la façon la plus optimal possible.
Un utilisateur expérimenté n'aura pas vraiment plus de difficulté à compiler, mais est-ce le réel marché que je vise? Je présente une base qui contient tout pour faire des applications/jeux facilement. Je présente le tout d'une façon différente avec un vision différente, je travaille sur des outils pour rendre le tout encore plus facile, entre autre concevoir un IDE qui vas exporter vers toute les plateformes directement. En gros c'est un tout en un, parfait pour les débutant et ceux qui n'ont pas envie d’utiliser des outils lourd et complexe à utiliser.
- Edité par Maeiky 7 avril 2015 à 4:55:54
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Merci, j'avoue que je n'aurais sans doute pas tenté le coup si j'aurais su toute l’ampleur du travail dès le départ, mais je ne vais pas laisser tomber après 6 ans
Petite news
Suite à un problème avec OpenGL, une erreur que je n’arrivais pas à cibler, j'ai décider de me lancer dans une gestion d'erreurs en béton.
Si une fonction OpenGL échoue, on peut la détecté à l'aide de la fonction glGetError. Le problème c'est que ça n'indique pas quel fonction à raté, à moins de tester cette fonction après chacun des appels OpenGL. En gros, c'est ce que j'ai fais, mais de façon totalement invisible.
Donc mes appels de OGL porte une légère différence dans le nom (GL_XXX au lieu de glXXX), ce qui me permet d'appeler une fonction qui combine la fonction OGL avec un test de glGetError
De plus je voulais avoir le plus d'infos possibles, grâce aux macros, je peux y récupérer le fichier et la ligne de la fonction qui échoue.
Ce n'est pas tout, je suis aller encore plus loin en indiquant la valeur de chacun des paramètres.
Tout ça est activé en mode debug puis enlevé en mode release encore un fois de façon invisible.
De plus j'ai améliorer le système de chargement de fonction OGL qui charge tout à la volé, donc on aura même plus besoin de linker OGL
Pour faire tout ça, il ma fallu avoir une solide définition de chacune des fonctions, j'en ai pour environ 2000 lignes de code juste pour ça Un petit exemple pour une fonction :
Plutôt impressionant, et preuve de ta volonté forte, j'avais déjà pensé faire un système comme celui-là (mais avec une génération automatique de code, espèce de fou), et puis cette extension est arrivée (et a été intégrée dans le noyau):
OpenGL Debug Output (GL_ARB_debug_output). (Certes elle n'est disponible que pour les drivers récents, mais comme c'est pour le développement on s'en fiche).
Les messages produits sont de ce style:
OpenGL debug message (ID: 0x3F3): Sent by context: 0x029ccab4 -Source: OpenGL API -Type: Error -Severity: High Message: glDeleteShader failed because (depending on the operation) a referenced binding point is empty; a referenced name is not the name of an object; or the given name is otherwise not valid to this operation (GL_INVALID_VALUE)
ou encore:
25/04/2015 - 08:36:48: OpenGL debug message (ID: 0x8DC): Sent by context: 0x08bcf10c -Source: OpenGL API -Type: Error -Severity: High Message: glProgramUniform1i parameter has specified an invalid value '1488398576': not the location of an active uniform in the default uniform block (GL_INVALID_OPERATION)
Et l'impact est minimal (gestion directe par le driver, overhead uniquement en cas d'erreur).
Avec la possibilité de mettre un break avec le debuggeur sur le callback OpenGL et de remonter la callstack (en forçant une synchronisation CPU/GPU permanente, mais encore une fois ce n'est que pour le développement).
Edit: D'ailleurs tu viens de me faire découvrir une erreur dans mon moteur, huehue.
Pour vrai , j'imagine que ça pourra être une surcouche en cas d'erreur. Merci pour l'info Au moins, j'ai de l'information de l'endroit de l'erreur sans passer par le débogueur.
Mais en effet c'est générer automatiquement, rentrer tout ça à la mains relève de la folie , donc je peux créer le code que je veux avec les fonctions OGL, je peux donc en faire toute sorte d'usage.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Oui, pardon pour l'attente, j'avais énormément de choses à faire. C'est du OGL 3.3 oui.
J'ai pratiquement tout réécris GZE, surtout pour la gestion de la mémoire, les namespace, les arrays et listes sous forme de template et les strings en UTF8.
Bonne nouvelle ! Je rends aujourd'hui publique, le langage sur lequel je travaille depuis si longtemps et qui devrait enfin donner une réponse au curieux C'est le CWave, voir ici :
J'ai changé complètement mon système de rotation, j'utilise maintenant entièrement les quaternions, qui sont indispensable si on veut en combiner plusieurs, sans quoi, on se retrouve avec des problème de mauvaise interpolation et gimbal lock.
Voici ici mon meilleurs exemple, qui était impossible à réaliser auparavant :
Voici le code relatif en CWave :
public class DemoArrow extends Clip {
public var oImg : Img;
public function DemoArrow( _oParent : Root ):void {
Clip(_oParent, 0.0, 0.0);
oImg = new Img(this, 650.0, 0.0, E"Arrow.png", false, 220, 82);
//Container setup
TnX(oItf.nHalfFrameWidth); //Center to screen X
TnY(oItf.nHalfFrameHeight); //Center to screen Y
TnZ(600); //Put the container a little further
//Arrow setup
oImg.MnYaw( Math.nPI/2.0); //Turn Arrow at 90deg
}
override public function fUpdateParentToChild():void {
MnYaw(0.025); //Container rotate, Arrow inside then follow a circular path on Z axis
MnRoll(0.005); //Container rotate, Arrow inside then follow a circular path on X axis
oImg.MnRoll(0.255); //Arrow rotate itself, Rolling on is Yaw rotation (90 deg in setup)
}
}
J'ai aussi commencé le système de lumière qui est de type phong en combinaison avec le type goraud. Je précise que j’utilise une interpolation bilinéaire des normales comme pour le goraud, ce qui ce résume à l'interpolation de gauche :
J'ai commencé mon système de batching qui me permet d'afficher plusieurs dizaines de millier de sprites (60fps). J'ai aussi commencé le texte.
Je vous reviens prochainement la dessus.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
J'ai décidé d’utiliser le superbe logiciel Tiled pour GZE. C'est à dire un loader .Tmx et tout le système de tiled qui s'en suit comme base à GZE.
Ça me permet en même temps de testé mon système de batching.
On peut donc créer des map facilement pour tout type de jeux, ce qui nous donne une sorte d'interface graphique.
Voici ma première map :
Ce que ça donne dans GZE :
Pour en arriver là, il a fallu d’abord me faire un loader XML, car le TMX sont sous cette forme. Voici à quoi ressemble le code CWave pour charger un XML :
oXml = new Xml("MyFirstXml.xml");
if(oXml.fLoad()){
oCurrNode = oXml.fFirst();
if(oCurrNode.hType == XmlNode.eType.Element){
var _oElement : XmlElement = oCurrNode;
Debug.fTrace1("XML Version : " + _oElement.fAttribute("version"));
}
}
Bon ce n'est pas sans problèmes, j'ai un souci lorsque je veux redimensionner un ensemble de tiles ou en y appliquant de la perspective :
Ça peut sembler mineur, mais on peut y voir le quadrillage et ce n'est pas parce qu'ils sont mal positionné.
Le problème est très complexe, en fait c'est car chaque séquences de tiles peu être placé dans n'importe quel ordre et ils perdent ainsi l'information de l'interpolation du pixel voisin en bordure.
Voici un petit test vite fait, pour illustrer :
J'ai modifier mon tileset :
Voici le résultat :
Ça fonctionne, mais le problème c'est que l'ordre peut changer, donc les voisin ne sont jamais les mêmes.
J'ai pensé à diverses solutions, je crois que je vais me tourner vers le fragment shader et faire l'interpolation moi même, ce qui sera très flexible.
À bientôt
- Edité par Maeiky 1 septembre 2015 à 15:07:44
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
pour moi c'est plus un problème dans ton moteur, quand tu récupères le tileset pour ensuite l'afficher
car dans ton 2eme essai, tu as enlevé la "séparation" entre 2 tiles, et ca a marché, ce qui signifie qu'il faudrait peut etre revoir comment tu t'y prends pour extraire chaque tile du tileset, de manière à ne pas prendre en compte ces bordures
pour moi c'est plus un problème dans ton moteur, quand tu récupères le tileset pour ensuite l'afficher
car dans ton 2eme essai, tu as enlevé la "séparation" entre 2 tiles, et ca a marché, ce qui signifie qu'il faudrait peut etre revoir comment tu t'y prends pour extraire chaque tile du tileset, de manière à ne pas prendre en compte ces bordures
Si j'ai bien compris, c'est exactement ce qu'il a dit... C'est comme si son array de vertices avaient les bonnes coordonnées de textures, mais, pour déterminer les couleurs aux bords d'une tuile, il interpole le pixel juste au dessus dans la texture qui, lui, est noir...
L'être humain, contrairement aux geeks qui ne sont de toute façon pas des êtres humains, est un animal social taillé pour vivre en "meute".
Ben sinon c'est ptet simplement le choix d'une interpolation linéaire qui est mauvais, alors qu'en 2D sur des sprite sheet tout le monde fait du pixel-perfect avec une "interpolation" en "nearest" c'est-à-dire aucune interpolation.
C'était plus complexe que je le croyais, car il me fallait également résoudre les coins
L'affichage est bien avec des vertex array, l'envoie des données se font en un appel, j'utilise les attribDivisor avec offset, pour réduire l'overhead, le tout par instances.
Le nombre de drawcall est calculé automatiquement (généralement 1 seul drawcall), dépendamment du nombre de shaders , buffer ou atlas.
Pour ce qui est du choix de l'interpolation, je vais répondre avec une image, qui vaut mille mots :
Une solution aurait pu être d'utiliser un buffer puis transformer celui-ci, mais ça consomme beaucoup de mémoire et il faut parcourir les pixels deux fois, ce qui est très lourd. De plus ça brise le batching.
Pour ce qui est d'un effet délibéré pixelisé en GL_NEAREST, c'est plutôt moche lors de mouvements, à moins de vouloir un effet full retro, mais personnellement je trouve que ce serait encore mieux de faire un style rétro avec des techniques d'aujourd'hui.
Pour les performances de cette méthode, j'ai à peine 1% de plus d'utilisation GPU pour du 1024*768 60fps (~10%).
Ce qui offre un feature unique au moteur
Ma prochaine étape sera d’intégrer la réflexion et rotation de tiles
Edit :
Vous pouvez tester l'exécutable qui montre la différence entre le filtre bilinaire ci-dessus et un filtrage "nearest" (aucun filtre):
A priori quelqu'un qui utilise une tilemap va vouloir le rendu "pixelisé" de GL_NEAREST. Quand on travaille en tiles c'est qu'on est en 2D, en pixel-perfect, on ne veut surtout pas d'interpolation ou même de coordonnées non-entières qui nuisent activement à la qualité du rendu. La feature est unique à ton moteur pour une bonne raison.
Ta feature est peut-être utile à quelqu'un qui développe un jeu 3D avec des tilemaps (???) mais pour le cas général, j'espère que tu as le nearest par défaut...
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
Mes articles | Nazara Engine | Discord NaN | Ma chaîne Twitch (programmation)
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
GZE, un moteur multiplateforme, adapté pour de la 2D, 3D et création de logiciels.
"J'aimerai faire un jeu, mais pas un gros jeu hein. Un petit truc simple du style MMO."