Resumo e conhecimento básico de escrita de Shader

Por que incomoda?

Por que já existe um editor visual de Shader como o ShaderForge ? Por que a Asset Store já tem tantos componentes legais de Shader para download? Ainda é necessário aprender a escrever Shader?


2014-0718-1607-11-33.png
  • Porque as ferramentas/componentes do Shader acima existem, em última análise, na forma de arquivos Shader.
  • Os desenvolvedores/artistas técnicos precisam ser capazes de realizar análises funcionais, avaliação de eficiência, seleção, otimização, compatibilidade e até depuração do Shader.
  • Para necessidades especiais, pode ser mais prático e eficiente escrever o Shader diretamente.

Resumindo, escrever Shader é importante; mas se é urgente ou não depende das necessidades do projeto.

Escopo envolvido

Este artigo discute apenas o conhecimento e o uso do Unity ShaderLab. mas,

  • Os conceitos básicos relacionados à renderização não são discutidos. Para conceitos básicos, consulte artigos como Visão geral do pipeline de renderização .
  • Nem discute técnicas específicas de renderização.
  • Há muitas diferenças na arquitetura de hardware de GPUs de dispositivos móveis e GPUs de dispositivos de desktop. Para obter detalhes, consulte o capítulo "Breve visão geral da arquitetura de GPU de dispositivos móveis" abaixo.

Usar sombreador


2014-0720-1007-25-36.png


Conforme mostrado na imagem acima, pode ser resumido em uma frase:

  1. Existe MeshRenderer no GameObject,
  2. Há uma lista de materiais no MeshRenderer,
  3. Existe apenas um Shader em cada Material;
  4. Material expõe as propriedades ajustáveis ​​do Shader no editor.

Portanto, a chave é como escrever Shader.

Noções básicas de sombreador

editor

Na verdade, é satisfatório usar o MonoDevelop, um IDE anti-humano, para escrever o Shader. Há destaque de sintaxe, mas não há dicas de sintaxe.
Se você estiver acostumado com o Visual Studio, poderá implementar o realce de sintaxe dos arquivos .Shader da seguinte maneira.

  • Baixe o arquivo de palavras-chave usertype.dat adicionado pelo próprio autor donaldwu . Inclui algumas palavras-chave do Unity ShaderLab e todas as palavras-chave do HLSL. Palavras-chave serão adicionadas no futuro.
  • Coloque o usertype.dat baixado na pasta Microsoft Visual Studio xx.x\CommonX\IDE\;
  • Abra o VS, Ferramentas>Opções>Editor de Texto>Extensão de arquivo, preencha "shader" na extensão, selecione VC++ como editor e clique em Adicionar;
  • Reinicie o VS, pronto.

Sombreador

Shader "ShaderLab Tutorials/TestShader"
{
    // ...
}

2014-0720-1707-17-42.png


O nome do shader determinará diretamente o caminho onde o shader aparece no material.

SubShader

Shader "ShaderLab Tutorials/TestShader" {
    SubShader
    {
        //...
    }
}

Um Shader possui vários SubShaders. Um SubShader pode ser entendido como um esquema de renderização de um Shader . Ou seja, o SubShader foi escrito para diferentes situações de renderização. Cada Shader tem pelo menos um SubShader e, teoricamente, pode haver um número infinito, mas dois ou três são suficientes.
Apenas um SubShader será selecionado para renderização por vez. As regras específicas de seleção de SubShader incluem:

  • Selecione de cima para baixo
  • Rótulo SubShader, rótulo Pass
    • Se está em conformidade com o "caminho de renderização do Unity" atual
    • Se corresponde ao ReplacementTag atual
  • O SubShader é compatível com a GPU atual?
  • espere

O primeiro SubShader selecionado de acordo com esta regra será usado para renderização, e o SubShader não selecionado será ignorado para esta renderização.

SubShaderTag

Shader "ShaderLab Tutorials/TestShader" {
    SubShader
    {
        Tags { "Queue"="Geometry+10" "RenderType"="Opaque" }
        //...
    }
}

