Comment les niveaux mipmap sont-ils calculés dans Metal?

14

Ma question concerne spécifiquement Metal, car je ne sais pas si la réponse changerait pour une autre API.

Ce que je crois comprendre jusqu'à présent est le suivant:

  • Une texture mipmappée a des "niveaux de détail" précalculés, où des niveaux de détail inférieurs sont créés en sous-échantillonnant la texture d'origine de manière significative.

  • Les niveaux Mipmap sont référencés dans un niveau de détail décroissant, où le niveau 0est la texture d'origine, et les niveaux supérieurs sont des réductions de puissance de deux.

  • La plupart des GPU implémentent un filtrage trilinéaire, qui sélectionne deux niveaux mipmap voisins pour chaque échantillon, des échantillons de chaque niveau à l'aide du filtrage bilinéaire, puis fusionne linéairement ces échantillons.

Ce que je ne comprends pas vraiment, c'est comment ces niveaux de mipmap sont sélectionnés. Dans la documentation de la bibliothèque standard Metal, je constate que des échantillons peuvent être prélevés, avec ou sans spécification d'une instance d'un lod_optionstype. Je suppose que cet argument change la façon dont les niveaux de mipmap sont sélectionnés, et il existe apparemment trois types de lod_optionstextures 2D:

  • bias(float value)
  • level(float lod)
  • gradient2d(float2 dPdx, float2 dPdy)

Malheureusement, la documentation ne prend pas la peine d'expliquer ce que font ces options. Je peux deviner que cela bias()biaise un niveau de détail choisi automatiquement, mais alors qu'est-ce que le biais valuesignifie? À quelle échelle fonctionne-t-il? De même, comment le lodof est-il level()traduit en niveaux mipmap discrets? Et, fonctionnant sous l'hypothèse qui gradient2d()utilise le dégradé de la coordonnée de texture, comment utilise-t-il ce dégradé pour sélectionner le niveau mipmap?

Plus important encore, si j'omets le lod_options, comment les niveaux mipmap sont-ils alors sélectionnés? Cela diffère-t-il selon le type de fonction en cours d'exécution?

Et, si l'opération par défaut spécifiée par no-lod-options sample()est de faire quelque chose comme gradient2D()(au moins dans un shader de fragments), utilise-t-elle de simples dérivées d'espace d'écran ou fonctionne-t-elle directement avec un rastériseur et des coordonnées de texture interpolées calculer un gradient précis?

Et enfin, quelle est la cohérence de ce comportement d'un appareil à l'autre? Un vieil article (ancien comme dans DirectX 9) que j'ai lu faisait référence à une sélection mipmap complexe spécifique à un périphérique, mais je ne sais pas si la sélection mipmap est mieux définie sur les architectures plus récentes.

lcmylin
la source

Réponses:

17

La sélection de Mip est assez bien standardisée sur tous les appareils aujourd'hui, à l'exception de certains détails minuscules du filtrage anisotrope, qui restent à définir par les fabricants de GPU individuels (et ses détails précis ne sont généralement pas publiquement documentés).

Un bon endroit pour en savoir plus sur la sélection du mip est dans la spécification OpenGL, section 8.14, «Texture Minification» . Je suppose que cela fonctionne de la même manière dans Metal. (Apple aurait pu changer quelque chose, étant donné qu'ils fabriquent à la fois le matériel et l'API ... mais j'en doute.) Je vais le résumer ici.

La sélection de mip par défaut (n'utilisant aucun des lod_optionsmodificateurs) utilise les dégradés d'espace d'écran des coordonnées de texture pour choisir les niveaux de mip. Essentiellement, il essaie de choisir les niveaux de mip qui produisent le plus près possible d'un mappage 1: 1 de texels en pixels. Par exemple, si les dégradés ont une longueur de 4 texels par pixel, il choisirait le niveau de mip 2 (qui est 1/4 de la taille du niveau 0 et vous donne donc 1 texel mipped par pixel).

Avec le filtrage trilinéaire, puisque vous n'atterrissez généralement pas sur un mappage exact 1: 1, il sélectionne les deux niveaux les plus proches et les interpole linéairement entre eux, de sorte que vous avez une transition en douceur entre les niveaux de mip lorsque la caméra ou les objets de votre scène se déplacent autour.

λλλλ=2.8

λJournal2(1/4)=-2

Maintenant, comme pour les options de modification:

  • biasλ
  • levelλλlod
  • gradient2dvous permet de placer vos propres vecteurs de dégradé, qui se substituent aux dégradés implicites de l'espace d'écran des coordonnées de texture. Le reste du processus de sélection et d'échantillonnage du mip se déroule normalement, mais avec les gradients modifiés. Cela vous permet de personnaliser le filtrage anisotrope.

Dans d'autres types de shaders, à part les shaders de fragments, il n'y a pas de notion de "dégradés d'espace d'écran", donc les deux dernières opérations sont généralement les seules autorisées - toute opération qui essaie d'utiliser des dégradés implicites donnerait une erreur de compilation. Je ne suis pas sûr que Metal le fasse, mais c'est ce que j'attends de travailler avec d'autres API.

Nathan Reed
la source