Bonjour,
j'essaye en ce moment de développer un système de rendu de monde de voxels ( comme Minecraft, je sais très original ..) avec LWJGL et Opengl 3.3+
Enfait, mon problème se situe dans le fait que je cherche à optimiser au maximum la vitesse de rendu : utiliser le moins de draw calls possible, et minimiser les transferts de données entre la carte graphique et le processeur.
Mon système pour l'instant est simple : 3 threads :
- Thread logique : mécanique principale
- Thread graphique : appels Opengl, etc
- Thread d'échange de données : informations sur les voxels
Mes blocs sont stockés dans de grands tableaux d'entiers de 64*64*256 (appelés "chunks").
Du coup, j'en suis venu à 2 idées de "structures" différentes pour le rendu, mais qui ont chacunes leurs inconvénients :
- Première méthode : Pour chaque voxel de la map, je stocke le minimum d'informations nécessaires au rendu : id texture, niveau de luminosité, le tout dans un grand VBO. Si un bloc est vide ou ne doit pas être rendu, l'id de la texture est 0 (ceci afin de pouvoir midifier facilement le VBO plus tard, comme la place est deja réservée dans la mémoire).
Ensuite, je créé 6 VAO contenant chacun 1 VBO contenant eux même les coordonnées des points d'une des 6 faces d'un cube. Puis, selon la direction et la position de la caméra, à chaque frame, je rends 3 de ces VBO ( on peut voir au maximum 3 faces d'un cube au même moment ) avec glDrawArraysInstanced. Les informations sur les blocs sont ainsi utilisées en paramètres : dans le vertex shader, si l'id de la texture est différent de 0, je rends le bloc, sinon, j'annule l'instance.
Avantages :
- je peux modifier facilement un bloc en "mappant" le VBO et en modifiant seulement les blocs concernés
- un seul draw call, moins de synchronisations entre la carte graphique et le processeur
Inconvénients :
- si le bloc n'existe pas et qu'il ne doit pas être rendu, un vertex shader a quand même été lancé et cela coûte beaucoup en performances
- Deuxième méthode : On reprend la méthode 1, mais on sépare chaque chunk dans un VBO différent. De plus, les blocs inexistants ne sont pas ajoutés ni remplacés par des 0.
Avantages :
- pas de vertex shaders lancés inutilement
- frustum culling plus facile
- moins de mémoire utilisée sur la carte graphique car les blocs vides ne sont pas enregistrés
Inconvénients :
- à chaque modification d'un chunk, il faut réuploader TOUTES les informations concernant ce chunk (mauvais pour les performances ..)
- beaucoup plus de draw calls (64 pour un terrain de 256 * 256 * 256 blocs)
Mes questions sont donc :
1) Peut on annuler prématurément une instance selon une valeur stockée dans un VBO avec glDrawArraysInstanced ?
2) Peut on ajouter ou supprimer des informations dans un VBO sans avoir à tout réuploader (ce qui peut être très fréquent) ?
Merci d'avance si vous avez lu (et compris) mon pavé !![]()
Partager