O SubShader pode ter tags (Tags) definidas dentro dele. Tag especifica a ordem de renderização (tempo) deste SubShader, bem como algumas outras configurações.

  • "RenderType"Rótulo. O Unity pode substituir todos os Shaders que correspondam a um RenderType específico em tempo de execução. Camera.RenderWithShaderou Camera.SetReplacementShaderusados ​​juntos. O RenderType integrado do Unity inclui:
    • "Opaque": a maioria dos objetos opacos usa isso;
    • "Transparent": A maioria dos objetos transparentes, incluindo efeitos de partículas, usa isso;
    • "Background": Todos os camarotes usam isso;
    • "Overlay": Tanto a GUI quanto o reflexo de lente usam isso;
    • RenderTypeOs usuários também podem definir qualquer valor para essa tag por conta própria .
    • Deve-se observar que Camera.RenderWithShadero Camera.SetReplacementShaderrótulo obrigatório ou não obrigatório só pode ser RenderTypeum RenderTyperótulo usado internamente para Substituir no Unity. Você também pode personalizar seu próprio rótulo totalmente novo para Substituir.
      Por exemplo, você adiciona Tag ao seu ShaderA.SubShaderA1 (o SubShader que será selecionado pelo Unity, geralmente o primeiro SubShader no arquivo Shader) e "Distort"="On"depois passa-o "Distort"como parâmetro replacementTagpara a função. Neste momento, replacementShaderse houver um ShaderB.SubShaderB1 idêntico ao parâmetro real "Distort"="On", então este SubShaderB1 substituirá SubShaderA1 para esta renderização.
    • Para obter detalhes, consulte Renderização com shaders substituídos
  • "Queue"Rótulo. Defina a ordem de renderização. O valor pré-fabricado é
    • "Background". O valor é 1000. Por exemplo, usado para camarotes.
    • "Geometry". O valor é 2.000. A maioria dos objetos está nesta fila. Objetos opacos também estão aqui. A ordem de renderização dos objetos nesta fila será ainda mais otimizada (deve ser de perto para longe, e o teste z inicial pode eliminar fragmentos que não precisam ser processados ​​​​pelo FS). Os objetos em outras filas são renderizados de acordo com sua posição espacial, de longe para perto.
    • "AlphaTest". O valor é 2450. Os objetos que foram AlphaTested estão nesta fila.
    • "Transparent". O valor é 3000. Objetos transparentes.
    • "Overlay". O valor é 4000. Como reflexo de lente.
    • O usuário pode definir qualquer valor, como"Queue"="Geometry+10"
  • "ForceNoShadowCasting", "true"quando o valor for , significa que sombras não são aceitas.
  • "IgnoreProjector", "true"quando o valor for , significa que a projeção do componente Projetor não é aceita.

Além disso, o resumo não oficial da experiência sobre filas e lotes de renderização é que a geração da fila de renderização de um quadro é determinada por cada objeto de renderização por vez:

  • Marca Shader e RenderType,
  • Renderer.SortingLayerID,
  • Renderer.SortingOrder,
  • Material.renderQueue (o valor padrão é "Queue" no Shader),
  • Transform.z(ViewSpace) (o padrão é de frente para trás de acordo com o valor z, mas quando a Queue é "Transparente", é de trás para frente de acordo com o valor z).

Depois que a fila de renderização é determinada (talvez haja um mecanismo de sinalização suja?), O renderizador percorre a fila de renderização por sua vez e os objetos de renderização do "mesmo" material são combinados em um lote.

Passar

Shader "ShaderLab Tutorials/TestShader" {
    SubShader {
        Pass
        {
            //...
        }
    }
}

Um SubShader (esquema de renderização) é executado por blocos Pass. Cada Pass consome um DrawCall correspondente. Reduza o número de passagens tanto quanto possível, satisfazendo ao mesmo tempo o efeito de renderização.

Etiqueta de passagem

Shader "ShaderLab Tutorials/TestShader" {
    SubShader {
        Pass
        {
            Tags{ "LightMode"="ForwardBase" }
            //...
        }
    }
}

Semelhante ao SubShader que possui sua própria tag exclusiva, o Pass também possui sua própria tag exclusiva.
A tag mais importante é "LightMode"especificar qual caminho de renderização ("Rendering Path") do Pass e do Unity usar juntos. Além dos mais importantes ForwardBase, ForwardAddos valores da Tag que requerem lembretes adicionais aqui podem incluir:

  • Always, sempre renderiza, mas não controla a iluminação
  • ShadowCaster, usado para renderizar objetos que produzem sombras
  • ShadowCollector, usado para coletar sombras de objetos no Buff de coordenadas da tela.

