Cherchez Unity

Graphismes XR : bonnes pratiques et solutions

Last updated: January 2019

Ce que vous trouverez sur cette page : des tonnes d'astuces sur la façon d'optimiser vos shaders et la pile de post-traitement le plus efficacement possible. Cet article sera très utile pour les programmeurs expérimentés travaillant sur Unity qui sont ou seront amenés à développer du contenu en XR (RV et/ou RA).

Uity prend actuellement en charge quatre méthodes pour la XR : multi-pass, single-pass, l'instance single-pass et Android single-pass (similaire à l'instance single-pass).

Multi-pass
  • Nécessite de travailler deux fois les graphes de la scène : pour chacune des deux textures qui représentent les yeux, vous devez rendre vos objets/scènes séparément.
  • Ne partage pas le travail du GPU pour les textures, ce qui rend cette solution de rendu peu efficace. Mais elle fonctionne par défaut sur la plupart des appareils et nécessite donc peu de modifications.
  • Partage la détermination des surfaces et une partie du rendu de génération des ombres.
Single-pass
  • Avec cette méthode, deux textures sont emballées dans une texture plus grande (texture double).
  • Pour le premier objet à être tracé, la fenêtre est placée à gauche, l'objet est tracé ; puis la fenêtre passe à droite et l'objet est à nouveau tracé.
  • Les graphes de la scène sont travaillés une seule fois, ce qui permet un traitement plus rapide par le processeur. Cela nécessite toutefois de nombreux changements d'état de GPU.

graphismes unity xr

Un exemple simple de rendu stéréo single-pass

Instances single-pass
  • Disponible à partir de la version 2017.2.
  • Les deux textures qui représentent les yeux sont contenues dans n même niveau de textures (deux sections du même niveau de texture).
  • Lorsque la fenêtre est paramétrée, les réglages s'appliquent automatiquement aux deux sections. Lorsque vous créez un tracé, une instance est générée. En fonction de l'instance, Unity détermine quelle section rendre.
  • Implique la même quantité de travail niveau GPU, mais mois de requêtes et de travail pour le processeur, ce qui améliore significativement les performances.
  • Disponible pour :
    • Windows 10 avec D3D11 et pilotes graphiques récents.
    • Hololens.
    • PS4.
  • Passe en multi-pass si l'extension n’est pas prise en charge sur l'appareil cible.
  • DrawProceduralIndirect(...) nécessite des modifications manuelles.

graphismes unity xr

Un exemple d'instance single-pass

Ajoutez ces macros à vos shaders si vous utilisez les instances single-pass

Si vous optez pour les instances single-pass, nous vous recommandons d'ajouter les macros suivantes à votre vertex et à vos shaders de fragments. La procédure est très simple et tous les shaders intégrés à Unity sont compatibles.

Pour les shaders vertex :

graphismes unity xr

Code de shader sans macros.

graphismes unity xr

Le même code avec la première macro ajoutée...

graphismes unity xr

La deuxième macro...

graphismes unity xr

La troisième...

graphismes unity xr

Et la quatrième.

Si vous devez utiliser unity_StereoEyeIndex dans le shader de fragment, procédez comme suit :

graphismes unity xr

Quelques différences entre RenderScale et RenderViewportScale

Imaginons que vous vouliez redimensionner une texture de 1 à 0,5. Si vous utilisez RenderScale, la texture originale sera supprimée et une nouvelle texture d'un quart de la taille de l'originale sera créé, car celle-ci fait 0,5 dans chaque dimension.

Il s'agit d'une opération coûteuse en ressources à effectuer de manière dynamique lorsque votre jeu est en cours d'exécution. C'est la raison pour laquelle RenderViewportScale est une solution plus efficace. Elle définit la fenêtre sur une portion plus petite de la même texture et rend en fonction, de cette manière :

graphismes unity xr

