Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Moteur 3D] hARMful

Ensemble de bibliothèques C++/OpenGL

Anonyme
    2 avril 2020 à 0:13:04

    Bonjour/Bonsoir à toutes et à tous,

    Voici un projet de moteur 3D en OpenGL. Il n'a aucun but, si ce n'est l'apprentissage. Pour l'instant, il ne fait rien qu'afficher des objets 3D avec des shaders...

    Exemple de scène

    -
    Edité par Anonyme 5 juillet 2020 à 16:44:10

    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      8 avril 2020 à 12:27:19

      Bonjour à tous,

      Amélioration des ombres

      -
      Edité par Anonyme 5 juillet 2020 à 16:44:28

      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        21 mai 2020 à 18:17:31

        Bonjour,

        Début de rendu PBR/IBL

        -
        Edité par Anonyme 5 juillet 2020 à 16:44:43

        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          26 mai 2020 à 11:12:19

          Bonjour,

          Développement d'un outil pour générer les images nécessaires a l'IBL

          -
          Edité par Anonyme 5 juillet 2020 à 16:45:09

          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            3 juin 2020 à 11:56:01

            Hello,

            J'ai ajouté de quoi calculer la BRDF look-up table au programme (optionnel). Le calcul étant un peu long, j'ai recouru au multithreading et ça donne un bon coup de fouet. Le programme utilise autant de threads que disponibles sur le CPU, j'ai pas mis d'option pour ça...

            L'image a une taille en puissance de 2 uniquement. Je la découpe en autant de carrés de 32x32 pixels que nécessaire et j'alloue autant de threads que possible. Sur un Intel i7 4 cœurs HT (donc 2 threads par cœur), si l'image est composée de 4 portions, il y aura 4 threads. S'il y a 256 portions, il y aura 8 threads qui tourneront en boucle jusqu'à compléter l'image entièrement.
            Les threads piochent dans une stack de portions jusqu'à épuisement de son contenu.

            L'image peut avoir une taille minimale de 32x32 pixels (ce qui fera tourner un seul thread). Il n'y a pas de taille maximale même si elle fait généralement 512 voire 1024 pixels de côtés.

            -
            Edité par Anonyme 5 juillet 2020 à 16:45:25

            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              12 juin 2020 à 21:02:24

              Bonsoir !

              J'ai de premiers résultats pour du rendu PBR avec l'ensemble des données générées avec l'outil dont j'ai parlé au-dessus. Voici quelques rendus à chaud, bien que des détails soient encore à finaliser.

              Pour la dernière, le rendu n'est pas terrible. C'est normal car Assimp ne supporte pas le rendu PBR autrement qu'avec le format glTF. Or, je n'aime pas ce format car il est vraiment trop lourd en plus d'être du texte donc très long à charger de base. Quand ça arrive, le moteur utilise ce qu'il peut de Assimp (= couleur de diffus) et le reste est mis en valeurs par défaut. Un peu comme le fait Unity, mais Unity fait ça mieux évidemment !

              Pour les autres objets, c'est pas beaucoup mieux. C'est un système où il faut respecter une certaine structure de dossier pour placer les différentes textures (albedo, normal, ...) puisque Assimp ne sait pas les trouver. Il me faudra faire un éditeur pour qu'il soit possible de créer des matériaux compatibles avec le moteur.

              Il y a des bugs mineurs à corriger encore, comme les reflets qui tremblent un peu en bougeant la caméra.
              Quand le rendu sera débogué, je pense que je continuerai sur des choses un peu plus légères pour faire une "pause". J'aimerais ajouter des effets de post-prod comme du bloom. Ca donne une image bien plus jolie.
              Parmi les autres choses que je voudrais faire en terme de shading : parallax mapping, subsurface scattering, clear coat et anisotropie.

              A bientôt !

              -
              Edité par Anonyme 5 juillet 2020 à 16:45:45

              • Partager sur Facebook
              • Partager sur Twitter
                15 juin 2020 à 15:37:12

                C'est du lourd tous ça ;)

                le projet à un discord ?

                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  15 juin 2020 à 18:04:59

                  Hello ! Merci ! :)

                  Non, j'ai juste une chaîne Youtube pour faire des vidéos quand une nouvelle feature fonctionne à peu près. Jusqu'à présent, l'aspect communauté n'est pas vraiment développé.

                  Je trouve que le moteur n'a pas encore beaucoup d'intérêt pour un Discord et tout. En fait, c'est un projet à la base plutôt pour apprendre à faire des trucs en OpenGL/GLSL sur le temps libre, donc orienté plutôt shaders/rendu. Alors je sais pas si ça peut vraiment motiver des gens au point de mettre un Discord. :euh:

                  Je te cache pas que j'aimerais beaucoup avoir déjà un truc où on peut interagir plus (contrôles, moteur physique...). Là, ça serait déjà plus plaisant pour qu'une communauté se forme et commence à tester avec des mini jeux.

                  C'est d'ailleurs pour ça qu'il a encore de grosses lacunes. Il est très mal optimisé car j'ai fait aucun effort là-dessus. Donc une petite scène va vite ramer et un jeu ne pourrait même pas tourner correctement...
                  J'ai des idées pour améliorer les perfs mais le rendu est prioritaire encore maintenant. Quand les grosses bases seront posées, là je pense que j'irai sur un gros refactoring du système (au sens Entité-Composant-Système) afin d'optimiser le moteur. Ensuite, j'ajouterai des contrôles et le moteur physique Bullet ! :D

                  Oui, je sais vendre mes projets. Faudrait que je me convertisse dans le marketing ! :p

                  -
                  Edité par Anonyme 15 juin 2020 à 18:09:49

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    24 juin 2020 à 11:07:22

                    Salut,

                    C'est la première démo pour la V2.0 du moteur. Il n'y a absolument rien de définitif, la V2.0 devrait sortir fin automne/début hiver 2020. J'aimerais la sortir en décembre 2020 au plus tard.

                    C'est donc une première version avec des shaders de base pour ce rendu. Je compte en ajouter d'autres pour différentes surfaces : "subsurface scattering" pour la peau par exemple, "clear coat" pour les peintures métallisées, rendu amélioré des tissus, ...

                    Avant ça, je vais revoir en profondeur le fonctionnement interne du moteur. Je pensais m'attaquer à cette partie dans plusieurs mois lors d'une grosse phase d'optimisation mais finalement je bouscule un peu ces plans. Il me semble plus intéressant de faire les modifications maintenant pour pérenniser la structure du moteur. De plus, en optimisant plus tôt, je pourrai proposer des interactions utilisateur aussi plus tôt (= faire quelque chose de "jouable" avec le moteur).

                    Au programme, principalement du multithreading et le static batching (pour limiter le nombre de drawcalls). Avant de lancer la boucle principale de rendu, le programme va optimiser l'arbre de scène et précalculer/regrouper les données pouvant l'être. C'est grosso modo la ligne que je me donne à cet instant où je n'ai que des objets physiquement statiques.

                    :)

                    -
                    Edité par Anonyme 5 juillet 2020 à 16:46:01

                    • Partager sur Facebook
                    • Partager sur Twitter
                      27 juin 2020 à 23:34:17

                      Bon boulot ! J'adore le logo
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Anonyme
                        28 juin 2020 à 18:20:23

                        Coucou Crevette,

                        Merci bien ! En éternel insatisfait, je vois plein de défauts à corriger au plus vite. ^^

                        A commencer par l'architecture. Le principe de ce projet est de partir d'une solution naïve et d'explorer ensuite des solutions plus complexes quand ça se révèle nécessaire. Pour l'architecture du moteur de rendu, j'ai franchi ce cap. J'étais basé sur une approche 100% arbre (de scène) avec des noeuds portant des composants. Ca fait le taf mais c'est très très loin d'être optimal. Je précise que c'est pas une découverte et que c'est parfaitement assumé. C'est ma façon de travailler pour mieux comprendre les enjeux de ce qui est communément établi. J'ai ce besoin d'expérimenter de mon côté pour me rendre compte et comprendre pourquoi c'est de la m****, pourquoi les gens font comme ça et pas autrement. :D

                        Déjà, les performances sont nulles. C'était quelque chose de connu dès le départ (j'avais prévu des phases d'optimisation avant même la sortie de la V1.0), ce n'est pas une surprise qui tombe du ciel tout à coup. Cependant, j'ai un peu changé mon fusil d'épaule et j'ai commencé à revoir mon planning il y quelques semaines pour mettre en place le static batching plus tôt que prévu. Puis, j'ai pensé que multithreader le prétraitement sur CPU serait encore un gros plus, en particulier avec la possibilité de développer un "thread pool" (j'en ai codé un dans l'outil d'IBL et sa place est plutôt dans la bibliothèque). Le premier but de ce projet était pour moi d'arriver à du rendu un peu plus joli que du simple Phong. Or là, ça commence à arriver même s'il faut encore énormément de boulot.
                        Le fait d'optimiser les performances côté CPU me laissera le champ libre pour commencer à rendre le moteur exploitable sur des scènes plus grosses, l'interaction, la physique et les animations. Ce n'est pas un détail et je ne suis pas sûr de continuer uniquement sur du rendu pour les prochaines versions. En clair, j'aimerais distiller ici et là le moteur physique et les interactions avec l'utilisateur au lieu d'y consacrer des versions spécifiques et tardives.

                        Bon, quand on commence à regrouper tout ça, on se dit autant mettre les deux pieds dans le plat !
                        Donc j'ai commencé à designer une architecture Entité-Composant-Système. Je me suis un peu documenté sur le sujet et je m'en suis inspiré pour faire quelque chose qui me convienne aussi. J'ai introduit en plus l'idée d'une machine à états pour les différents systèmes, certains devant s'exécuter successivement avant d'autres (inputs, réception réseau et IA, suivi de la physique), ou certains pouvant s'exécuter en parallèle après ces changements dans la scène (rendu, son, envoi réseau). Avant de mettre en place cette architecture, je voudrais la tester car c'est la première fois que je fais cet exercice donc il y a pas mal d'inconnues.
                        Il se trouve que j'ai commencé à apprendre le langage Rust. Je pensais me lancer dans un petit jeu 2D (avec SDL2) après la sortie de la V2.0 du moteur, histoire de faire un petit break et de produire quelque chose de plus concret. Je me dis que c'est peut-être l'occasion de justement apprendre Rust en implémentant une telle architecture dans un petit projet similaire. Le but n'est pas de faire le jeu complet immédiatement mais au moins tester quelques bribes de l'architecture pour en voir les plus gros défauts et les corriger. Une fois cette étape faite, je pourrai intégrer l'architecture dans le moteur sans avoir à tout modifier 40 fois.

                        En fait, le passage de V1.x à V2.x s'accompagne de modifications assez radicales dans l'utilisation du moteur. J'aimerais conserver autant que possible ce qui aura été fait dans dans la V2.0, sans devoir refaire de profonds changements invalidant totalement les projets. D'où ce besoin d'assurer la bonne architecture et la remettre le moins possible en cause.

                        Donc pour résumer ce pavé : le projet sera indirectement "en pause" pendant quelques temps pour préparer la nouvelle architecture. :p

                        -
                        Edité par Anonyme 5 juillet 2020 à 16:46:14

                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 juin 2020 à 22:15:05

                          Tu n'avait

                          pas d'ECS ?
                          Comment fesait tu ton rendu ? Un SceneGraph (arbre) de tes objet ?
                          Avec l'ECS tout ca deviens beaucoup plus rapide : tu manipule une liste d'identifiant ( int ) plutot qu'une liste d'objet.

                          Dans mon cas mon ECS ressemble a ca :

                          using Entity = std::size_t;

                          using Ctype = std::string;
                          
                          class base_component {
                          private:
                              Ctype type;
                              Entity owner;
                          }


                          et le store :

                          using Box = std::map<Entity, std::unique_ptr<BComponent>>;
                          
                          		class CBox {
                          		public:
                          			void Add(std::unique_ptr<BComponent> comp)
                          			{
                          				auto owner = comp->Owner();
                          				Components_.emplace(owner, std::move(comp));
                          			}
                          
                          			BComponent* Get(Entity owner)
                          			{
                          				auto found = Components_.find(owner);
                          
                          				if (found != Components_.end())
                          				{
                          					return found->second.get();
                          				}
                          
                          				return nullptr;
                          			}
                          
                          			void Remove(Entity owner)
                          			{
                          				Components_.erase(owner);
                          			}
                          		private:
                          			Box Components_;
                          		};
                          
                          		using Boxes = std::map<CType, CBox>;
                          
                          		class Store {
                          		public:
                          			Store() {};
                          
                          			template<class T>
                          			T* Add(std::unique_ptr<BComponent> comp)
                          			{
                          				auto t = comp->Type();
                          				auto box = Boxes_.find(t);
                          
                          				// add the box, it does not exist yet
                          				if (box == Boxes_.end())
                          				{
                          					CBox new_box{};
                          					Boxes_.emplace(t, std::move(new_box));
                          					box = Boxes_.find(t);
                          				}
                          
                          				auto owner = comp->Owner();
                          				box->second.Add(std::move(comp));
                          
                          				return static_cast<T*>(box->second.Get(owner));
                          			}
                          
                          		private:
                          			Boxes Boxes_;
                          		};

                          Mon 'Store' a donc cette forme : std::map< Component_type , std::map< Owner , Component>>.
                          En gros : 1 boite par type de composant. 1 composant par entité.

                          Quasi le systeme entier a access au store. Ainsi il suffit de :

                          auto const Position = store.Get<Position*>(owner);
                          if(Position != nullptr)
                             Position.x = ..
                             Position.y = ..
                             Position.z = .. 

                          Est-ce le meilleur design ? Aucune idée , mais c'etait le plus simple pour moi pour conserver et recuperer un composant.

                          A partir de la ton scene graph peut etre composé que d'entités.

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            29 juin 2020 à 0:47:12

                            J'avais un ECS mais il n'a pas la meilleure architecture. J'ai du mal à l'appeler ECS mais ça y correspond. Tu peux te faire une idée de l'architecture avec Qt3D dont je m'étais inspiré partiellement. Je pense encore garder une part de cette façon de faire, en particulier le framegraph que je trouve puissant, bien que cette partie sera légèrement revue.
                            Le Frostbite Engine utilise aussi un framegraph par exemple, très probablement différemment de ma gestion, mais il en utilise un.
                            https://www.ea.com/frostbite/news/framegraph-extensible-rendering-architecture-in-frostbite

                            Pour l'instant, je ne montre pas le résultat de l'architecture remodelée, je le ferai quand elle sera définitive. Là je pourrai vraiment parler d'ECS. Je vais bien utiliser des ID pour les entités et les composants, ainsi que des systèmes et des événements pour les communications internes au moteur.

                            Jusqu'à présent je me passais d'ID car je gérais ça à l'aide de pointeurs comme je n'avais pas de gestion d'événements. Or, ce manque d'événements était aussi une grosse limitation de l'architecture actuelle.

                            -
                            Edité par Anonyme 29 juin 2020 à 0:49:50

                            • Partager sur Facebook
                            • Partager sur Twitter

                            [Moteur 3D] hARMful

                            × 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.
                            • Editeur
                            • Markdown