Para obter detalhes sobre tags relacionadas a outros caminhos de renderização, consulte o capítulo seguinte "Tipos de caminhos de renderização do Unity".
Para valores específicos de todas as tags, consulte a sintaxe do ShaderLab: Pass Tags .

Cair pra trás

Shader "ShaderLab Tutorials/TestShader"{
    SubShader { Pass {} }

    FallBack "Diffuse" // "Diffuse"即Unity预制的固有Shader
    // FallBack Off //将关闭FallBack
}

Quando todos os SubShaders deste Shader não suportarem a placa gráfica atual, outro Shader especificado pela instrução FallBack será usado. É melhor especificar a implementação de Shader pré-fabricada do próprio Unity para FallBack, pois geralmente pode ser executada em todas as placas gráficas atuais.

Propriedades

Shader "ShaderLab Tutorials/TestShader"
{
    Properties {
    _Range ("My Range", Range (0.02,0.15)) = 0.07 // sliders
    _Color ("My Color", Color) = (.34, .85, .92, 1) // color
    _2D ("My Texture 2D", 2D) = "" {} // textures
    _Rect("My Rectangle", Rect) = "name" { }
    _Cube ("My Cubemap", Cube) = "name" { }
    _Float ("My Float", Float) = 1
    _Vector ("My Vector", Vector) = (1,2,3,4)

    // Display as a toggle.
    [Toggle] _Invert ("Invert color?", Float) = 0
    // Blend mode values
    [Enum(UnityEngine.Rendering.BlendMode)] _Blend ("Blend mode", Float) = 1
    //setup corresponding shader keywords.
    [KeywordEnum(Off, On)] _UseSpecular ("Use Specular",  Float) = 0
    }

    // Shader
    SubShader{
        Pass{
          //...
          uniform float4 _Color;
          //...
          float4 frag() : COLOR{ return fixed4(_Color); }
          //...
             #pragma multi_compile __ _USESPECULAR_ON
          }
    }

    //fixed pipeline
    SubShader    {
        Pass{
            Color[_Color]
        }
    }
}
  • Os parâmetros que o Shader expõe à arte no editor Unity são implementados por meio de Propriedades.
  • Todos os parâmetros possíveis são mostrados acima. Existem basicamente três categorias: Float, Vector e Texture.
  • Além de editar Propriedades através do editor, os scripts também podem ser editados através Materialda interface (por exemplo SetFloat, SetTextureedição)
  • Essas propriedades são então acessadas no programa Shader por meio de [name](pipeline fixo) ou diretamente name(Shader programável).
  • O atributo também pode ser adicionado na frente de cada propriedade semelhante ao C# para obter funções adicionais do painel da interface do usuário. Consulte MaterialPropertyDrawer.html para obter detalhes .

Tipos de dados no Shader

Existem 3 tipos numéricos básicos : floate half. Esses três tipos numéricos básicos podem ser ainda compostos em vetor e matriz, por exemplo, são compostos por 3 e 16 .fixed
half3halffloat4x4float

  • float: Número de ponto flutuante de alta precisão de 32 bits.
  • half: Número de ponto flutuante de média precisão de 16 bits. O intervalo é [-60.000, +60.000], que pode ter precisão de 3,3 casas decimais após o ponto decimal.
  • fixed: Número de ponto flutuante de baixa precisão de 11 bits. O intervalo é [-2, 2] e a precisão é 1/256.
O tipo de dados afeta o desempenho
  • Contanto que a precisão seja suficiente.
    • Vetores de cores e unidades, usefixed
    • Em outros casos, tente usá-lo half(ou seja, o intervalo está entre [-60.000, +60.000], com precisão de 3,3 casas decimais); caso contrário, use-o float.

Matriz no ShaderLab

