Pesquisar em Unity

Gráficos XR: melhores práticas e soluções alternativas

Last updated: January 2019

O que você encontrará nesta página: diversas dicas sobre como otimizar seus shaders e como usar a pilha de pós-processamento com maior eficiência. Este é um ótimo artigo para ler se você já tem experiência em programação com Unity e estiver desenvolvendo ou desenvolverá conteúdo em XR (VR e/ou AR).

Atualmente, Unity é compatível com quatro métodos de renderização para XR: multi-pass, single-pass, o recentemente lançado single-pass instancing e Android single-pass (que é semelhante ao single-pass instancing).

Multi-pass
  • Requer duas passagens do gráfico de cena: para cada uma das duas texturas que representam os olhos, você deve renderizar seus objetos/cenas separadamente.
  • Não compartilha o trabalho GPU entre as texturas, o que torna o caminho de renderização menos eficiente; mas funciona por padrão na maioria dos dispositivos, portanto, requer poucas alterações.
  • Partilha o culling e parte da renderização da geração de sombras.
Single-pass
  • Com este método, duas texturas são embaladas em uma textura maior (referida como uma textura de largura dupla).
  • Para o primeiro objeto a ser desenhado, a viewport é definida para o lado esquerdo, o objeto é desenhado; então, a viewport muda para o lado direito e o objeto é desenhado novamente.
  • O gráfico de cena é executado apenas uma vez, então o processo é mais rápido na CPU. No entanto, necessita muitas mudanças de estado do GPU para concluir o processo.

gráficos xr no unity

Um exemplo simples de renderização estéreo single-pass

Single-pass instancing
  • Disponível na versão 2017.2 e superior.
  • As duas texturas que representam os olhos estão ambas contidas em uma matriz de textura (duas seções do mesmo arranjo de textura).
  • Quando se configura a viewport, aplica-se automaticamente a ambas as partes. Quando você faz um desenho, gera-se um desenho de instância que é o dobro do normal. Dependendo da instância, Unity determina a seção a renderizar.
  • Implica a mesma quantidade de trabalho de GPU, mas menos draw calls e trabalho para a CPU, por isso é significativamente mais eficiente.
  • Disponível para:
    • Windows 10 com D3D11 e drivers de gráficos recentes.
    • Hololens.
    • PS4.
  • Voltaremos a multi-pass se a extensão não for suportada no dispositivo de destino
  • DrawProceduralIndirect (...) requer mudanças manuais.

gráficos xr no unity

Um exemplo de single-pass instancing

Adicione estas macros em seus shaders se você usar single-pass instancing

Se você escolhe single-pass instancing, recomendamos que adicione as seguintes macros aos seus shaders de vértices e de fragmentos. O procedimento é muito simples, e todos os shaders integrados a Unity são compatíveis.

Shader de vértices

gráficos xr no unity

Código Shader sem macros.

gráficos xr no unity

O mesmo código com a primeira macro adicionada ...

gráficos xr no unity

A segunda macro ...

gráficos xr no unity

A terceira...

gráficos xr no unity

E a quarta macro adicionada.

Se você precisa usar unit_StereoEyeIndex no shader de fragmentos, você deve fazer isto:

gráficos xr no unity

Algumas diferenças ao usar RenderScale vs. RenderViewportScale

Digamos que você deseja redimensionar uma textura de 1 a 0,5. Se você fizer isso usando RenderScale , a textura original será excluída e uma nova textura será criada no tamanho de um quarto do original, pois é 0,5 em cada dimensão.

Esta é uma operação custosa para fazer dinamicamente enquanto o seu jogo está sendo executado, e é por isso que RenderViewportScale é uma solução mais eficiente, pois define a Viewport para uma porção menor da mesma textura e renderiza em função, assim:

gráficos xr no unity

Isso é muito mais eficiente, mas apresenta alguns problemas, pois você está usando apenas uma parte da textura (veja a seção mais abaixo com mais dicas em RenderViewportScale ).

Assim, RenderScale elimina efetivamente, e depois cria novas texturas, enquanto que RenderViewportScale modifica a viewport. Algumas outras diferenças a ter em conta:

  • XRSettings.eyeTextureResolutionScale é para tamanho de textura real enquanto XRSettings.renderViewportScale se aplica à viewport usada para renderização.
  • XRSettings.renderViewportScale não é suportado usando renderização diferida.
  • Como a escala é aplicada em ambas as dimensões, um valor de 0,5 gera uma imagem que é 25% do tamanho original.
