Como transferir um shader de um mecanismo de jogo para o Substance Painter

Meu nome é Taras Uleisky, sou um artista técnico no Plarium Kharkiv. Para otimizar os gráficos do nosso Survival RPG em dispositivos móveis, usamos nossos shaders personalizados. Eles envolvem o uso de texturas e mapas exclusivos que não são semelhantes a texturas e mapas em outros métodos populares de sombreamento. Como resultado, não está totalmente claro para os artistas 3D como criar essas texturas para ativos no jogo. Para ver imediatamente como o modelo 3D ficará no mecanismo de jogo no estágio de texturização, mudei o shader para Substance Painter. Praticamente não há materiais de API no Substance Painter no momento; eu próprio estudei esse tópico, então decidi compartilhar minhas próprias idéias.



Shader de unidade


O jogo usa sombreamento matcap. Além da textura diff usual, duas texturas Matcap pré-criadas também são transferidas para o shader. Eles são interpolados e desfocados usando duas máscaras, respectivamente. Como resultado, a textura Matcap é multiplicada por brilho difuso e falso e reflexos podem ser vistos no material.



O exemplo abaixo mostra como o Matcap é implementado em um gráfico de sombreador. Nesse caso, duas texturas do Matcap são compactadas em uma e divididas em canais. Ou seja, metal e não metal nos canais R e G, respectivamente.



Dois Matcaps são interpolados, por exemplo, por verificador.



O resultado é uma certa analogia com metal e não metal como no sombreamento PBR.

Queríamos adicionar rugosidade e sujeira aos materiais, para criar algum tipo de analógico de rugosidade no sombreamento PBR. Para fazer isso, usamos o método de texturização.mapeamento mip . Uma sequência de texturas cria a chamada pirâmide MIP com uma resolução máxima de 1x1. Por exemplo: 1 × 1, 2 × 2, 4 × 4, 8 × 8, 16 × 16, 32 × 32, 64 × 64, 128 × 128. Cada uma dessas texturas é chamada de nível MIP. Para implementar arranhões no sombreador pixel por pixel, com base na máscara, é necessário selecionar o nível MIP necessário. Acontece assim: onde o pixel na máscara é preto, o nível máximo de MIP é selecionado no Matcap e onde a cor do pixel é branca, o nível de MIP é 0.





Como resultado, o sombreador permite simular reflexões e realces, adicionar rugosidade e arranhões leves. E tudo isso sem o uso do Cubemap, sem cálculos complexos de iluminação e outras técnicas que reduzem significativamente o desempenho de dispositivos móveis.



Configurando o Substance Painter para criar um shader


Todos os shaders disponíveis no Pintor de substâncias são escritos em GLSL.
Especificamente, para escrever um shader para o Substance Painter, eu uso o código VS gratuito. Para realçar a sintaxe, é melhor usar o suporte de idiomas do Shader para a extensão do VS Code.



Há muito pouco material sobre a API no Substance Painter, portanto, a documentação padrão encontrada na Ajuda / Documentação / Shader API não tem preço.



A segunda coisa que ajudará a escrever o shader é o shaders padrão no Substance Painter. Para encontrá-los, vá para ... / Allegorithmic / SubstancePainter / resources / shelf / allegorithmic / shaders.

Vamos tentar escrever o shader apagado mais simples que mostrará a cor Base. Primeiro, crie um arquivo de texto com a extensão .glsl e escreva um shader tão simples. Talvez, enquanto nada estiver claro, eu lhe falarei mais sobre a estrutura do shader no Substance Painter.



Crie um novo projeto e arraste o shader para o seu shell. Na lista suspensa Importar seus recursos para , selecione o projeto 'project_name' .



Isso é necessário para que todas as alterações possam ser atualizadas.

Agora vá para Window / Views / Shader Settings e selecione seu novo shader na janela que aparece. Você pode usar a pesquisa.



Se você vir que o modelo inteiro é branco e pode desenhar a cor Base nele, fez tudo certo. Agora você pode salvar o projeto e ir para a próxima seção.



Se o modelo for rosa, provavelmente haverá um erro no sombreador - uma notificação sobre isso estará no console.

Construindo um shader no Substance Painter


Considere a estrutura de um shader usando o shader apagado descrito anteriormente como exemplo.



O método de sombra é a parte básica do shader; ele não funcionará sem ele. Tudo o que será descrito dentro pode ser exibido em um modelo 3D. Todos os cálculos finais são produzidos através da função diffuseShadingOutput () .

As linhas 3 e 4 criam um parâmetro e uma variável, respectivamente. O parâmetro associa o canal de cores Base à variável na qual a textura pintada será armazenada. Todos os parâmetros estão explicitados na ajuda ; no caso da cor Base, tudo deve ser escrito como no exemplo. A linha 8 apresenta a textura nas coordenadas uv do modelo 3D. Observo que, para a textura com cor Base, o sistema Sparse Virtual Textures é usado , porque a biblioteca está conectada com a primeira linhalib-sparce.glsl .

