Olá pessoal. Anteriormente, meus artigos eram e Programação reativa no desenvolvimento de jogos: especificidades do Unity . Desenvolvendo jogos no Unity: examinando abordagens para organizar a arquitetura Hoje, gostaria de abordar um tópico como renderização e shaders no Unity. Shaders (em palavras simples) são instruções para placas de vídeo que informam como renderizar e transformar objetos no jogo. Então, bem-vindo ao clube, amigo. Cuidado! Este artigo tinha um quilômetro de comprimento, então o dividi em duas partes! Como funciona a renderização no Unity? Na versão atual do , temos três pipelines de renderização diferentes - integrado, HDRP e URP. Antes de lidar com a renderização, precisamos entender o conceito dos pipelines de renderização que o Unity nos oferece. Unity Cada pipeline de renderização executa algumas etapas que executam uma operação mais significativa e formam um processo de renderização completo. E quando carregamos um modelo (por exemplo, .fbx) no palco, antes de chegar aos nossos monitores, ele percorre um longo caminho, como se fosse de Washington a Los Angeles por estradas diferentes. Cada pipeline de renderização tem suas propriedades com as quais trabalharemos. As propriedades do material, fontes de luz, texturas e todas as funções dentro do sombreador afetarão a aparência e a otimização dos objetos na tela. Então, como esse processo acontece? Para isso, precisamos discutir a arquitetura básica dos pipelines de renderização. O Unity divide tudo em quatro estágios: funções de aplicativo, trabalho com geometria, rasterização e processamento de pixels. Funções do aplicativo O processamento das funções começa na CPU e ocorre dentro da nossa cena. Isso pode incluir: Processamento de física e erro de cálculo de colisão animações de textura Entrada de teclado e mouse Nossos roteiros É aqui que nosso aplicativo lê os dados armazenados na memória para gerar posteriormente nossas primitivas (triângulos, vértices, etc.). Ao final da etapa de aplicação, tudo isso é enviado para a etapa de processamento de geometria para trabalhar as transformações de vértices por meio de transformações de matrizes. Processamento de geometria Quando o computador solicita através da CPU as imagens que vemos na tela, isso é feito em 2 etapas: da nossa GPU Quando o estado de renderização é configurado e as etapas de processamento de geometria para processamento de pixel foram passadas Quando o objeto é renderizado na tela A fase de processamento de geometria ocorre na GPU e é responsável por processar o vértices do nosso objeto. Essa fase é dividida em quatro subprocessos: sombreamento de vértice, projeção, recorte e exibição na tela. Quando nossas primitivas foram carregadas e montadas com sucesso no primeiro estágio de aplicação, elas são enviadas para o estágio de sombreamento de vértices. Tem duas tarefas: Calcular a posição dos vértices no objeto Converta a posição em outras coordenadas espaciais (de coordenadas locais para globais, por exemplo) para que possam ser renderizadas na tela Além disso, nesta etapa, podemos selecionar adicionalmente as propriedades que serão necessárias para as próximas etapas de desenho dos gráficos. Isso inclui normais, tangentes, bem como coordenadas UV e outros parâmetros. A projeção e o recorte funcionam como etapas adicionais e dependem das configurações da câmera em nossa cena. Observe que todo o processo de renderização é feito em relação ao Camera Frustum. A projeção será responsável pela perspectiva ou mapeamento ortográfico, enquanto o recorte nos permite aparar o excesso de geometria fora do Camera Frustum. Rasterização e trabalho com pixels A é a rasterização. Consiste em encontrar pixels em nossa projeção que correspondam às nossas coordenadas 2D na tela. O processo de encontrar todos os pixels que estão ocupados pelo objeto de tela é chamado de rasterização. Este processo pode ser considerado uma etapa de sincronização entre os objetos em nossa cena e os pixels na tela. próxima etapa do trabalho de renderização As seguintes etapas são executadas para cada objeto na tela: O Triangle Setup é responsável por gerar dados sobre nossos objetos e transmiti-los para travessia. Triangle Traversal enumera todos os pixels que fazem parte do grupo de polígonos; neste caso, este grupo de pixels é chamado de fragmento. A última etapa segue quando coletamos todos os dados e estamos prontos para exibir os pixels na tela. Nesse ponto, é iniciado o fragment shader, responsável pela visibilidade de cada pixel. Ele é responsável pela cor de cada pixel a ser renderizado na tela. Sombreamento avançado e adiado Como já sabemos, o Unity possui três tipos de pipelines de renderização: integrado, URP e HDRP. De um lado, temos o Built-In (o tipo de renderização mais antigo que atende a todos os critérios do Unity). Por outro lado, temos o HDRP e o URP mais modernos, otimizados e flexíveis (chamados Scriptable RP). Cada pipeline de renderização possui seus caminhos para processamento gráfico, que correspondem ao conjunto de operações necessárias para ir desde o carregamento da geometria até a renderização na tela. Isso nos permite processar graficamente uma cena iluminada (por exemplo, uma cena com luz direcional e paisagem). Exemplos de caminhos de renderização incluem caminho direto, caminho adiado e adiado legado e aceso de vértice legado. Cada um suporta determinados recursos e limitações, tendo seu desempenho. No Unity, o caminho de encaminhamento é o padrão para renderização. Isso ocorre porque o maior número de placas de vídeo o suporta. Mas o caminho a seguir tem suas limitações de iluminação e outros recursos. Observe que o URP suporta apenas o caminho de encaminhamento, enquanto o HDRP tem mais opções e pode combinar os caminhos de encaminhamento e adiados. Para entender melhor esse conceito, devemos considerar um exemplo onde temos um objeto e uma luz direcional. A forma como esses objetos interagem determinará nosso caminho de renderização (modelo de iluminação). Além disso, o resultado será influenciado por: Características do material Características das fontes de iluminação O modelo básico de iluminação corresponde à soma de 3 propriedades diferentes: cor ambiente, reflexão difusa e reflexão especular. O cálculo da iluminação é feito no shader. Pode ser feito por vértice ou fragmento. Quando a iluminação é calculada por vértice, ela é chamada de iluminação por vértice e é feita no estágio de shader de vértice. Da mesma forma, se a iluminação for calculada por fragmento, ela é chamada de sombreador por fragmento ou por pixel e é feita no estágio de sombreamento de fragmento (pixel). A iluminação de vértices é muito mais rápida que a iluminação de pixels, mas você deve considerar que seus modelos devem ter muitos polígonos para obter um belo resultado. Matrizes no Unity Então, vamos voltar aos nossos estágios de renderização, mais precisamente ao estágio de trabalhar com vértices. Matrizes são usadas para sua transformação. Uma matriz é uma lista de elementos numéricos que obedecem a certas regras aritméticas e são freqüentemente usadas em computação gráfica. No Unity, as matrizes representam transformações espaciais. Entre eles, podemos encontrar: UNITY_MATRIX_MVP UNITY_MATRIX_MV UNITY_MATRIX_V UNITY_MATRIX_P UNITY_MATRIX_VP UNITY_MATRIX_T_MV UNITY_MATRIX_IT_MV unity_ObjectToWorld unity_WorldToObject Todos eles correspondem a matrizes quatro por quatro (4x4). Cada matriz tem quatro linhas e quatro colunas de valores numéricos. Um exemplo de matriz pode ser a seguinte opção: Como foi dito antes - nossos objetos possuem dois nós (em alguns editores gráficos, eles são chamados de transform e shape), e ambos são responsáveis pela posição de nossos vértices no espaço do objeto. O espaço do objeto define a posição dos nós em relação ao centro do objeto. E toda vez que mudamos a posição, rotação ou escala dos vértices do objeto, multiplicamos cada vértice pela matriz do modelo (no caso do Unity - UNITY_MATRIX_M). Para transferir coordenadas de um espaço para outro e trabalhar dentro dele, trabalharemos constantemente com diferentes matrizes. Propriedades de objetos poligonais Continuando o tema de trabalhar com objetos poligonais, posso dizer que no mundo dos gráficos 3D, todo objeto é formado por uma malha poligonal. Os objetos em nossa cena têm propriedades; cada um sempre contém vértices, tangentes, normais, coordenadas UV e cores. Todos juntos formam uma malha. Tudo isso é . gerenciado por shaders Com os shaders, podemos acessar e modificar cada um desses parâmetros. Normalmente usaremos vetores (float4) ao trabalhar com esses parâmetros. A seguir, vamos analisar cada um dos parâmetros do nosso objeto. Vértices Os vértices de um objeto correspondem a um conjunto de pontos que definem a área da superfície no espaço 2D ou 3D. Em editores 3D, os vértices geralmente são representados como pontos de interseção entre a malha e o objeto. Os vértices são caracterizados, via de regra, por 2 pontos: Eles são componentes filhos do componente de transformação Eles têm uma certa posição de acordo com o centro do objeto comum no espaço local Isso significa que cada vértice tem seu componente transform responsável por seu tamanho, rotação e posição, além de atributos que indicam onde esses vértices estão em relação ao centro do nosso objeto. normais As normais nos ajudam inerentemente a determinar onde a face de nossas fatias de objeto está localizada. Uma normal corresponde a um vetor perpendicular na superfície de um polígono, que é usado para determinar a direção ou orientação de uma face ou vértice. Tangentes Referindo-se à documentação do Unity, obtemos a seguinte descrição: Uma tangente é . As tangentes no Unity são representadas como Vector4, com componentes x,y,z definindo o vetor e w usado para inverter o binormal, se necessário - Unity Manual um vetor de comprimento unitário que segue a superfície da Malha ao longo da direção da textura horizontal (U) O que diabos eu acabei de ler? Em linguagem simples, as tangentes seguem as coordenadas U em UV para cada forma geométrica. coordenadas UV Muitos caras olharam as skins do e talvez, como eu, até tentaram desenhar algo próprio. E as coordenadas UV estão exatamente relacionadas a isso. Podemos usá-los para colocar uma textura 2D em um objeto 3D. GTA Vice City Essas coordenadas atuam como pontos de referência que controlam quais texels no mapa de textura correspondem a cada vértice na malha. A área das coordenadas UV equivale a um intervalo entre 0,0 (float) e 1,0 (float), onde "0" representa o ponto inicial e "1" representa o ponto final. Cores dos vértices Além da posição, rotação e tamanho, os vértices também têm suas cores. Quando exportamos um objeto de um software 3D, ele atribui uma cor ao objeto que precisa ser afetado pela iluminação ou cópia de outra cor. A cor do vértice padrão é branco (1,1,1,1,1,1) e as cores são codificadas em RGBA. Com a ajuda das cores dos vértices, você pode, por exemplo, trabalhar com mesclagem de texturas, como mostra a imagem acima. Pequena conclusão Este é o fim da 1 parte. Na parte 2, discutirei: o que é um sombreador Idiomas do sombreador Tipos básicos de shader no Unity Estrutura do sombreador ShaderLabName Misturando Buffer Z (Buffer de Profundidade) Seleção Cg/HLSL gráfico de sombreamento Se você tiver alguma dúvida, deixe nos comentários!