Procéder ainsi est bien plus efficace, mais peut impliquer des difficultés car vous utilisez uniquement une portion de la texture (consultez la section suivante, qui comprend plus d'astuces sur RenderViewportScale).

RenderScale supprime puis crée de nouvelles textures, tandis que RenderViewportScale modifie la fenêtre. Voici quelques autres différences à connaître :

  • XRSettings.eyeTextureResolutionScale est pour la talle réelle de la texture, tandis que XRSettings.renderViewportScale s'applique à la fenêtre utilisée pour le rendu.
  • XRSettings.renderViewportScale n'ets pas pris en charge lors de l'utilisation du rendu en différé.
  • L'échelle s'appliquant dans les deux dimensions, une valeur de 0,5 génèrera une image représentant 25 % de la taille originale.
La pile de post-traitement en XR : difficultés et solutions

La dernière version de l’extraordinaire pile de post-traitement est disponible. L'utilisation de la pile avec des contenus XR entraîne quelques difficultés. Elles sont évoquées dans la prochaine section, ainsi que les solutions qui sont désormais à votre disposition.

Difficulté

Pour utiliser les derniers effets de post-traitement, vous devez utiliser une cible de rendu intermédiaire basée sur les propriétés et la taille source :

  • En cas de texture double, la texture de rendu est fait au moins le double de la largeur de la portion d’œil individuelle.
  • Avec l'instance single-pass et le système similaire Android single-pass, nous devons créer une couche de texture avec une section par œil.

Solution

  • Unity a conçu XRSettings.eyeTextureDesc pour vous permettre de générer plus rapidement le format de texture d'espace écran correct (version 2017.2 et plus récentes).
  • Un RenderTextureDescriptor est alors issu du manager XRTexture du moteur, ce qui signifie qu'il est configuré de manière à correspondre aux textures gérées par le moteur.
  • Vous pouvez également appeler RenderTextureDescriptor via une texture source, si elle est disponible. Si vous utilisez l'ancienne infrastructure MonoBehaviour.OnRenderImage, par exemple, vous disposerez de cette texture source et vous pourrez en tirer le descripteur.
  • Utilisez eyeTextureDesc pour remplacer toutes vos allocations RenderTexture avec l'élément RenderTextureDescriptor fourni, ce qui est bien plus efficace que générer manuellement des paramètres.
  • RenderTextureDescriptor est une API plus simple qui correspond à ce que font les API sous-jacentes. Si vous utilisez des arguments explicites, Unity les emballe dans un RenderTextureDescriptor, puis les passe dans le moteur (dans RenderTexture.GetTemporary ou CommandBuffer.GetTemporaryRT). Vous gérez ce processus côté code au lieu de laisser la couche intermédiaire s'en charger.

Difficulté

En XR, il existe une différence entre la taille physique de la texture rendue et la taille logique visible à l'écran/à l'oeil.

Solution

  • Concernant l'allocation de texture rendue intermédiaire, utilisez eyeTextureDesc pour allouer ces textures physiques.
  • Si vous avez une logique de shader ou de script basée sur la taille de l'écran (par exemple si vous utilisez les paramètres de la taille de l'écran dans un shader ou si vous créez une pyramide de texture), basez-vous sur la taille logique. Pour ce faire, vous pouvez utiliser XRSettings.eyeTextureHeight et XRSettings.eyeTextureWidth.
  • Cela représente les tailles de texture « par œil », elles sont nécessaires pour connaître la taille de l'écran utilisé.
  • En cas de double texture, eyeTextureWidth ne correspond pas exactement à la moitié de la largeur de eyeTextureDesc. Cela s'explique car le descripteur, pour allouer les textures, double la largeur puis la compresse légèrement afin de s'assurer qu'elle est adaptée au MIP mapping.

Voici un exemple de code que vous auriez pu utiliser avant d'avoir accès à eyeTextureWidth pour déterminer la largeur voulue pour votre écran :

graphismes unity xr

Désormais, il vous suffit de récupérer la largeur de l'écran via eyeTexturewidth et de l'utiliser pour un ratio d'écran par exemple. Découvrez les exemples de scripts ci-dessous :

graphismes unity xr

Difficulté

Comment vous assurer que les coordonnées de votre texture sont correctes pour la stéréo et s'appliquent à la sortie pour l'oeil correct ?

Si vous travaillez à partir d'une texture double largeur, vous devez vous assurer que les coordonnées de votre texture sont basées sur la bonne moitié de la texture (chaque moitié correspond à un œil).

Solution

Vous aurez besoin d'un correcteur de coordonnées de texture par œil. Unity vous propose deux solutions :

1. La macro TRANSFORM_TEX

  • This is a macro that works with _ST properties in ShaderLab. It’s most commonly used with MainTex_ST.
  • La propriété _ST est actualisée avant chaque œil en mode single-pass double largeur, modifiant les coordonnées de votre texture pour la gamme adaptée à votre œil. Elle gère également RenderViewportScale automatiquement.

graphismes unity xr

  • Unity will populate _ST shader properties if you’re using Graphics.Blit or CommandBuffer.Blit:
    • MainTex_ST est toujours peuplée.
    • Les autres propriétés _ST seront remplies si la texture est une texture XR (VRTextureUsage!=None).
  • Cette macro ne fonctionne pas avec les procédures blit personnalisées telles que BlitFullScreenTriangle dans la toute dernière pile de post-traitement.

2. Les fonctions d'assistance unity_StereoScaleOffset et UnityStereoTransformScreenSpaceTex/TransformStereoScreenSpaceTex

unity_StereoScaleOffset est un niveau de float4s :

  • UnityStereoTransformScreenSpaceTex
  • TransformStereoScreenSpaceTex