Você pode encontrar muitas implementações do Matcap, mas seu ponto principal é que as normais do modelo são direcionadas para a câmera e a textura é girada ao longo dos eixos xe y. Para girar o normal em direção à câmera, precisamos visualizar a matriz ou o tipo de matriz . Você pode encontrar um no certificado mencionado acima.



Portanto, esses são os mesmos nomes declarados como no caso da cor Base. Agora precisamos obter as normais do modelo 3D.


Zero como o quarto elemento do vetor é necessário.

Multiplicar uma matriz de vista com um vetor normal expandirá o normal para a câmera.



Não esqueça que, ao multiplicar matrizes, a ordem dos fatores é importante. Se você alterar a ordem da multiplicação, os resultados serão diferentes.

Agora você pode criar coordenadas uv a partir do viewNormal .



É hora de ligar a textura matcap.



Nesse caso, o parâmetro criará um campo de textura na interface do sombreador e, se o projeto tiver uma textura com o nome "Matcap_mip", o Substance Painter o puxará para cima automaticamente.



Vamos verificar o que aconteceu.



Aqui, a textura do Matcap é expandida em novas coordenadas e multiplicada pela cor Base na saída. Quero prestar atenção ao fato de que a textura Matcap é expandida através da função texture () e da cor Base - através da função textureSparse () . Isso ocorre porque as texturas especificadas na interface do sombreador não podem ser do tipo SamplerSparse .

O resultado deve ser algo como isto:



Agora adicione uma máscara que misture dois Matcap's. Por conveniência, adicione dois Matcap'a em uma textura, dividindo-os em canais. Como resultado, duas texturas Matcap estarão nos canais R e G, respectivamente.

Acontecerá algo como isto:



Vamos começar a adicionar uma máscara ao shader. O princípio é semelhante à adição da cor Base.



É suficiente substituir o valor da cor básica por user0 no parâmetro

Agora obtenha o valor da máscara no pixel shader e misture as texturas matcap.



Aqui, apenas o canal R é usado na máscara, porque será preto e branco. Os dois canais matcap são misturados usando a função mix () , um análogo do lerp no Unity.

Vamos atualizar o sombreador e adicionar canais personalizados na interface. Para fazer isso, vá para Window / Views / Texture Set Settings, na janela próxima ao cabeçalho Canais, clique no sinal de mais e selecione usuário0 na lista grande.



O canal pode ser chamado como você quiser.

Agora, desenhando neste canal, você pode ver como as duas texturas do Matcap são misturadas.



O sombreador do Unity também usava mapas normais para o Matcap, que eram feitos a partir de um modelo de alto poli. Vamos tentar fazer o mesmo no Pintor de substâncias.

Para usar todas as operações em normais, você precisa conectar a biblioteca apropriada :



Agora, conectamos os mapas normais. Existem dois deles no Substance Painter: um é obtido por cozimento e o segundo pode ser desenhado.



De acordo com os parâmetros, você pode adivinhar que channel_normal é um mapa normal, de acordo com o qual você pode desenhar, e texture_normal- mapa normal assado. Também observo que o nome da variável texture_normal está incorporado na API e você não pode nomeá-lo a seu critério.

Em seguida, descompacte os cartões no pixel shader:



Em seguida, misturamos os mapas normais e os normais que estão nos vértices do modelo. Para fazer isso, na biblioteca conectada acima, há uma função normalBlend () .



Primeiro misturamos os dois mapas normais e depois os normais normais. Embora realmente não importe em qual ordem misturá-los.

A rotação dos normais na direção do olhar da câmera ficará assim:



Então você não pode mudar nada, tudo permanecerá o mesmo. Deve ser algo como isto:



O mapeamento Mip, como mencionado acima, neste caso é necessário para simular arranhões, algo como uma placa de rugosidade no sombreamento PBR. Mas o principal problema é que a pirâmide dos cartões mip não é gerada para a textura, que é transmitida a partir da interface do shader e, portanto, o método textureLod () da glsl não funciona. Pode-se ir para o outro lado e carregar a textura do Matcap através do canal do usuário, como foi feito para misturar o Matcap. Mas então a qualidade da textura diminuirá bastante e artefatos estranhos aparecerão.

Uma solução alternativa é criar uma pirâmide de cartões MIPmanualmente, no Adobe Photoshop ou outro editor semelhante, e selecione o nível MIP. A pirâmide é construída de maneira bastante simples. É necessário proceder a partir do tamanho da textura original - no meu caso, é 256x256. Criamos um arquivo com um tamanho de 384x256 (384, porque 256 + 256/2) e agora reduzimos a textura original pela metade até que ele tenha um pixel de tamanho. Todas as versões de texturas reduzidas são colocadas à direita da textura original em ordem crescente. Deverá ocorrer da seguinte maneira:



Agora você pode começar a escrever uma função que encontre as coordenadas de cada textura na pirâmide, dependendo da cor de cada pixel na máscara.

A maneira mais fácil é armazenar as coordenadas uv que serão calculadas para cada textura em uma matriz. O tamanho da matriz será determinado como log2 (altura). Como precisamos do uv original , os adicionamos ao argumento da função. Para determinar qual elemento da matriz usar em um pixel específico, adicione nível ao argumento da função.



Agora calcule uv para a textura original, ou seja, corte os 128 pixels extras de largura. Para fazer isso, multiplique a coordenada x por ⅔.



Para usar o restante da textura da pirâmide, você precisa encontrar padrões. Quando criamos a pirâmide a partir das texturas, percebemos que cada vez que a textura é reduzida pela metade em relação ao tamanho anterior. Ou seja, quantas vezes o tamanho da textura diminui, você pode determinar aumentando 2 para a potência do nível MIP .



Acontece que, se você selecionar o nível, por exemplo, 4, a textura diminuirá 16 vezes. ComoAs coordenadas uv são determinadas de 0 a 1, então o tamanho precisa ser normalizado, ou seja, 1 dividido por quantas vezes a textura diminuiu, por exemplo, 1 dividido por 16.

Usando o valor obtido da variável size, você pode calcular as coordenadas para um nível MIP específico .



O tamanho do uv é reduzido da mesma maneira que o tamanho da textura. Na coordenada x, a textura sempre muda em ⅔. O deslocamento da coordenada y pode ser definido como a soma de todos os valores da variável de tamanho para cada valor de nível . Ou seja, se o valor for nível = 1 , uv na coordenada y mudará em 0 pixels e, se nível = 2 , a mudança será metade da altura da textura - 128 pixels. Se nível = 3, a mudança será 128 + 64 pixels e assim por diante. A soma de todos os turnos pode ser obtida usando o ciclo.



Agora, a cada iteração, a variável de deslocamento adicionará e mudará a textura ao longo do eixo y pelo número desejado de pixels. O algoritmo passo a passo é mais ou menos assim:



O último passo é exibir um canal que selecionará o nível desejado em cada pixel. Já fizemos isso, nada de novo.





Para selecionar o nível MIP como uma textura, apenas multiplique o comprimento da matriz pela textura. Agora você pode conectar novas coordenadas uv através do método que acabamos de escrever.



Não se esqueça de converter a textura no tipo int, pois agora é um índice para a matriz.
Em seguida, você precisa adicionar um canal personalizado no Substance Painter, como fizemos anteriormente. Deveria acontecer assim:





a única coisa que falta para o shader é a fonte de luz e a capacidade de girá-lo pressionando shift. Antes de tudo, para isso, precisamos de um parâmetro que produza o ângulo de rotação pressionando shift e a matriz de rotação .





Colocamos aleatoriamente a fonte de luz e multiplicamos a posição pela matriz de rotação.



Agora a fonte de luz irá girar em torno do eixo y pressionando shift, mas até agora este é apenas um vetor no qual a posição da fonte de luz é armazenada. Há coisas boascomo implementar luz direcional em um shader. Vamos nos concentrar nele. Resta determinar a direção da luz e a iluminação do nosso modelo.



A cor da sombra e a cor da fonte de luz serão definidas pelos parâmetros:



Os parâmetros de cor são interpolados de acordo com a iluminação calculada acima.



Acontecerá assim:



Usando esses parâmetros, você pode ajustar a cor da sombra e a cor da fonte de luz através da interface do Substance Painter.



Criar e configurar uma predefinição


Quando o shader estiver pronto, você precisará importar a textura Matcap e o shader com a configuração de prateleira.



Removemos todos os canais não utilizados e adicionamos canais de usuário: a



predefinição para exportar texturas será semelhante a qualquer outra, exceto pelo uso de nossos canais personalizados.



Criaremos um modelo para todas as configurações para que, quando você criar o projeto, o sombreador desejado seja imediatamente atribuído e todos os canais de textura sejam configurados. Para fazer isso, vá para File / SaveAsTemplate e salve o modelo.



Agora, ao criar um novo projeto, você não precisa configurar nada. Basta selecionar o modelo desejado.



O que você conseguiu


Um artista técnico pode criar efeitos especiais, personalizar cenas e otimizar os processos de renderização. Eu também queria que os modelos de armaduras e armas de Stormfall: Saga of Survival fossem exatamente o que os artistas em 3D pretendiam. Como resultado, o modelo 3D no Substance Painter parece o mesmo que no mecanismo do jogo.


Modelo 3D no Pintor de substâncias com sombreamento personalizado.


Modelo 3D no Unity com sombreamento personalizado.

Espero que o artigo tenha sido útil e tenha inspirado você a novas conquistas!

All Articles