J'ai un monde basé sur des cubes comme Minecraft et je me demande s'il existe un moyen de construire un cube avec moins de 24 sommets afin de pouvoir réduire l'utilisation de la mémoire.
Cela ne me semble pas possible pour 2 raisons: les normales ne sortiraient pas bien et les textures par face ne fonctionneraient pas.
Est-ce le cas ou je me trompe? Peut-être existe-t-il une nouvelle technologie DX11 sophistiquée qui peut vous aider?
Edit: Juste pour clarifier, j'ai 2 exigences: j'ai besoin de normales de surface pour chaque face de cube afin de faire un bon éclairage et j'ai besoin d'un moyen d'adresser un index différent dans un tableau de texture pour chaque face de cube
Réponses:
Si vous n'avez besoin que de normales par face et si vos texcoords pour une face sont strictement 0/0, 0/1, 1/0, 1/1 (ou similaire pour convenir à votre disposition), vous pouvez construire un cube avec 8 verts et soit 30 (bande avec redémarrage) ou 36 (liste) index. Récupérez les normales et les texcoords en utilisant une recherche de tableau constante basée sur SV_VertexID dans votre vertex shader.
Cela signifie que vous n'avez même pas besoin d'inclure des texcoords ou des normales dans votre tampon de vertex, ce qui vous donnera encore plus d'économie de mémoire.
En allant plus loin, vous pouvez toujours aller jusqu'à 24 verts par cube mais aussi utiliser l'instanciation. Chaque cube aurait une taille fixe dans votre tampon de vertex (1x1x1) et vous auriez un facteur d'échelle et une position (en supposant que vos cubes ne tournent pas, une matrice s'ils le font) en tant que données par instance. Dans le cas non rotatif, vous avez un coût unique de 24 verts, mais chaque cube n'a besoin que de 6 flotteurs pour être entièrement spécifié. Dans le cas rotatif, vous regardez 16 flottants, mais même cela représente une économie substantielle (vous êtes plus susceptible de goulot d'étranglement côté processeur sur les transformations matricielles dans ce cas - pour le cas non rotatif construisant une matrice à la volée) votre vertex shader - même si c'est fait par vertex, est si stupidement rapide que vous n'avez même pas besoin de vous en soucier).
Pour les textures par face, utilisez simplement un tableau de textures. Vous devez vous assurer que chacune de ces textures dans le tableau est de la même taille, bien sûr, et vous devrez toujours casser votre lot actuel si le tableau lui-même doit changer, mais sinon il fera très bien le travail. Ajoutez un troisième texcoord à votre définition de sommet qui définit la tranche de tableau à utiliser pour chaque face.
Vous n'avez pas besoin d'un GS avec cela, et il devrait fonctionner plus rapidement que d'en utiliser un car l'activation du stage de shaders de géométrie imposera des frais supplémentaires.
J'ai un code de référence dans mon moteur qui dessine juste un tas de cubes en utilisant cette méthode, et je peux facilement mâcher plus de 300 000 cubes tout en effaçant 60fps, sur un GPU relativement bas de gamme, et sans rien faire d'autre pour optimiser le processus . Certes, je ne les éclaire ni ne les texture, mais j'ai le mélange alpha activé, la suppression de la face arrière désactivée, et dans l'ensemble, il s'équilibre avec ma partie "ne rien faire d'autre pour optimiser", donc cela devrait vous donner une idée raisonnable du type de vous pouvez frapper avec cette méthode.
la source
Je pense que l'optimisation principale que vous pouvez faire est basée sur le fait que tous les cubes n'auront pas réellement besoin des 24 sommets . En fait, les seuls cubes qui ont besoin de 24 sommets sont ceux qui flottent dans les airs, ce qui est probablement rare.
En général, ne générez des quadruples que pour les faces en contact avec l'air . Cela signifie que si deux cubes se touchent, vous n'avez pas besoin de générer de sommets pour la face où ils se touchent.
L'image ci-dessous illustre ce concept, mais en 2D pour une meilleure compréhension. Dans l'image, il y a 11 blocs occupés (représentés par les cercles gris remplis), ce qui nécessiterait normalement 4 x 11 = 44 bords pour représenter (4 car c'est un carré, pas un cube). Mais comme vous pouvez le voir, vous n'avez vraiment besoin de dessiner les bords que lorsqu'ils sont en contact avec un carré vide, qui dans ce cas, n'est que de 8 bords.
Si un exemple aussi simple en 2D a réussi à réduire 44 arêtes à 8 arêtes, imaginez les gains dans un grand monde 3D ...
C'est l'approche décrite dans cet article , que je vous recommande de lire, bien qu'elle soit destinée à OpenGL. Les concepts devraient cependant être assez universels.
Vous pourriez aussi probablement utiliser un shader de géométrie pour générer les sommets à la volée sur le GPU, éliminant ainsi la nécessité de les stocker en mémoire, mais je n'ai pas d'expérience avec cela, et je ne sais pas non plus à quel point il fonctionnerait pour un grand monde.
la source