Ao se referir a "Linha-Maior" e "Coluna-Maior", eles podem significar coisas diferentes dependendo da situação:

  • Matematicamente, refere-se principalmente a se o vetor V é um vetor linha ou um vetor coluna. Citado em [Game Engine Architecture 2ª Edição, 183]. Preste atenção na multiplicação de V e M. Quando é um Vetor Linha, é escrito como VM em matemática, e a Matriz fica à direita. A linha inferior da Matriz representa Traduzir; quando é um Vetor Coluna , é escrito como MtVt em matemática, e a Matriz está à esquerda e precisa ser traduzida.Set, a coluna mais à direita da Matriz representa Traduzir.
  • Na interface de acesso: Row-Major é MyMatrix[Row][Column], Column-Major é MyMatrix[Column][Row]. A interface de acesso do HLSL / CG é Row-Major, por exemplo, MyMatrix[3] retorna a 3ª linha; a interface de acesso do GLSL é Column-Major, por exemplo, MyMatrix[3] retorna a 3ª coluna.
  • Armazenamento de registro: se cada elemento é armazenado no registro em linhas ou colunas. Um exemplo de situação geral em que você precisa prestar atenção é se MyMatrix de float2x3 ocupa 2 registros (Linha-Maior) ou 3 registros (Coluna-Maior). No HLSL, row_major ou column_major podem ser definidos por meio de #pragmapack_matrix.

As situações acima são irrelevantes entre si.
Então, no ShaderLab, é Column Vector em termos de matemática, Row-Major em termos de interface de acesso e (ainda não identificado) em termos de armazenamento.

O sistema de coordenadas de cada espaço no ShaderLab

Geralmente, os vértices de entrada do Vertex Buff para o Vertex Shader,

  • Este vértice é um vértice no sistema de coordenadas para canhotos Model Space vInModel,
    que é expresso por Coordenadas Homogêneas com w=1 (portanto equivalente às Coordenadas Cartesianas) vInModel = float4(xm, ym, zm, 1);
  • vInWrold = mul(_Object2World , vInModel)Finalmente, obtém-se que no sistema de coordenadas da esquerda Espaço Mundial vInWorld, são Coordenadas Homogêneas com w=1 (portanto é equivalente a Coordenadas Cartesianas) vInWorld = float4(xw, yw, zw, 1);
  • vInView = mul(UNITY_MATRIX_V , vInWrold)Por fim, obtém-se que no sistema de coordenadas da direitavInView View Space , são Cooridniatas Homogêneas com w=1 (portanto é equivalente a Coordenadas Cartesianas) vInWorld = float4(xv, yv, zv, 1);
  • vInClip = mul(UNITY_MATRIX_P , vInView)Finalmente, obtém-se que no sistema de coordenadas esquerdo Clip Space vInClip, são coordenadas homogêneas cujo w muitas vezes não é igual a 1 (portanto , muitas vezes não é equivalente às coordenadas cartesianas) vInClip = float4(xc, yc, zc, wc);
    deixe os valores absolutos dos comprimentos de r, l, t, b, n, f seja a seguinte imagem:


    Observe que o valor z na frente da câmera no View Space é um número negativo e -z é um número positivo. Então as coordenadas do Clip Space de GL/DX/Metal são:
    • GL:
      • xc=(2nx+rz+lz)/(r-l);
      • yc=(2ny+tz+bz)/(t-b);
      • zc=(-fz-nz-2nf)/(f-n);
      • wc=-z;
    • DX/Metal:
      • xc=(2nx+rz+lz)/(r-l);
      • yc=(2ny+tz+bz)/(t-b);
      • zc=(-fz-nf)/(f-n);
      • wc=-z;
  • vInNDC = vInClip / vInClip.wPor fim, obtém-se que no sistema de coordenadas da esquerda Normalized Device Coordinates vInNDC, são as Coordenadas Homogêneas com w=1 (portanto é equivalente às Coordenadas Cartesianas) vInNDC = float4(xn, yn, zn, 1).
    xnO intervalo de valores da soma yné [-1,1].
    • GL: zn=zc/wc=(fz+nz+2nf)/((f-n)z);
    • DX/Metal: zn=zc/wc=(fz+nf)/((f-n)z);
    • No Unity, zno intervalo de valores pode ser determinado assim:
      • Se UNITY_REVERSED_Zdefinido, zno intervalo de valores é [ UNITY_NEAR_CLIP_VALUE, 0], ou seja, [1,0]
      • Se UNITY_REVERSED_Zindefinido, zno intervalo de valores é [ UNITY_NEAR_CLIP_VALUE, 1]
        • Se SHADER_API_D3D9/ SHADER_API_D3D11_9Xfor definido, isso é [0,1]
        • Caso contrário, esse é o caso do OpenGL, que é [-1,1]
