Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les cartes d'ombre en cascade (CSM) sont la meilleure façon de combattre l'une des erreurs les plus courantes avec les ombrages : l'aliasing de perspective. Cet article technique, qui suppose que le lecteur est familiarisé avec le mappage d’ombres, traite du sujet des CSM (Cascaded Shadow Maps). Plus précisément, il :
- explique la complexité des CSMs;
- fournit des détails sur les variations possibles des algorithmes CSM ;
- décrit les deux techniques de filtrage les plus courantes : le pourcentage de filtrage plus proche (PCF) et le filtrage avec des mappages d’ombres de variance (VSMs) ;
- identifie et résout certains des pièges courants associés à l’ajout de filtrage aux CSMs ; et
- montre comment mapper des modèles de services cloud à Direct3D 10 via du matériel Direct3D 11.
Le code utilisé dans cet article se trouve dans le Kit de développement logiciel DirectX (SDK) dans les exemples CascadedShadowMaps11 et VarianceShadows11. Cet article s’avère le plus utile après avoir implémenté les techniques décrites dans l’article technique, Les techniques courantes pour améliorer les cartes de profondeur d’ombre sont implémentées.
Cartes d'ombres en cascade et aliasing de perspective
L’alias de perspective dans une carte d’ombres est l’un des problèmes les plus difficiles à surmonter. Dans l’article technique, les techniques courantes pour améliorer les cartes de profondeur de l’ombre, l’alias de perspective est décrit et certaines approches pour atténuer le problème sont identifiées. Dans la pratique, les CSM ont tendance à être la meilleure solution et sont couramment employées dans les jeux modernes.
Le concept de base des machines virtuelles cloud est facile à comprendre. Différentes zones de la caméra frustum nécessitent des cartes d’ombre avec différentes résolutions. Les objets les plus proches de l’œil nécessitent une résolution supérieure à celle des objets plus distants. En fait, lorsque l’œil se déplace très près de la géométrie, les pixels le plus proche de l’œil peuvent nécessiter tellement de résolution que même une carte d’ombre 4096 × 4096 est insuffisante.
L'idée de base des CSMs consiste à diviser le frustum en plusieurs frusta. Une carte d'ombres est rendue pour chaque sous-frustum ; le pixel shader prélève ensuite des données de la carte qui correspond le mieux à la résolution requise (Figure 2).
Figure 1. Couverture de la carte d'ombres
Dans la figure 1, la qualité est indiquée (de gauche à droite) de la plus haute à la plus basse. La série de grilles représentant des cartes d'ombres avec un frustum d’affichage (cône inversé en rouge) illustre comment la couverture des pixels est affectée par différentes résolutions des cartes d’ombres. Les ombres sont de la meilleure qualité (pixels blancs) lorsqu'il y a un rapport de mappage de 1:1 entre les pixels dans l'espace d'affichage et les texels dans la carte d'ombre. L’alias de perspective se produit sous la forme de cartes de textures volumineuses et bloquées (image gauche) lorsque trop de pixels sont mappés au même texel d’ombre. Lorsque la carte d’ombres est trop grande, elle est sous-échantillonnée. Dans ce cas, les texels sont ignorés, des effets de scintillement apparaissent et les performances sont affectées.
Figure 2 : Qualité des ombres de CSM
La figure 2 montre les extraits de la section de qualité la plus élevée dans chaque carte d’ombres de la figure 1. La carte d’ombres avec les pixels les plus étroitement placés (à l’apex) est la plus proche de l’œil. Techniquement, il s’agit de cartes de la même taille, avec le blanc et le gris utilisés pour illustrer le succès de la carte d’ombre en cascade. Le blanc est idéal, car il présente une bonne couverture : un rapport de 1:1 pour les pixels d’espace oculaire et les texels de la carte d’ombre.
Les CSMs nécessitent les étapes suivantes par trame.
Partitionnez le frustum en sous-frusta.
Calculez une projection orthographique pour chaque sous-frustum.
Générez une carte d’ombres pour chaque sous-frustum.
Affichez la scène.
Lier les cartes d'ombre et effectuez le rendu.
Le nuanceur de vertex effectue les opérations suivantes :
- Calcule les coordonnées de texture pour chaque subfrustum clair (sauf si la coordonnée de texture nécessaire est calculée dans le nuanceur de pixels).
- Transforme et éclaire le vertex, et cetera.
Le nuanceur de pixels effectue les opérations suivantes :
- Détermine la carte d’ombre appropriée.
- Transforme les coordonnées de texture si nécessaire.
- Échantillonne la cascade.
- Allume le pixel.
Partitionnement du frustum
Le partitionnement du frustum est l’acte de créer des sous-frusta. Une technique pour fractionner le frustum consiste à calculer les intervalles de zéro à cent pour cent dans la direction Z. Chaque intervalle représente ensuite un plan proche et un plan éloigné sous la forme d’un pourcentage de l’axe Z.
Figure 3. Afficher les frustums partitionnés arbitrairement
En pratique, le recalcul des divisions de frustum par image provoque un scintillement des bords d’ombre. La pratique généralement acceptée consiste à utiliser un ensemble statique d’intervalles en cascade par scénario. Dans ce scénario, l’intervalle le long de l’axe Z est utilisé pour décrire un sous-frustum qui se produit lors du partitionnement du frustum. La détermination des intervalles de taille corrects pour une scène donnée dépend de plusieurs facteurs.
Orientation de la géométrie de scène
En ce qui concerne la géométrie de la scène, l’orientation de la caméra affecte la sélection de l’intervalle en cascade. Par exemple, une caméra très près du sol, telle qu’une caméra au sol dans un jeu de football, a un ensemble statique différent des intervalles de cascade qu’une caméra dans le ciel.
La figure 4 montre des caméras différentes et leurs partitions respectives. Lorsque la plage Z de la scène est très grande, d’autres plans fractionnés sont nécessaires. Par exemple, lorsque l’œil est très proche du plan terrestre, mais que les objets distants sont toujours visibles, plusieurs cascades peuvent être nécessaires. Diviser le frustum afin que davantage de fractionnements soient près de l'œil (où l'aliasing de perspective change le plus rapidement) est également utile. Lorsque la plupart de la géométrie est regroupée dans une petite section (par exemple, une vue aérienne ou un simulateur de vol) du frustum de vue, moins de cascades sont nécessaires.
Figure 4. Différentes configurations nécessitent des fractionnements frustum différents
(Gauche) Lorsque la géométrie a une plage dynamique élevée en Z, beaucoup de cascades sont requises. (Centre) Lorsque la géométrie a une plage dynamique faible en Z, on tire peu d'avantages de l'utilisation de plusieurs frustums. (Droite) Seules trois partitions sont nécessaires lorsque la plage dynamique est moyenne.
Orientation de la lumière et de la caméra
La matrice de projection de chaque cascade est ajustée de manière serrée autour de son sous-frustum correspondant. Dans les configurations où la caméra de vue et les directions lumineuses sont orthogonales, les cascades peuvent être ajustées étroitement avec peu de chevauchement. Le chevauchement devient plus grand au fur et à mesure que la lumière et la caméra de prise de vue se déplacent pour être dans l’alignement parallèle (Figure 5). Lorsque la lumière et la caméra de vue sont presque opposées (face à face), on parle alors de « frusta en duel », et c'est un scénario très difficile pour la plupart des algorithmes de gestion des ombres. Il n’est pas rare de limiter la lumière et la caméra afin que ce scénario ne se produise pas. Cependant, les CSMs surpassent de nombreux autres algorithmes dans ce scénario.
Figure 5. Le chevauchement des cascades augmente à mesure que la direction de la lumière devient parallèle à la direction de la caméra
De nombreuses implémentations CSM utilisent des frusta de taille fixe. Le nuanceur de pixels peut utiliser la profondeur Z pour indexer dans le tableau de cascades lorsque le frustum est divisé en intervalles de taille fixe.
Calcul d’une limite de View-Frustum
Une fois les intervalles de frustum sélectionnés, les sous-frusta sont créés en utilisant l'une des deux méthodes suivantes : adapter à la scène et adapter à la cascade.
Ajuster à la scène
Tous les frusta peuvent être créés avec le même plan proche. Cela force les cascades à se chevaucher. L’exemple CascadedShadowMaps11 appelle cette technique adaptée à la scène.
Ajuster à cascade
Vous pouvez également créer des frustas avec l’intervalle de partition réel utilisé comme plan proche et lointain. Cela provoque un ajustement plus serré, mais se dégrade pour s’adapter à la scène en cas de frusta en duel. Les exemples CascadedShadowMaps11 appellent cette technique adaptée à la cascade.
Ces deux méthodes sont présentées dans la figure 6. Optimiser l'affichage en cascade réduit le gaspillage de résolution. Le problème avec l'ajustement à la cascade est que la projection orthogonale augmente et se réduit en fonction de l'orientation du frustum de vue. La technique de mise à l'échelle à la scène ajuste la projection orthographique selon la taille maximale du frustum de vue, éliminant ainsi les artefacts qui apparaissent lorsque la caméra se déplace. Les techniques courantes pour améliorer les mappages de profondeur de l’ombre traitent les artefacts qui apparaissent lorsque la lumière se déplace dans la section « Déplacement de la lumière par incréments dimensionnés par texel ».
Figure 6. Ajuster à la scène ou ajuster à la cascade
Afficher la carte d’ombres
L’exemple CascadedShadowMaps11 restitue les mappages d’ombres dans une mémoire tampon volumineuse. Cela est dû au fait que PCF sur les tableaux de textures est une fonctionnalité Direct3D 10.1. Pour chaque cascade, une fenêtre d’affichage est créée qui couvre la section de la mémoire tampon de profondeur correspondant à cette cascade. Un nuanceur de pixels nul est lié, car seule la profondeur est nécessaire. Enfin, la fenêtre d’affichage et la matrice d’ombre correctes sont définies pour chaque cascade, car les cartes de profondeur sont rendues une à la fois dans la mémoire tampon d’ombre principale.
Afficher la scène
La mémoire tampon contenant les ombres est désormais liée au nuanceur de pixels. Il existe deux méthodes pour sélectionner la cascade implémentée dans l’exemple CascadedShadowMaps11. Ces deux méthodes sont expliquées avec du code de shader.
Sélection en cascade basée sur des intervalles
Figure 7. Sélection en cascade basée sur l’intervalle
Dans la sélection basée sur l’intervalle (figure 7), le vertex shader calcule la position dans l’espace monde du vertex.
Output.vDepth = mul( Input.vPosition, m_mWorldView ).z;
Le pixel shader reçoit la profondeur interpolée.
fCurrentPixelDepth = Input.vDepth;
La sélection en cascade basée sur des intervalles utilise une comparaison de vecteurs et un produit scalaire pour déterminer la cascade correcte. La CASCADE_COUNT_FLAG spécifie le nombre de cascades. La m_fCascadeFrustumsEyeSpaceDepths_data contraint les partitions du volume de visualisation. Après la comparaison, la fonction fComparison contient une valeur de 1 où le pixel actuel est supérieur à la barrière et une valeur de 0 lorsque la cascade actuelle est plus petite. Un produit point additionne ces valeurs dans un index de tableau.
float4 vCurrentPixelDepth = Input.vDepth;
float4 fComparison = ( vCurrentPixelDepth > m_fCascadeFrustumsEyeSpaceDepths_data[0]);
float fIndex = dot(
float4( CASCADE_COUNT_FLAG > 0,
CASCADE_COUNT_FLAG > 1,
CASCADE_COUNT_FLAG > 2,
CASCADE_COUNT_FLAG > 3)
, fComparison );
fIndex = min( fIndex, CASCADE_COUNT_FLAG );
iCurrentCascadeIndex = (int)fIndex;
Une fois la cascade sélectionnée, la coordonnée de texture doit être transformée en cascade correcte.
vShadowTexCoord = mul( InterpolatedPosition, m_mShadow[iCascadeIndex] );
Cette coordonnée de texture est ensuite utilisée pour échantillonner la texture avec la coordonnée X et la coordonnée Y. La coordonnée Z est utilisée pour effectuer la comparaison de profondeur finale.
sélection en cascade basée sur carte
La sélection basée sur la carte (Figure 8) teste les quatre côtés des cascades pour trouver la carte la plus étroite qui couvre le pixel spécifique. Au lieu de calculer la position dans l’espace mondial, le nuanceur de vertex calcule la position de l’espace d’affichage pour chaque cascade. Le nuanceur de pixels effectue une itération sur les cascades afin de mettre à l’échelle et de déplacer les coordonnées de texture afin qu’elles indexent la cascade actuelle. La coordonnée de texture est ensuite testée par rapport aux limites de texture. Lorsque les valeurs X et Y de la coordonnée de texture se trouvent à l’intérieur d’une cascade, elles sont utilisées pour échantillonner la texture. La coordonnée Z est utilisée pour effectuer la comparaison de profondeur finale.
Figure 8. Sélection en cascade basée sur une carte
sélection Interval-Based et sélection Map-Based
La sélection basée sur des intervalles est légèrement plus rapide que la sélection basée sur la carte, car la sélection en cascade peut être effectuée directement. La sélection basée sur la carte géographique doit croiser la coordonnée de texture avec les limites de cascade.
La sélection basée sur la carte utilise la cascade plus efficacement lorsque les mappages d’ombres ne s’alignent pas parfaitement (voir la figure 8).
Mélange entre Cascades
Les VSM (décrites plus loin dans cet article) et les techniques de filtrage telles que le PCF peuvent être utilisés avec des CSM basse résolution pour produire des ombres douces. Malheureusement, cela entraîne une couture visible (Figure 9) entre les couches en cascade, car la résolution ne correspond pas. La solution consiste à créer une bande entre les mappages d’ombres où le test d’ombre est effectué pour les deux cascades. Le nuanceur interpole ensuite linéairement entre les deux valeurs en fonction de l’emplacement du pixel dans la bande de fusion. Les exemples CascadedShadowMaps11 et VarianceShadows11 fournissent un curseur d’interface graphique graphique qui peut être utilisé pour augmenter et diminuer cette bande floue. Le nuanceur effectue une bifurcation dynamique afin que la grande majorité des pixels ne lisent que depuis la cascade actuelle.
Figure 9. Coutures en cascade
(Gauche) On peut voir une couture visible où se chevauchent les cascades. (Droite) Lorsque les cascades sont mélangées entre elles, aucune couture ne se produit.
Filtrage des cartes d'ombres
PCF
Le filtrage des cartes d’ombres ordinaires ne produit pas d’ombres douces et floues. Le matériel de filtrage flout les valeurs de profondeur, puis compare ces valeurs floues à l’espace clair texel. Le bord dur résultant du test de réussite/échec existe toujours. Le flou des cartes d’ombre ne sert qu’à déplacer par erreur le bord dur. PCF active le filtrage sur les cartes d'ombres. L’idée générale de PCF est de calculer un pourcentage du pixel dans l’ombre en fonction du nombre de sous-échantillonnages qui passent le test de profondeur sur le nombre total de sous-échantillonnages.
Le matériel Direct3D 10 et Direct3D 11 peut effectuer PCF. L’entrée d’un échantillonneur PCF se compose de la coordonnée de texture et d’une valeur de profondeur de comparaison. Par souci de simplicité, le PCF est expliqué avec un filtre à quatre points. L’échantillonneur de texture lit la texture quatre fois, similaire à un filtre standard. Toutefois, le résultat retourné est un pourcentage des pixels qui ont réussi le test de profondeur. La figure 10 montre comment un pixel qui passe l’un des quatre tests de profondeur est de 25 pour cent dans l’ombre. La valeur réelle retournée est une interpolation linéaire basée sur les coordonnées de sous-texel des lectures de texture pour produire un dégradé lisse. Sans cette interpolation linéaire, le PCF à quatre appuis ne peut retourner que cinq valeurs : { 0.0, 0.25, 0.5, 0.75, 1.0 }.
Figure 10. Image filtrée PCF, avec 25 % du pixel sélectionné couvert
Il est également possible d’effectuer un PCF sans prise en charge matérielle ou d'étendre le PCF à des noyaux plus volumineux. Certaines techniques échantillonnent même avec un noyau pondéré. Pour ce faire, créez un noyau (tel qu’un Gaussian) pour une grille N × N. Les poids doivent avoir une somme de 1. La texture est ensuite échantillonnée N2 fois. Chaque échantillon est redimensionné par les poids correspondants dans le noyau. L’exemple CascadedShadowMaps11 utilise cette approche.
Biais de profondeur
Le biais de profondeur devient encore plus important lorsque des noyaux PCF volumineux sont utilisés. Il n’est valide que pour comparer la profondeur de l’espace clair d’un pixel par rapport au pixel qu’il mappe à la carte de profondeur. Les voisins du texel de la carte de profondeur indiquent une position différente. Cette profondeur est susceptible d’être similaire, mais peut être très différente en fonction de la scène. La figure 11 met en évidence les artefacts qui se produisent. Une seule profondeur est comparée à trois texels voisins dans la carte d’ombres. L’un des tests de profondeur échoue de manière erronée, car sa profondeur ne correspond pas à la profondeur calculée de l’espace léger de la géométrie actuelle. La solution recommandée à ce problème consiste à utiliser un décalage plus important. Toutefois, un décalage trop important peut entraîner Peter Panning. Le calcul d’un plan proche serré et d’un plan lointain permet de réduire les effets de l’utilisation d’un décalage.
Figure 11. Auto-ombre erronée
L’auto-ombre erronée résulte de la comparaison des pixels dans la profondeur de l’espace de lumière aux texels dans la carte d'ombres qui ne correspondent pas. La profondeur dans l’espace lumineux est corrélée à l’ombre texel 2 dans la carte de profondeur. Texel 1 est supérieur à la profondeur de l’espace lumineux tandis que 2 est égal et 3 est inférieur. Texels 2 et 3 passent le test de profondeur, tandis que Texel 1 échoue.
Calcul d’un biais de profondeur par texel avec DDX et DDY pour les PCFs volumineux
Le calcul d’un biais de profondeur par texel avec ddx et ddy pour les pcF volumineux est une technique qui calcule le biais de profondeur correct (en supposant que la surface est planaire) pour le texel de la carte d’ombre adjacente.
Cette technique ajuste la profondeur de comparaison sur un plan à l’aide des dérivées. Étant donné que cette technique est complexe de calcul, elle doit être utilisée uniquement lorsqu’un GPU a des cycles de calcul à économiser. Lorsque des noyaux très volumineux sont utilisés, il peut s’agir de la seule technique qui fonctionne pour supprimer les artefacts d’auto-ombre sans provoquer l'effet de "Peter Panning".
La figure 12 met en évidence le problème. La profondeur dans l’espace lumineux est connue pour le texel qui est comparé. Les profondeurs de l’espace lumineux qui correspondent aux texels voisins dans la carte de profondeur sont inconnues.
Figure 12. Scène et carte de profondeur
La scène rendue est affichée à gauche, et la carte de profondeur avec un exemple de bloc texel est affiché à droite. Le texel de l’espace oculaire est mappé au pixel étiqueté D au centre du bloc. Cette comparaison est exacte. La profondeur correcte dans l’espace oculaire correspondant aux pixels voisins de D est inconnue. Le mappage des texels voisins vers l’espace oculaire n’est possible que si nous partons du principe que le pixel se rapporte au même triangle que D.
La profondeur du texel, qui est en corrélation avec la position dans l'espace de la lumière, est connue. La profondeur est inconnue pour les texels voisins dans la carte de profondeur.
À un niveau élevé, cette technique utilise les opérations ddx et hlSL ddy pour trouver la dérivée de la position de l’espace clair. Ceci est complexe parce que les opérations de dérivée retournent le gradient de la profondeur de l'espace de lumière par rapport à l'espace écran. Pour convertir cela en dégradé de la profondeur de l’espace lumineux par rapport à l’espace lumineux, une matrice de conversion doit être calculée.
Explication avec le code shader
Les détails du reste de l’algorithme sont donnés sous forme d’explication du code du nuanceur qui effectue cette opération. Ce code se trouve dans l’exemple CascadedShadowMaps11. La figure 13 montre comment les coordonnées de texture de l’espace clair correspondent à la carte de profondeur et comment les dérivés de X et Y peuvent être utilisés pour créer une matrice de transformation.
Figure 13. Espace d’écran à matrice d’espace clair
Les dérivés de la position de l’espace léger dans X et Y sont utilisés pour créer cette matrice.
La première étape consiste à calculer la dérivée de la position de l’espace d’affichage lumineux.
float3 vShadowTexDDX = ddx (vShadowMapTextureCoordViewSpace);
float3 vShadowTexDDY = ddy (vShadowMapTextureCoordViewSpace);
Les GPU de classe Direct3D 11 calculent ces dérivées en exécutant en parallèle des blocs de 2 × 2 pixels, puis en soustrayant les coordonnées de texture du voisin en X pour ddx et du voisin en Y pour ddy. Ces deux dérivés composent les lignes d’une matrice de 2 × 2. Dans sa forme actuelle, cette matrice peut être utilisée pour convertir des pixels voisins de l’écran en pentes d’espace clair. Toutefois, l’inverse de cette matrice est nécessaire. Une matrice qui transforme les pixels voisins de l’espace lumineux en pentes d’espace écran est nécessaire.
float2x2 matScreentoShadow = float2x2( vShadowTexDDX.xy, vShadowTexDDY.xy );
float fInvDeterminant = 1.0f / fDeterminant;
float2x2 matShadowToScreen = float2x2 (
matScreentoShadow._22 * fInvDeterminant,
matScreentoShadow._12 * -fInvDeterminant,
matScreentoShadow._21 * -fInvDeterminant,
matScreentoShadow._11 * fInvDeterminant );
Figure 14 : Espace clair vers l’espace écran
Cette matrice est ensuite utilisée pour transformer les deux texels ci-dessus et à droite du texel actuel. Ces voisins sont représentés comme un décalage par rapport au texel actuel.
float2 vRightShadowTexelLocation = float2( m_fTexelSize, 0.0f );
float2 vUpShadowTexelLocation = float2( 0.0f, m_fTexelSize );
float2 vRightTexelDepthRatio = mul( vRightShadowTexelLocation,
matShadowToScreen );
float2 vUpTexelDepthRatio = mul( vUpShadowTexelLocation,
matShadowToScreen );
Le rapport créé par la matrice est finalement multiplié par les dérivés de profondeur pour calculer les décalages de profondeur pour les pixels voisins.
float fUpTexelDepthDelta =
vUpTexelDepthRatio.x * vShadowTexDDX.z
+ vUpTexelDepthRatio.y * vShadowTexDDY.z;
float fRightTexelDepthDelta =
vRightTexelDepthRatio.x * vShadowTexDDX.z
+ vRightTexelDepthRatio.y * vShadowTexDDY.z;
Ces pondérations peuvent désormais être utilisées dans une boucle PCF pour ajouter un décalage à la position.
for( int x = m_iPCFBlurForLoopStart; x < m_iPCFBlurForLoopEnd; ++x )
{
for( int y = m_iPCFBlurForLoopStart; y < m_iPCFBlurForLoopEnd; ++y )
{
if ( USE_DERIVATIVES_FOR_DEPTH_OFFSET_FLAG )
{
depthcompare += fRightTexelDepthDelta * ( (float) x ) +
fUpTexelDepthDelta * ( (float) y );
}
// Compare the transformed pixel depth to the depth read
// from the map.
fPercentLit += g_txShadow.SampleCmpLevelZero( g_samShadow,
float2(
vShadowTexCoord.x + ( ( (float) x ) * m_fNativeTexelSizeInX ) ,
vShadowTexCoord.y + ( ( (float) y ) * m_fTexelSize )
),
depthcompare
);
}
}
PCF et CSM
PCF ne fonctionne pas sur les tableaux de textures dans Direct3D 10. Pour utiliser PCF, toutes les cascades sont stockées dans un grand atlas de texture.
Décalage basé sur les dérivées
L'ajout des décalages basés sur des dérivées pour les CSM présente certains défis. Cela est dû à un calcul dérivé au sein d’un contrôle de flux divergent. Le problème se produit en raison d’une façon fondamentale que les GPU fonctionnent. Les GPU Direct3D11 fonctionnent sur 2 × 2 quads de pixels. Pour effectuer une dérivée, les GPU soustraient généralement la valeur de la variable du pixel actuel à celle du pixel voisin. La façon dont cela se produit varie du GPU au GPU. Les coordonnées de texture sont déterminées par la sélection en cascade basée sur la carte ou par intervalle. Certains pixels dans un quad de pixels choisissent une cascade différente par rapport au reste des pixels. Cela entraîne des coutures visibles entre les cartes d’ombres, car les décalages dérivés sont désormais complètement incorrects. La solution consiste à effectuer la dérivée sur les coordonnées de texture de l’espace d’affichage lumineux. Ces coordonnées sont identiques pour chaque cascade.
Bourrage pour les noyaux PCF
Index des noyaux PCF en dehors d’une partition en cascade si la mémoire tampon d’ombre n’est pas rembourrée. La solution consiste à rembourrer le bord extérieur de la cascade en utilisant une demi-taille du noyau PCF. Cela doit être implémenté dans le shader qui sélectionne la cascade et dans la matrice de projection qui doit rendre la cascade suffisamment grande pour que la bordure soit conservée.
Carte de variance d'ombres
Pour plus d'informations, consultez les "Variance Shadow Maps" (VSMs) par Donnelly et Lauritzen, qui permettent d'activer le filtrage direct des cartes d'ombre. Lorsque vous utilisez des VSM, toutes les puissances du matériel de filtrage de texture peuvent être utilisées. Le filtrage triligne et anisotropique (Figure 15) peut être utilisé. En outre, les machines virtuelles virtuelles peuvent être floues directement par le biais de la convolution. Les machines virtuelles virtuelles présentent certains inconvénients ; deux canaux de données de profondeur doivent être stockés (profondeur et profondeur carrée). Lorsque les ombres se chevauchent, la fuite de lumière est courante. Ils fonctionnent bien avec des résolutions inférieures mais peuvent cependant être combinés avec des modules de sécurité cloud (CSM).
Figure 15 : Filtrage anisotropique
Détails de l’algorithme
Les VSM (Variational Shadow Maps) fonctionnent en représentant à la fois la profondeur et le carré de la profondeur sur une carte d’ombre à deux canaux. Cette carte d’ombre à deux canaux peut ensuite être floue et filtrée comme une texture normale. L’algorithme utilise ensuite l’inégalité de Chebychev dans le nuanceur de pixels pour estimer la fraction de la zone de pixels qui passerait le test de profondeur.
Le nuanceur de pixels récupère les valeurs de profondeur et de profondeur carrée.
float fAvgZ = mapDepth.x; // Filtered z
float fAvgZ2 = mapDepth.y; // Filtered z-squared
La comparaison de profondeur est effectuée.
if ( fDepth <= fAvgZ )
{
fPercentLit = 1;
}
Si la comparaison de profondeur échoue, le pourcentage du pixel allumé est estimé. La variance est calculée comme la moyenne des carrés moins le carré de la moyenne.
float variance = ( fAvgZ2 ) − ( fAvgZ * fAvgZ );
variance = min( 1.0f, max( 0.0f, variance + 0.00001f ) );
La valeur fPercentLit est estimée avec l’inégalité de Chebychev.
float mean = fAvgZ;
float d = fDepth - mean;
float fPercentLit = variance / ( variance + d*d );
Saignement léger
Le plus gros inconvénient des VSM est le saignement léger (figure 16). Des fuites de lumière se produisent lorsque plusieurs projeteurs d'ombres se masquent les uns les autres le long des arêtes. Les VSM ombrent les bords des ombres en fonction des disparités de profondeur. Lorsque les ombres se chevauchent, une disparité de profondeur existe au centre d’une région qui doit être ombrée. Il s’agit d’un problème lié à l’utilisation de l’algorithme VSM.
Figure 16 : Saignement de la lumière VSM
Une solution partielle au problème consiste à élever la fPercentLit à une puissance. Cela a pour effet d’atténuer le flou, ce qui peut provoquer des artefacts où la disparité de profondeur est faible. Il existe parfois une valeur magique qui atténue le problème.
fPercentLit = pow( p_max, MAGIC_NUMBER );
Une alternative à élever le pourcentage d'éclairage à une puissance consiste à éviter les configurations où les ombres se chevauchent. Même les configurations d’ombre hautement paramétrées ont plusieurs contraintes sur la lumière, la caméra et la géométrie. Le saignement léger est également réduit à l’aide de textures de résolution supérieure.
Les cartes d’ombres de variance en couches (LVSM) résolvent le problème au prix de diviser le frustum en couches perpendiculaires à la lumière. Le nombre de cartes requises serait considérable lorsque des CSM sont également utilisées.
En outre, Andrew Lauritzen, co-auteur du document sur les VSM et auteur d’un article sur les LVSM, a discuté de la combinaison de cartes d’ombre exponentielles (ESM) avec des VSM pour contrer le mélange de lumière dans un Forum Beyond3D.
Modules de sécurité virtuels avec des modules de sécurité cloud
L’exemple VarianceShadow11 combine les VSMs et les CSMs. La combinaison est assez simple. L’exemple suit les mêmes étapes que l’exemple CascadedShadowMaps11. Étant donné que PCF n’est pas utilisé, les ombres sont floues dans une convolution séparable à deux pas. Ne pas utiliser PCF permet également à l’exemple d’utiliser des tableaux de texture au lieu d’un atlas de texture. PCF sur les tableaux de textures est une fonctionnalité de Direct3D 10.1.
Dégradés utilisant des modèles de services cloud
L’utilisation de dégradés avec des CSM peut produire une couture le long de la bordure entre deux cascades, comme illustré dans la figure 17. L’exemple d’instruction utilise des dérivés entre les pixels pour calculer des informations, telles que le niveau mipmap, nécessaire par le filtre. Cela provoque un problème en particulier pour la sélection de mipmap ou le filtrage anisotropique. Lorsque les pixels d’un quad prennent différentes branches dans le nuanceur, les dérivés calculés par le matériel GPU ne sont pas valides. Cela entraîne une couture irrégulière le long de la carte d'ombre.
Figure 17 : Coutures sur les bordures en cascade dues à un filtrage anisotropique avec gestion de flux divergent
Ce problème est résolu en calculant les dérivés sur la position dans l’espace vue de la lumière. La coordonnée de l’espace vue de la lumière n’est pas spécifique à la cascade sélectionnée. Les dérivés calculés peuvent être mis à l’échelle par la partie d’échelle de la matrice de texture de projection au niveau mipmap correct.
float3 vShadowTexCoordDDX = ddx( vShadowMapTextureCoordViewSpace );
vShadowTexCoordDDX *= m_vCascadeScale[iCascade].xyz;
float3 vShadowTexCoordDDY = ddy( vShadowMapTextureCoordViewSpace );
vShadowTexCoordDDY *= m_vCascadeScale[iCascade].xyz;
mapDepth += g_txShadow.SampleGrad( g_samShadow, vShadowTexCoord.xyz,
vShadowTexCoordDDX, vShadowTexCoordDDY );
VSMs comparés aux ombres standard avec PCF
Les machines virtuelles et PCF tentent d’estimer la fraction de la zone de pixels qui réussirait le test de profondeur. Les VSM fonctionnent avec le matériel de filtrage et peuvent être floutés avec des noyaux séparables. Les noyaux de convolution séparables sont considérablement moins chers à implémenter qu’un noyau complet. En outre, les VSM comparent une profondeur dans l'espace lumineux à une valeur de la carte de profondeur de cet espace. Cela signifie que les machines virtuelles n’ont pas les mêmes problèmes de décalage que PCF. Techniquement, les VSM échantillonnent en profondeur sur une plus grande zone et effectuent une analyse statistique. Cela est moins précis que PCF. Dans la pratique, les VSM effectuent un très bon travail de fusion, ce qui entraîne une compensation moins importante. Comme décrit ci-dessus, le principal inconvénient des VSM est le saignement léger.
Les VSM et PCF représentent un compromis entre la puissance de calcul GPU et la bande passante de texture GPU. Les VSM nécessitent davantage de calculs mathématiques pour calculer la variance. PCF nécessite davantage de bande passante de mémoire de texture. Les noyaux PCF volumineux peuvent rapidement devenir des goulots d’étranglement par la bande passante de texture. Avec la puissance de calcul GPU qui augmente plus rapidement que la bande passante GPU, les VSM deviennent plus pratiques des deux algorithmes. Les VSM s’affichent également mieux avec les mappages d’ombres à résolution inférieure en raison de la fusion et du filtrage.
Résumé
Les CSM offrent une solution au problème d’aliasing de perspective. Il existe plusieurs configurations possibles pour obtenir la fidélité visuelle nécessaire pour un titre. PCF et VSMs sont largement utilisés et doivent être combinés avec les CSMs pour réduire l'aliasing.
References
Donnelly, W. et Lauritzen, A. Variance shadow maps. Dans SI3D '06 : Actes du symposium de 2006 sur le graphisme et les jeux interactifs en 3D. 2006. pp. 161-165. New York, NY, États-Unis : ACM Press.
Lauritzen, Andrew et McCool, Michael. Cartes d'ombre de variance en couches. Actes de l’interface graphique 2008, du 28 au 30 mai 2008, Windsor, Ontario, Canada.
Engel, Wolfgang F. Section 4. Cartes d’ombre en cascade ShaderX5 , Advanced Rendering Techniques, Wolfgang F. Engel, Ed. Charles River Media, Boston, Massachusetts. 2006. pp. 197-206.