Considéré comme une partie du bloc constant single-pass (UnityStereoGlobals). Indexé avec Unity_StereoEyeIndex.

Lorsqu'une double largeur est utilisée, unity_StereoEyeIndex est liée à un buffer constant, puis chaque requête actualise le bon œil. La valeur de l'oeil gauche est placée dans un buffer constant, l'oeil gauche est travaillé. Puis la valeur de l'oeil droit est placée dans un buffer constant et l'oeil droit est travaillé. Les instances de shader sauront que, pour chaque requête, elles pourront chercher dans le buffer constant et trouver la valeur correcte pour unity_StereoEyeIndex.

graphismes unity xr

Une fois que vous savez que unity_StereoEyeIndex est correctement peuplée, vous pouvez être assuré qu'elle sélectionne le bon élément dans unity_StereoScaleOffset.

graphismes unity xr

Il y a quelques inconvénients à utiliser unity_StereoScaleOffset :

  • Disponible uniquement pour le mode single-pass. Vous devez utiliser les méthodes de l'assistant.
  • L'utilisation entraînera les modes multi-pass et monoscopic et génèrera des erreurs de compilation de shader. En outre, RenderViewportScale n'est pas prise en compte.

Comment vous assurer que les niveaux de votre texture sont correctement déclarées, et que vous travaillez à partir de la bonne section ?

Solution

Utilisez UNITY_DECLARE_SCREENSPACE_TEXTURE. Les langues de shader traitent les niveaux de texture différemment des textures « normales ». Les instances Single-pass et Android single-pass utilisant les niveaux de texture, nous devons nous assurer que nous déclarons nos textures correctement.

graphismes unity xr

Comme pour la double largeur, nous devons travailler à partir de la bonne portion de l'oeil. Ces portions des yeux sont placées dans les couches du niveau de texture. Nous pouvons récupérer la bonne couche via unity_StereoEyeIndex et en utilisant la macro UNITY_SAMPLE_SCREENSPACE_TEXTURE.

graphismes unity xr

Gérer RenderViewportScale : quelques éléments à garder à l'esprit

  • unity_StereoScaleOffset n'offre aucune prise en charge.
  • La plupart des effets de post-traitement utilisent CommandBuffer.Blit/Graphics.Blit, ce qui signifie qu'ils peuvent également utiliser _MainTex_ST (et d'autres méthodes _ST) pour prendre en charge RenderViewportScale.
  • Mais la version 2 de la pile de post-traitement de Unity ne vous permet pas d'utiliser ces méthodes. Elle utilise sa propre version de l'infrastructure de shader, vous offrant ainsi une solution assez simple. Voici comment procéder :

    Côté shader :

    • Créez une nouvelle constante : déclarez "float rvsGlobal" dans xrLib.hlsl
    • Retravaillez TransformStereoScreenSpaceTex pour utiliser rvsGlobal

    Côté script :

    • Liez la valeur RenderViewportScale en tant que propriété globale via le script
    • Utilisez Shader.SetGlobalFloat

    graphismes unity xr

Clamping stéréo

Si vous travaillez des éléments espace écran dans un shader, assurez-vous dene pas appliquer vos réglages au mauvais œil en mode single-pass double largeur ou en dehors de la zone RenderViewportScale valide. C'est là qu'intervient UnityStereoClamp : cette propriété s'assure que la portion correcte de la texture est travaillée.

graphismes unity xr

L'utilisation est très simple, bien que l'inspection manuelle soit requise.

Pour changer de source et ne plus utiliser les coordonnées de texture générées par interpolation, vous pouvez utiliser Unity.StereoClamp().

  • Soyez attentif aux effets pouvant survenir à cause du sampling si vous utilisez les coordonnées.
  • N'utilisez pas cette fonction dans le shader de vertex.
Quelques astuces supplémentaires avant de vous laisser :
  • Assurez-vous que l'effet de post-traitement que vous utilisez est adapté à la XR.
    • Most temporal effects add blurriness and latency
    • Simulating depth of field, a property of physical cameras, in a headset, which is simulating the human eye, will most likely cause nausea.
  • Si vous utilisez le mode multi-pass et que vous conservez les anciennes textures, vous aurez besoin d'un ensemble de textures par œil.
    • Singular history set could/will lead to sharing history between eyes!
    • Works automatically with single-pass
  • Si vous rencontrez des difficultés, essayez les différents modes de rendu stéréo.
    • Nature of artifact can provide hints on where things might be going wrong.
Plus de ressources

Dites-nous si vous avez aimé ce contenu !

Oui, continuez comme ça Ça pourrait être mieux
Compris

Ce site utilise des cookies dans le but de vous offrir la meilleure expérience possible. Consultez la page de politique des cookies pour en savoir plus.