v2f vert (appdata v)
{
    v2f o;
    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    // 1 、2、3是等价的,和4是不等价的
    // 因为是M在左、V在右,所以是Column Vector
    // 因为是HLSL/CG语言,所以是访问方式是Row-Major
    o.rootInView = mul(UNITY_MATRIX_MV, float4(0, 0, 0, 1)); // 1
    o.rootInView = float4(UNITY_MATRIX_MV[0].w, UNITY_MATRIX_MV[1].w, UNITY_MATRIX_MV[2].w, 1); // 2                
    o.rootInView = UNITY_MATRIX_MV._m03_m13_m23_m33;  // 3
    //o.rootInView = UNITY_MATRIX_MV[3]; // 4

    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    // 因为是ViewSpace是右手坐标系,所以当root在view前面的时候,z是负数,所以需要-z才能正确显示颜色
    fixed4 col = fixed4(i.rootInView.x, i.rootInView.y, -i.rootInView.z, 1);
    return col;
}

struct appdata
{
    float4 vertex : POSITION;
};
struct v2f
{
    float4 rootInView : TEXCOORD0;
    float4 vertex : SV_POSITION;
};

Formulário de sombreador

Forma de sombreador 1: pipeline fixo

O pipeline fixo é para compatibilidade com placas gráficas mais antigas. Eles são todos iluminação de vértice. No futuro, o pipeline fixo pode ser um recurso abandonado pelo Unity, por isso é melhor não aprendê-lo e tratá-lo como se não existisse. A característica é que existem blocos em forma de Materialblocos inferiores, sem blocos CGPROGRAMe ENDCGblocos.

Shader "ShaderLab Tutorials/TestShader"
{
    Properties {
    _Color ("My Color", Color) = (.34, .85, .92, 1) // color
    }

    // Fixed Pipeline
    SubShader
    {
        Pass
        {
            Material{
            Diffuse [_Color]
            Ambient [_Color]
            }

            Lighting On
        }
    }
}

Forma de sombreador 2: sombreador programável

Shader "ShaderLab Tutorials/TestShader"
{
    Properties {}

    SubShader
    {
        Pass
        {
          // ... the usual pass state setup ...

          CGPROGRAM
          // compilation directives for this snippet, e.g.:
          #pragma vertex vert
          #pragma fragment frag

          // the Cg/HLSL code itself
          float4 vert(float4 v:POSITION) : SV_POSITION{
              return mul(UNITY_MATRIX_MVP, v);
          }
          float4 frag() : COLOR{
              return fixed4(1.0, 0.0, 0.0, 1.0);
          }
          ENDCG
          // ... the rest of pass setup ...
          }
    }
}
  • A forma mais poderosa e gratuita.
  • CGPROGRAMA característica é que o ENDCGbloco de soma aparece no Pass
  • Diretivas de compilação #pragma. Consulte os trechos Cg do site oficial para obter detalhes . Os importantes incluem:
Diretivas de compilação Exemplo/Significado
#pragma vertex name
#pragma fragment name
Substitua o nome para especificar a função Vertex Shader e a função Fragment Shader.
#pragma target name Substitua o nome (por 2.0, 3.0etc.). Defina a versão do modelo de sombreador de destino de compilação.
#pragma only_renderers name name ...
#pragma exclude_renderers name name...
#pragma only_renderers gles gles3,
#pragma exclude_renderers d3d9 d3d11 opengl,
compilado apenas para a plataforma de renderização especificada (plataforma de renderização)
  • Biblioteca de referência. #include "UnityCG.cginc"Importe a biblioteca especificada através do formulário . UnityCG.cgincEsse é o comumente usado . Para obter detalhes sobre outras bibliotecas, consulte o site oficial Arquivos de inclusão de shader integrados .
  • Valor integrado do ShaderLab. O Unity fornece valores convenientes e comumente usados ​​para o programa Shader. Por exemplo, o exemplo a seguir UNITY_MATRIX_MVPrepresenta a matriz MVP neste momento. Para obter detalhes, consulte o site oficial Valores integrados do ShaderLab .
  • Semântica dos parâmetros de entrada e saída do shader (Semântica). Os parâmetros de entrada e saída entre cada estágio do processo de pipeline (como entre o estágio Vertex Shader e o estágio FragmentShader) especificam o significado dos parâmetros por meio de cadeias de caracteres semânticas. A semântica comumente usada inclui: COLOR, SV_Position, TEXCOORD[n]. A semântica completa dos parâmetros pode ser encontrada em HLSL Semantic (por ser uma conexão HLSL, pode não estar completamente disponível no Unity).
  • Em particular, como a entrada do Vertex Shader geralmente é o início do pipeline, o Unity possui estruturas de dados integradas comumente usadas para essa finalidade:
