Utiliser l'instanciation pour tout?

16

L'instanciation améliore les performances (de manière significative) lors du rendu de plusieurs copies (des centaines de milliers?) Du même maillage à la fois. Mais combien de temps faut-il pour rendre exactement une copie avec un appel de tirage? Serait-ce une bonne ou une mauvaise idée d'utiliser l'instanciation pour toute la géométrie rendue par le moteur?

Edit: Disons que nous créons un jeu FPS. La plupart des objets n'ont qu'un seul exemple: un couteau, une arme à feu, une mitrailleuse, un bâtiment et une tour radio. Mais il y a aussi des objets avec plusieurs instances: des arbres (par exemple 3 types d'arbres avec des centaines d'instances), de l'herbe, etc. et l'herbe en utilisant l'instanciation, nous les rendons tous en utilisant l'instanciation. Donc, notre tour radio n'a qu'une seule instance (dont nous stockons les informations dans un tampon de données d'instance) et nous rendons cette tour en utilisant une sorte d' DrawInstanced()appel avec un nombre d'instances égal 1. Même chose avec tous les autres objets (bien sûr, les arbres et l'herbe ont plusieurs instances).

Ma question est donc: est-ce une mauvaise idée de dessiner une seule instance d'un objet en utilisant l'instanciation? L'instanciation a-t-elle trop de surcharge (en termes de mémoire et de performances) ou est-elle en aucune façon indésirable pour le rendu d'objets à instance unique?

NPS
la source

Réponses:

19

Sous D3D9 avec XPDM, vous souhaiterez presque certainement l'instance autant que possible. Le surdébit d'appel est tellement élevé que cela a du sens. Dans ce scénario, le point de croisement peut être aussi bas que 2 ou 3 instances.

Si vous n'avez qu'une seule instance d'un maillage donné, il peut sembler à la surface tentant de le dessiner sans instance. Cependant, regardez ce qui est impliqué:

  • Vous devez basculer du chargement des données dans un tampon par instance vers le téléchargement des constantes de shader.
  • Vous devez conserver deux copies de votre vertex shader: une pour instanciée et une pour non instanciée.
  • Vous devez conserver deux copies de votre code de rendu: de même.
  • Vous devez changer de shaders.
  • Vous devez changer de format de sommet.
  • Vous devrez peut-être changer de tampon de vertex.
  • Et puis vous devez recommencer si vous revenez au dessin instancié pour le groupe de maillages suivant.

Même si vous n'avez qu'un seul maillage (comme le modèle de pistolet dans un FPS), il existe des cas où l'instanciation est utile. Disons que vous faites une accumulation de lumière multipass dans un moteur de rendu direct et avec un z-prepass. Au lieu d'un passage supplémentaire pour chaque lumière, vous créez vos données de lumière par instance et vous les dessinez instanciées.

Sur la base du premier scénario, la morale de l'histoire est que si une classe d'objets peut utiliser l'instanciation, il est logique de toujours utiliser l'instanciation pour tous les objets de cette classe.

Sur la base du deuxième scénario, la morale de l'histoire est que l'instanciation peut avoir des utilisations non évidentes qui vont au-delà du simple fait de dire "J'ai besoin de dessiner 20 arbres".

Maximus Minimus
la source
Les raisons que vous avez données sont les mêmes que celles qui m'ont amené à poser cette question en premier lieu. Je vous remercie.
NPS
12

(Sur mon système, je ne l'ai testé nulle part ailleurs) Dans GL, l'instanciation d'un seul maillage (dessin avec count = 1) a des frais généraux désagréables, mais je ne sais pas d'où il vient. Je suggère fortement de ne pas le faire.

J'ai testé cela dans une application pratique il y a quelques mois. J'ai codé quelques algorithmes d'éclairage global dans la scène Crytek Sponza, qui se compose d'environ 350 mailles (je ne me souviens pas exactement), dont un couple partage une poignée d'exemples. Au début, je l'ai fait comme vous le suggérez, installez tout et dessinez le reste avec un nombre d'instances de 1, car cela simplifiait un peu le code de rendu.

Plus tard lors de l'optimisation du rendu, il suffit de revenir de l'instanciation des objets count = 1 à leur soumission de la manière habituelle, ce qui m'a sauvé 3,5 millisecondes par trame de temps sur un i7 3770k (et GTX 770). Changer les mailles avec plusieurs instances pour les faire simplement de la manière traditionnelle m'a fait gagner encore 0,5 ms. Globalement, l'application est passée de ~ 120 FPS à environ ~ 230 FPS.

Ces chiffres dépendent bien sûr toujours de l'endroit où se trouvent les goulots d'étranglement dans votre application, et les derniers 0,5 ms peuvent en fait devenir un ralentissement dans une application où vous êtes très lié à l'appel. Mais sinon, d'après mon expérience, l'instanciation a des frais généraux désagréables si vous ne dessinez pas beaucoup de choses à la fois.

TravisG
la source
Intéressant, mais ce serait bien de voir les données pour les pilotes AMD et Intel également, sinon, vous devriez vraiment dire "Sur mon système" au lieu de "Dans GL". D'un autre côté, même si ce n'est pas un problème avec d'autres implémentations, le fait que cela puisse être sur certaines est une raison suffisante pour éviter l'instanciation si vous ne l'utilisez pas.
bcrist
2

Vous pouvez être certain que dessiner un seul objet instancié est plus cher que de dessiner un seul objet normalement. Pour l'instanciation, le GPU se prépare à une grande quantité d'objets et cette préparation sera différente de celle d'un seul objet. Cependant, l'ampleur de cet écart de performances ne peut être trouvée qu'en expérimentant et dépend beaucoup de votre configuration de rendu réelle. La seule façon de savoir avec certitude est de le tester vous-même. L'analyse comparative d'un appel de tirage unique est difficile, voici plusieurs idées sur la façon de procéder.

Roy T.
la source
2

Cela fait 4 ans ... et je pense qu'il est prudent de dire qu'il est tout à fait correct de soumettre des appels de tirage "instanciés" avec 1. Comme vous l'avez peut-être remarqué, les nouvelles API DX12 et Vk ont toutes deux un nombre d'instances pouvant aller de 0 à NUM_INSTANCES . Notez également qu'il n'y a pas de DrawIndexed (...) .

ÉDITER

Par souci de prudence, ce qui précède est probablement correct avec ces API modernes, peut-être que l'utilisation de quelque chose de vieux comme Gl <3.3 ou peut-être DX11 nécessitera un profilage comme mentionné par d'autres utilisateurs.

Nacho
la source