Olá pessoal! Meu nome é Grigory Dyadichenko e sou o fundador e CTO da Foxsys Studios. Hoje eu quero falar sobre shaders. A capacidade de escrever shaders (e geralmente trabalhar com a renderização) é muito importante no desenvolvimento para plataformas móveis ou AR / VR, se você deseja obter gráficos interessantes. Muitos desenvolvedores acham que shaders são mágicos. Que há pouca informação boa sobre eles e que, para escrevê-los, você precisa ter pelo menos o título de candidato à ciência. Sim, o desenvolvimento de shaders por seus princípios é muito diferente do desenvolvimento do cliente. Mas o principal é entender os princípios básicos dos shaders, bem como conhecer sua essência, para que não haja nada mágico e a busca por informações sobre esse tópico seja uma tarefa simples. Esta série de artigos é voltada para iniciantes; portanto, se você é bom em programação de sombreadores, essa série não será do seu interesse. Quem quiser entender esse tópico - seja bem-vindo!

Este é um artigo introdutório no qual descreverei os princípios gerais de escrever shaders. Se o tópico for interessante, analisaremos mais detalhadamente em artigos separados: sombreadores de vértices, sombreamentos geométricos, sombreadores de pixel / fragmento, sombreadores triplanares, efeitos de espaço na tela e sombreadores de computador (OpenCL, CUDA, etc.). E, em geral, toda a mágica que pode ser feita na GPU. Isso será resolvido no contexto do pipeline padrão do Unity. Então, o LWRP e o HDRP até agora parecem um pouco úmidos para mim.
O que é um shader?
Fonte: www.shadertoy.com/view/MsGSRdDe fato, este é um programa em execução na GPU, cuja saída é informação diferente. Nos shaders de vértice, esses são os parâmetros dos vértices da malha. Os sombreadores de pixel são executados pixel por pixel.
Para entender como os shaders funcionam, você precisa dizer o que é um pipeline gráfico. Muitas vezes, as pessoas falam sobre esse tópico com palavras bastante complicadas, mas tornaremos um pouco mais fácil de entender. Veja o exemplo do OpenGL. A este respeito, eu realmente gosto desta imagem.

Se você omitir peças relacionadas à iluminação etc. Em geral, do ponto de escrever os mesmos shaders Unlit no hlsl, a essência é a seguinte. Temos um shader
#pragma vertex vert #pragma fragment frag
onde determinamos que a parte do vértice do shader será escrita na função vert e a parte do fragmento na função frag.
As estruturas que descrevemos no sombreador determinam quais dados serão obtidos da malha e após o processamento com o sombreador de vértice que fica nos nossos objetos MeshRenderer e MeshFilter.
struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; };
Em seguida, o sombreador de vértice calcula recebendo os dados de appdata como uma entrada e fornece o resultado na forma de uma estrutura v2f, que depois vai para o sombreador de fragmento. Que por sua vez já calculará a cor do pixel. Como as informações da v2f são gravadas apenas nos vértices (menores que os pixels), os dados na parte do fragmento são interpolados. Tudo isso pode ser representado como o fato de que vert é considerado em cada vértice independentemente. Em seguida, o resultado é transferido para a parte do fragmento, onde frag para cada pixel é considerado independente. Como os cálculos são realizados em paralelo, nessas partes não há informações sobre os vizinhos (se você não as transmitir de alguma maneira inteligente).
Mais detalhadamente, todas as nuances e muitos exemplos estão descritos na documentação do Unity
docs.unity3d.com/Manual/SL-Reference.htmlLinguagens de Programação Shader
Fonte: www.shadertoy.com/view/WsS3DcO que mais é importante para não esquecer. O fato de os shaders serem escritos em três linguagens de programação que nada têm a ver com unidade. CG, GLSL e HLSL. A maneira mais fácil de escrever shaders em uma unidade é através do HLSL, pois é onde os arquivos shader com permissão .shader são gravados. E se houver comparativamente pouca informação sobre shaders no contexto de uma unidade, as informações separadamente sobre HLSL, GLSL e CG são apenas toneladas. A documentação para os shaders descreve como transferir o que está escrito nesses idiomas para o Unity. Portanto, verifica-se que quase todas as informações em geral sobre essas linguagens de programação são válidas. Todos os três idiomas são muito semelhantes ao C, mas cada um tem suas próprias características.
Além disso, do ponto de vista do estudo de shaders, quando esses idiomas não levantam mais perguntas, é possível ver quais possibilidades o "UnityCG.cginc" e outras bibliotecas escritas pelo unity oferecem por si só para simplificar seu trabalho.
Por que se em shaders é ruim?
Fonte: www.shadertoy.com/view/Md3cWrÉ importante entender como os shaders são executados no nível do ferro e por que são tão rápidos que podem executar milhões de operações sem sobrecarregar.
A idéia principal das GPUs é o paralelismo máximo dos cálculos. Aqui é necessário introduzir um conceito como "frente de onda". De fato, é bastante simples, a frente de onda é um grupo de shaders que executa a mesma sequência de operações. Ou seja, do ponto de vista da GPU, a melhor opção é quando as mesmas instruções são executadas ao mesmo tempo. A única diferença na execução é a entrada. O problema da ramificação é que uma situação pode ocorrer quando, em um único grupo de sombreadores, os sombreadores devem invocar operações diferentes. O que, por sua vez, leva à criação de uma nova frente de onda, a cópia de dados nela, etc. E é muito caro.
Existem nuances e exceções, mas, para escrever com segurança, você deve entender como ele se comporta na versão de destino da API gráfica. Como o mesmo OpenGL ES 2 ou DX11 nesse aspecto é muito diferente.
Por que preciso saber disso, porque existem editores de nós?

É importante entender que os editores de nós são principalmente uma ferramenta para artistas técnicos. Estes são especialistas que têm experiência em matemática, mas são mais designers. Os shaders do tipo wireframe (onde é necessário o entendimento das coordenadas baricêntricas) ou a transformação em coordenadas cartesianas, que são usadas para projeções complicadas, são muito mais fáceis de fazer com o código, como muitos modelos matemáticos de materiais físicos. Ao mesmo tempo, do ponto de vista de um programador de sombreador, você essencialmente cria nós e ferramentas personalizadas para artistas técnicos criarem mágica real. Os editores de nós têm funcionalidade limitada deste ponto de vista. Portanto, é importante poder escrever shaders em idiomas como hlsl. Entenda como a renderização funciona, etc.
Recursos úteis para a aprendizagem
Fonte: www.shadertoy.com/view/4tlcWjEm termos de programação de shader de aprendizagem, um bom exercício é reescrever shaders de
www.shadertoy.com ou
glslsandbox.com . Além disso, há um perfil interessante de um especialista da Unity, onde você pode ver muitas coisas interessantes
github.com/keijiroTudo o resto é matemática e uma compreensão da física dos efeitos. Isso é semelhante à mistura dos ingredientes, se o problema específico da modelagem física não for resolvido. Muitas coisas interessantes podem ser feitas através da mistura de ruído, refração, dispersão de luz no subsolo, produtos cáusticos, efeito Fresnel, reação de difusão e outras propriedades físicas dos objetos. Em geral, a programação de sombreador certamente não é elementar, e há onde aprofundar.
Se o tópico de shaders for interessante, tentarei lançar uma série de artigos sobre esse tópico, já com exemplos e tutoriais específicos sobre o tópico de criar efeitos diferentes. Sugira nos comentários sobre o que você gostaria de ler e quais tópicos estudar. Obrigado pela atenção!
Todos os efeitos no artigo são uma gravação de efeitos de shader com shadertoy.