estrutura de dados significado
appdata_base entrada do sombreador de vértice com posição, normal, uma coordenada de textura.
appdata_tan entrada do sombreador de vértice com posição, normal, tangente, uma coordenada de textura.
appdata_full entrada do shader de vértice com posição, normal, tangente, cor do vértice e duas coordenadas de textura.
appdata_img entrada do shader de vértice com posição e uma coordenada de textura.

Forma de sombreador 3: SurfaceShader

Shader "ShaderLab Tutorials/TestShader"
{
    Properties {   }

    // Surface Shader
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float4 color : COLOR;
      };
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = 1;
      }
      ENDCG
    }
    FallBack "Diffuse"
}
  • SurfaceShader pode ser pensado como um açúcar de sintaxe para um Shader de iluminação e um gerador de iluminação VS/FS . Reduz a necessidade dos desenvolvedores escreverem código duplicado.
  • Em jogos para celular, devido aos requisitos de desempenho relativamente altos, não é recomendado o uso do SurfaceShader . Porque SurfaceShader é uma função relativamente "universal" e a universalidade geralmente leva a um baixo desempenho.
  • CGPROGRAMA característica é que o bloco de soma aparece no SubShader ENDCG. (Em vez de aparecer no Pass. Porque o próprio SurfaceShader será compilado em vários Passes.)
  • As instruções de compilação são:
    #pragma surface surfaceFunction lightModel [optionalparams]
    • surfaceFunction: função surfaceShader, no formatovoid surf (Input IN, inout SurfaceOutput o)
    • lightModel: O modo de iluminação usado. Incluindo Lambert(reflexão difusa) e BlinnPhong(reflexão especular).
      • Você também pode definir sua própria função de iluminação. Por exemplo, a instrução de compilação é#pragma surface surf MyCalc
  • Você define a estrutura de dados de entrada (como a acima Input), escreve sua própria função Surface para processar a entrada e, finalmente, gera o SurfaceOutput modificado. SurfaceOutput é definido como
    struct SurfaceOutput {
      half3 Albedo; // 纹理颜色值(r, g, b)
      half3 Normal; // 法向量(x, y, z)
      half3 Emission; // 自发光颜色值(r, g, b)
      half Specular; // 镜面反射度
      half Gloss; // 光泽度
      half Alpha; // 不透明度
    };

Forma de Shader 4: Shader Compilado

Clique em a.shader"Compile and show code" do arquivo, você pode ver o arquivo shader ShaderLab "compilado" do arquivo, o nome do arquivo está no formato Compiled-a.shader.
Ainda é um arquivo ShaderLab, que contém a string do código do shader que é finalmente enviada à GPU.
Primeiro, vamos descrever brevemente sua estrutura da seguinte maneira: você descobrirá que ela é muito semelhante à estrutura de pré-compilação do ShaderLab mencionada acima.

// Compiled shader for iPhone, iPod Touch and iPad, uncompressed size: 36.5KB
// Skipping shader variants that would not be included into build of current scene.
Shader "ShaderLab Tutorials/TestShader"
{
    Properties {...}
    SubShader {
        // Stats for Vertex shader:
        //        gles : 14 avg math (11..19), 1 avg texture (1..2)
        //       metal : 14 avg math (11..17)
        // Stats for Fragment shader:
        //       metal : 14 avg math (11..19), 1 avg texture (1..2)
        Pass {
            Program "vp" // vertex program
            {
                SubProgram "gles" {
                    // Stats: 11 math, 1 textures
                    Keywords{...} // keywords for shader variants ("uber shader")

                    //shader codes in string
                    "
                    #ifdef VERTEX
                    vertex shader codes
                    #endif

                    // Note, on gles, fragment shader stays here inside Program "vp"
                    #ifdef FRAGMENT
                    fragment shader codes
                    #endif
                    " 
                }

                SubProgram "metal"  {
                    some setup
                    Keywords{...}

                    //vertex shader codes in string
                    "..."
                }
            }

            Program "fp" // fragment program
            {
                SubProgram "gles" {
                    Keywords{...}
                    "// shader disassembly not supported on gles" //(because gles fragment shader codes are in Program "vp") 
                }

                SubProgram "metal" {
                    common setup
                    Keywords{...}

                    //fragment shader codes in string
                    "..."
                }
            }
        }
    }

    ...
}