Pilha pós-processamento em XR: desafios e soluções

A última versão da excelente pilha de pós-processamento está aqui. Usar a pilha para o conteúdo XR apresenta alguns desafios. Na próxima seção, você descobrirá quais soluções você pode encontrar no momento.

Desafio

Para usar muitos dos últimos efeitos de pós-processamento, você precisará renderizar para um objetivo de renderização intermédio baseado no tamanho e propriedades do objetivo fonte:

  • No caso de largura dupla, a textura de renderização tem pelo menos o dobro da largura da porção de olho individual.
  • Com single-pass instancing e Android single-pass semelhante, precisamos fazer um arranjo de textura, com uma seção por olho.

Solução

  • Unity oferece XRSettings.eyeTextureDesc para permitir gerar o formato de textura do espaço de tela correto (versão 2017.2 e posterior).
  • Isso retorna um RenderTextureDescriptor obtido do gerenciador XRTexture , da engine o que significa que está configurado para combinar as texturas gerenciadas pela engine.
  • Você também pode consultar RenderTextureDescriptor de uma textura fonte, se estiver disponível. Se você estiver usando a antiga infraestrutura MonoBehaviour.OnRenderImage , por exemplo, você tem essa textura fonte e você e pode obter diretamente o descritor.
  • Ao usar eyeTextureDesc , você pode substituir todas as alocações de RenderTexture com o RenderTextureDescriptor fornecido, que é mais eficiente do que gerar parâmetros manualmente.
  • RenderTextureDescriptor é uma API mais simples que corresponde ao que fazem as API subjacentes. Se você usar argumentos explícitos, Unity os embala em RenderTextureDescriptor e passa para a engine principal (em RenderTexture.GetTemporary ou CommandBuffer.GetTemporaryRT ). Você está gerenciando isso no lado do script, em vez de ter a camada intermediária fazendo todo o gerenciamento para você.

Desafio

Em XR, há uma diferença entre o tamanho físico da textura de renderização e o tamanho lógico da tela/olho.

Solução

  • Para a atribuição de textura de renderização intermediária, use eyeTextureDesc porque atribui essas texturas físicas.
  • Se você tem lógica de script ou shader com base no tamanho da tela (por exemplo, se você usa parâmetros de tela em um shader ou se cria uma pirâmide de textura), você deseja baseá-lo em tamanho lógico. Você pode fazer isso usando XRSettings.eyeTextureHeight e XRSettings.eyeTextureWidth .
  • Estes representam tamanhos de textura "por olho", que são necessários para conhecer o tamanho da tela em que você está operando.
  • Observe que, no caso de largura dupla eyeTextureWidth , não é exatamente a metade da largura de eyeTextureDesc . Isso ocorre porque o descritor, para alocar texturas, duplica a largura e, em seguida, comprime ligeiramente para garantir que seja adequado para o mapeamento MIP.

Aqui está um exemplo de código que você poderia ter usado antes da disponibilidade do EyeTextureWidth, para determinar a largura que você queria para a tela:

gráficos xr no unity

Agora, basta recuperar a largura da tela de eyeTexturewidth e usá-la para algo como uma relação de tela. Veja o exemplo de script abaixo:

gráficos xr no unity

Desafio

Como você garante que suas coordenadas de textura são corretas para estéreo e aplicam-se à saída para do olho correto?

Se você estiver trabalhando com uma textura de largura dupla, certifique-se de que suas coordenadas de textura são tiradas da metade correta da textura (cada metade corresponde a um olho).

Solução

Você precisará de um corrector de coordenadas de textura por olho e, para isso, Unity oferece duas soluções:

1. TRANSFORM_TEX macro

  • This is a macro that works with _ST properties in ShaderLab. It’s most commonly used with MainTex_ST.
  • A propriedade _ST é atualizada antes de cada olho no modo de largura dupla single-pass, transformando suas coordenadas de textura na área correta para o olho. Além disso, RenderViewportScale será usado automaticamente.

gráficos xr no unity

  • Unity will populate _ST shader properties if you’re using Graphics.Blit or CommandBuffer.Blit:
    • MainTex_ST está sempre preenchido.
    • Outras propriedades _ST serão preenchidas se a textura for uma textura XR (VRTextureUsage!=None).
  • Esta macro não funcionará com procedimentos de blit personalizados, como BlitFullScreenTriangle na última pilha de pós-processamento.

2. unit_StereoScaleOffset e UnityStereoTransformScreenSpaceTex/TransformStereoScreenSpaceTex funções auxiliares