Tipo de caminho de renderização do Unity (Caminho de renderização)

Visão geral

Os desenvolvedores podem escolher 1 dos 3 caminhos de renderização nas PlayerSettings do projeto Unity:

  • Iluminação diferida , caminho de iluminação retardado. Restaure iluminação e sombras com a mais alta qualidade entre os três. O desempenho da iluminação está relacionado apenas ao número final de pixels e mais fontes de luz não afetarão o desempenho.
  • Renderização direta , caminho de renderização sequencial. Um caminho de renderização que pode aproveitar todos os recursos do Shader e, claro, suporta iluminação em nível de pixel. É o mais utilizado e possui mais funções gratuitas. Seu desempenho está relacionado à quantidade de fontes de luz * à quantidade de objetos iluminados. O desempenho específico depende da complexidade do Shader utilizado.
  • Vertex Lit , caminho de iluminação do vértice. Iluminação de nível de vértice. Possui o melhor desempenho, maior compatibilidade, menos recursos suportados e pior qualidade.

O estágio interno do caminho de renderização e a tag LightMode do Pass

Cada caminho de renderização é dividido internamente em vários estágios.
Então, cada passagem no Shader pode ser atribuída a um LightMode diferente. Na verdade, LightMode diz: "Quero que este passe seja executado no subestágio YYY deste caminho de renderização XXX."

Levantamento diferido
Subestágios internos do caminho de renderização LightMode correspondente descrever
Passe Básico "PrepassBase" Renderizar informações do objeto. Ou seja, o vetor normal e o destaque são transferidos para uma textura de informações do objeto ARGB32 e as informações de profundidade são salvas no Z-Buff.
Passe de Iluminação Nenhuma passagem programável correspondente Com base nas informações do objeto obtidas no Base Pass, no sistema de coordenadas da tela, use o modo de iluminação BlinnPhong para renderizar as informações de iluminação na textura das informações de iluminação ARGB32 ( RGB representa o valor da cor difusa, A representa o destaque)
Passe Final "PrepassFinal" De acordo com a textura das informações de iluminação , o objeto é renderizado novamente e as informações de iluminação, informações de textura e informações de autoiluminação são finalmente misturadas. LightMap também é realizado neste Passe.
Renderização direta
Subestágios internos do caminho de renderização LightMode correspondente descrever
Passe Básico "ForwardBase" Renderização: a fonte de luz direcional mais brilhante (nível de pixel) e sombras correspondentes, todas as fontes de luz de nível de vértice, LightMap, todas as fontes de luz LightProbe SH (esfera harmônica, função harmônica esférica, luz de baixa frequência de ultra-alta eficiência), luz ambiente , brilho automático.
Passes Adicionais "ForwardAdd" Outras fontes de luz que requerem renderização em nível de pixel

Observe que na renderização direta, a fonte de luz pode ser uma fonte de luz em nível de pixel, uma fonte de luz em nível de vértice ou uma fonte de luz SH. Os critérios de julgamento são:

  • As fontes de luz configuradas como "Não Importante" são fontes de luz de nível de vértice e fontes de luz SH.
  • A luz direcional mais brilhante é sempre uma fonte de luz em nível de pixel
  • Aquelas configuradas como "Importantes" são todas fontes de luz em nível de pixel.
  • Se o número combinado de fontes de luz de nível de pixel nas duas situações acima for menor que a "Contagem de luz de pixel" em "Configurações de qualidade" , a fonte de luz na primeira situação será complementada como uma fonte de luz adicional de nível de pixel.

Além disso, as fontes de luz configuradas como "Auto" possuem anotações de julgamento mais complexas. A captura de tela é a seguinte:


2014-0720-1607-31-40.png


Para obter detalhes, consulte Detalhes do caminho de renderização de encaminhamento .

Vértice iluminado
Subestágios internos do caminho de renderização LightMode correspondente descrever
Vértice "Vertex" Renderizando objetos sem LightMap
VérticeLMRGBM "VertexLMRGBM" Renderizando um objeto LightMap com codificação RGBM
VérticeLM "VertexLM" Renderizando objetos LightMap com codificação LDR dupla

Passagens de diferentes LightMode são selecionadas

O caminho de renderização de um projeto é único, mas o Shader em um projeto permite passes com LightMode diferentes.
No Unity, a estratégia é “partir do modo de caminho de renderização configurado no projeto e buscar um Pass que melhor corresponda ao LightMode na ordem Deferred, Forward e VertxLit”.
Por exemplo, ao configurar um caminho Deferred, o Pass com LightMode relacionado ao Deferred será selecionado primeiro; se não puder ser encontrado, o Pass relacionado ao Forward será selecionado; se não puder ser encontrado, o Pass relacionado ao VertexLit será selecionado .
Para outro exemplo, ao configurar o caminho Forward, o Pass relacionado ao Forward será selecionado primeiro; se não puder ser encontrado, o Pass relacionado ao VertexLit será selecionado.

Breve descrição da arquitetura GPU de dispositivos móveis

A série "The Mali GPU: An Abstract Machine" fornece uma discussão abrangente usando a GPU Arm Mali como exemplo, que é brevemente descrita a seguir:

  • Parte 1 - Pipelining da Estrutura
    • Consiste em três etapas: Aplicação/Geometria/Fragmento. A maior das três é o gargalo.
    • A API de sincronização do OpenGL é uma "ilusão", na verdade é um CommandQueue (será forçado a sincronizar até encontrar uma Fence) para reduzir a espera mútua entre CPU/GPU.
    • Pipeline Throttle, para menor latência, quando a GPU acumula vários quadros (geralmente 3 quadros, ou eglSwapBuffers()para Present()distinguir quadros) de comandos, o sistema operacional bloqueará a CPU eglSwapBuffers()ou Present()a deixará ociosa, evitando assim mais envio de comandos subsequentes.
  • Parte 2 - Renderização baseada em blocos
    • A renderização diferida baseada em blocos ( Wiki , PowerVR / Mali / Adreno ) é um conceito importante. Ele processa múltiplas unidades de Fragment, como 16x16, em um quadro, e integra um cache pequeno, mas rápido, para o Shader, evitando assim grandemente o consumo de largura de banda (consumo de energia) entre o Shader e a memória principal.
  • Parte 3 - O Núcleo Midgard Shader
    • A GPU contém vários (atualmente 4-8 são comuns) Unified Shading Cores, que podem ser alocados dinamicamente para Vertex Shader, Fragment Shader ou Compute Kernel
    • Cada Unified Shader Core contém vários (atualmente 2 são comuns) Pipelines Aritméticos (pipeline A) para cálculos SIMD, 1 Pipeline Texutre (pipeline T) para amostragem de textura e 1 para pipeline sem carga/armazenamento (pipeline LS) para leitura e escrita de memória de classes de textura, como escrita e leitura de atributos de vértice, acesso a variáveis, etc.
    • Testes iniciais de ZS serão realizados para tentar reduzir o Overdraw (dependendo da ordem de envio do objeto renderizado de frente para trás)
    • O Forward Pixel Kill do Arm e a remoção de superfície oculta do PowerVR alcançam redução de overdraw no nível de pixel (sem depender da ordem de envio do objeto de renderização da frente para trás)
    • Quando o Shader usa discardou clipmodifica o valor de profundidade ou translucidez no Fragment Shader, o Early-ZS não será possível e o Late-ZS tradicional terá que ser usado.
  • Parte 4 - O Núcleo do Shader Bifrost
    • O novo modelo em 2016 otimizou a estrutura

Recursos de referência

  • Youtube: https://www.youtube.com/watch?v=hDJQXzajiPg (incluindo parte 1-6). O vídeo é uma das melhores maneiras de começar, então sugiro que você assista a parte 1 mesmo que não tenha lido todo o conteúdo abaixo.
  • Livro: "Explicação prática detalhada do desenvolvimento do Unity 3D ShaderLab"
  • Unidade vários documentos oficiais


Autor: DonaldW
Link: http://www.jianshu.com/p/7b9498e58659
Fonte: Os direitos autorais de Jianshu
pertencem ao autor. Para reimpressão comercial, entre em contato com o autor para autorização. Para reimpressão não comercial, indique a fonte.

Acho que você gosta

Origin blog.csdn.net/qq_25189313/article/details/78031678
Recomendado
Clasificación