unity_StereoScaleOffset é uma matriz de float4s:

  • UnityStereoTransformScreenSpaceTex
  • TransformStereoScreenSpaceTex

É definido como parte do bloco de constante single-pass ( UnityStereoGlobals ). É indexado com Unity_StereoEyeIndex .

No caso de largura dupla, unity_StereoEyeIndex está vinculado a um buffer constante, cada draw atualiza o olho correto. O valor do olho esquerdo é colocado em um buffer constante, o olho esquerdo é trabalhado. Então o valor do olho direito é colocado em um buffer constante e o olho direito é trabalhado. As instâncias do shader saberão que, para cada draw, eles podem pesquisar o buffer constante e encontrar o valor correto para unity_StereoEyeIndex .

gráficos xr no unity

Uma vez que você sabe que unity_StereoEyeIndex está preenchido corretamente, podemos usá-lo com a garantia de estar selecionando o elemento certo de unity_StereoScaleOffset .

gráficos xr no unity

Há alguns inconvenientes ao usar unity_StereoScaleOffset :

  • Disponível apenas para single-pass. Deve usar os métodos do assistente.
  • O uso direto leva a multi-pass e monoscópico e resulta em erros de compilação do shader. Além disso, RenderViewportScale não é considerado.

Como você pode garantir que seus arranjos de texturas estejam corretamente declarados e que a seleção seja feita a partir da seção correta?

Solução

Use UNITY_DECLARE_SCREENSPACE_TEXTURE . As linguagens de Shader tratam os arranjos de textura de maneira diferente das texturas "normais". Single-pass instancing e Android single-pass usam arranjos de textura, portanto, precisamos ter certeza de que declaramos nossas texturas corretamente.

gráficos xr no unity

Semelhante à largura dupla, precisamos trabalhar a partir da porção correta do olho; essas porções de olho são colocadas nas seções do arranjo de textura. Podemos extrair a seção correta de unit_StereoEyeIndex e usando a macro UNITY_SAMPLE_SCREENSPACE_TEXTURE.

gráficos xr no unity

Gerenciando o RenderViewportScale: alguns pontos a considerar

  • unit_StereoScaleOffset não oferece suporte.
  • A maioria dos efeitos pós-processamento usam CommandBuffer.Blit / Graphics.Blit, o que significa que podem usar_MainTex_ST (e outros métodos _ST) para suportar RenderViewportScale.
  • Mas com v.2 da pilha de pós-processamento da Unity, você não pode aplicar esses métodos. Para resolver o problema, você deve fornecer seu próprio suporte. Isso é bastante simples, porque a v.2 da pilha usa sua própria versão da infraestrutura de shader, o que significa que é fácil de substituir. Basta fazer o seguinte:

    No lado do shader:

    • Crie uma nova constante: Declare "float rvsGlobal" dentro xrLib.hlsl
    • Reformule TransformStereoScreenSpaceTex para utilizar rvsGlobal

    No lado do script:

    • Vinculeo valor RenderViewportScale como uma propriedade global do script
    • Use Shader.SetGlobalFloat

    gráficos xr no unity

Clamping estéreo

Se você estiver trabalhando com elementos de tela em um shader, certifique-se de não aplicar suas configurações no olho errado no modo de largura dupla single-pass ou fora da área válida RenderViewportScale . Aqui é onde intervém UnityStereoClamp : esta propriedade garante que a parte correta da textura seja trabalhada.

gráficos xr no unity

O uso é muito fácil, embora seja necessária uma inspeção manual.

Onde quer que você esteja diferindo a coordenada de textura gerada pela interpolação, você provavelmente precisará usar Unity.StereoClamp().

  • Tenha cuidado com os efeitos da amostragem da mesma coordenada devido ao clamping.
  • Não use isso no shader de vértices.
Mais algumas dicas antes de irmos:
  • Certifique-se de ponderar se o efeito de pós-processamento que você está usando faz sentido para o 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.
  • Se você estiver usando multi-pass e mantém texturas históricas, você precisa de um conjunto de texturas históricas por olho.
    • Singular history set could/will lead to sharing history between eyes!
    • Works automatically with single-pass
  • Se você estiver tendo problemas, experimente os diferentes modos de renderização estéreo.
    • Nature of artifact can provide hints on where things might be going wrong.
Mais recursos

Queremos saber! Você gostou deste conteúdo?

Sim, continue. Bem. Poderia ser melhor
Eu entendi

Usamos cookies para garantir a melhor experiência no nosso site. Visite nossa página da política de cookies para obter mais informações.