Criando grama interativa no Unreal Engine


Até recentemente, a grama nos jogos era geralmente indicada por uma textura no chão, em vez de renderizar caules individuais. Mas com o aumento do poder do ferro, tornou-se possível produzir grama. Grandes exemplos dessa renderização podem ser vistos em jogos como Horizon Zero Dawn e The Legend of Zelda: Breath of the Wild . Nesses jogos, o jogador pode percorrer os prados de grama e, mais importante, a grama responde às ações do jogador.

Felizmente, criar um sistema desse tipo não é muito difícil. De fato, o artigo ensinará exatamente isso! Neste tutorial, você aprenderá o seguinte:

  • Crie um campo vetorial usando um sistema de captura de cenas e partículas
  • Dobre a grama de um jogador com base em um campo vetorial
Nota: este tutorial pressupõe que você já conhece os conceitos básicos de trabalho com o Unreal Engine. Se você é novo no Unreal Engine, confira nossa série de dez partes de tutoriais do Unreal Engine para iniciantes . Em particular, consulte o tutorial Particle Systems para saber como usar o Cascade neste tutorial.
Nota: este tutorial faz parte de uma série de três tutoriais sobre como trabalhar com destinos de renderização:

Começando a trabalhar


Vamos começar baixando os materiais deste tutorial (você pode baixá-los aqui ). Descompacte-os, vá para InteractiveGrassStarter e abra InteractiveGrass.uproject . Você verá um pequeno campo de grama que será o tema deste tutorial. Também criei um widget para exibir o destino de renderização da captura de cena.



Antes de começar, você deve estudar o tutorial sobre como criar pegadas na neve , porque vou pular algumas informações. Vale a pena considerar que a captura e a projeção também são usadas neste tutorial. Para economizar tempo, preparei uma captura de planta, semelhante à planta do tutorial sobre as trilhas na neve.

Para começar, vejamos outra maneira de criar grama interativa. A maneira mais comum é transferir as coordenadas do jogador para o material da grama e usar uma máscara esférica para dobrar a grama em um determinado raio do jogador.

Embora essa abordagem seja muito boa, ela não aumenta quando queremos adicionar mais atores à grama. Para cada ator que você adicionar, você precisará adicionar outro parâmetro de coordenada e uma máscara esférica ao material. Um método mais escalável é usar um campo vetorial .

O que é um campo vetorial?


Um campo vetorial é apenas uma textura, cada pixel corresponde a uma direção. Se você costumava trabalhar com mapas de fluxo, eles são semelhantes. Mas, em vez de mover UV, usaremos o contato Deslocamento da posição mundial para mover os vértices. Ao contrário da solução com uma máscara esférica, para obter a direção da flexão, é suficiente que os materiais provem o campo vetorial apenas uma vez .

Vamos descobrir como você pode salvar as direções em uma textura. Veja esta grade:


Digamos que o ponto vermelho é o objeto que queremos mover. Se o movermos para o canto inferior direito, qual vetor denotará esse movimento? Se você respondeu (1, 1) , está certo! Como você provavelmente sabe, também pode representar vetores como flores e, assim, salvá-los em textura. Vamos inserir esse vetor no seletor de cores Unreal e ver qual cor ele retorna.


Como você pode ver, a direção (1, 1) retorna em amarelo. Isso significa que, se queremos dobrar a grama na direção dos eixos XY positivos, teremos que usar essa cor de textura. Vamos agora olhar para as cores de todos os vetores.


O quadrado inferior direito parece muito bom porque possui gradientes nos dois eixos. Isso significa que podemos armazenar qualquer vetor nesse quadrante como uma cor, porque cada vetor tem uma cor única.

Mas há um problema com os outros três quadrantes. Temos apenas um gradiente ao longo de um eixo, ou nenhum gradiente. Isso significa que vários vetores terão a mesma cor. Por exemplo, não podemos distinguir entre os vetores (-1, 1) e (0, 1) .

Esses três quadrantes não têm cores exclusivas para cada vetor, porque só podemos representar cores usando valores de 0 a 1. no entanto, esses três quadrantes usam valores negativos fora desse intervalo.

A solução é redistribuir os vetores para que todos eles se ajustem no intervalo de 0 a 1. Isso pode ser feito multiplicando o vetor por 0,5 e adicionando 0,5 . Aqui está uma visualização do que obtemos:


Agora cada vetor tem uma cor única. Quando precisamos usá-lo para cálculos, simplesmente o redistribuímos de volta para o intervalo de -1 a 1. Aqui estão algumas cores e as direções correspondentes após a redistribuição:

  • (0, 0): X e Y negativos
  • (0,5, 0,5): sem movimento
  • (0, 1): X negativo e Y positivo
  • (1, 0): X positivo e Y negativo

Agora vamos aprender como criar um campo vetorial no Unreal.

Criando um campo vetorial


Ao contrário de criar traços na neve, não realizaremos a captura da forma dos objetos. Em vez disso, pintaremos o alvo de renderização com pincéis. Estas serão apenas imagens do campo vetorial selecionado. Vou chamá-los de pincéis de direção .

Em vez de desenhar no alvo de renderização com embotamentos, podemos usar partículas . As partículas exibirão um pincel de instruções e emitidas pelo player. Para criar um campo vetorial, basta usar a captura de cena e capturar apenas partículas. A vantagem deste método é que a criação de rastreios é muito simples. Além disso, permite gerenciar facilmente propriedades como a duração do armazenamento de trilhas e seu tamanho. Além disso, as partículas criam traços temporariamente persistentes, porque existem após deixar a área de captura e retornar a ela.

Abaixo estão alguns exemplos de pincéis direcionais que podemos usar, bem como seus efeitos na grama. Observe que no exemplo abaixo, as partículas são invisíveis.


Para começar, vamos criar um material que exibirá um pincel de direção.

Criando material para direções


Existem duas maneiras de criar um pincel de direção:

  1. Matemático: direções e forma são definidas dentro do material. Sua vantagem é que ele não requer software de terceiros e é conveniente para formulários simples.
  2. Conversão normal de mapa: crie um mapa normal das direções e formas desejadas. Para converter o mapa em um campo vetorial adequado, basta remover o canal azul. A vantagem desse método é que você pode facilmente criar formas complexas. Abaixo está um exemplo de um pincel que será difícil criar matematicamente.


Para este tutorial, criaremos um pincel matematicamente. Vá para a pasta Materiais e abra M_Direction . Observe que o modelo de sombreamento Unlit está selecionado para este material. Isso é importante porque permite a captura de uma cena para capturar partículas sem afetá-las.

Para não complicar, criaremos um material que fará com que a grama se afaste do centro da partícula. Para fazer isso, crie o seguinte esquema:


Agora precisamos redistribuir. Para fazer isso, adicione os nós selecionados e conecte tudo da seguinte maneira:


Agora vamos dar ao pincel uma forma redonda. Para fazer isso, adicione os nós selecionados:


RadialGradientExponential controla o tamanho e a nitidez da circunferência do círculo. A multiplicação pela cor de partículas permite controlar a opacidade das partículas do sistema de partículas. Vou discutir isso em mais detalhes na próxima seção.

Aqui está a aparência do pincel:


Clique em Aplicar e feche o material. Agora que criamos o material, é hora de embarcar em um sistema de traços de partículas.

Criando um sistema de traços de partículas


Vá para a pasta ParticleSystems e abra PS_GrassTrail . Para economizar tempo, eu já criei todos os módulos necessários.


Veja como cada módulo afeta as pegadas da grama:

  • Spawn: a frequência da criação afeta a suavidade das faixas. Se as faixas parecerem intermitentes, você deverá aumentar a frequência de criação. Neste tutorial, deixaremos o valor padrão (20).
  • Vida útil : a vida útil da trilha até que a grama retorne ao seu estado original
  • Tamanho inicial: tamanho do traço
  • Cor ao longo da vida: como usamos a cor de partículas no material, você pode controlar a opacidade aqui. Você também pode alterar a curva alfa para controlar o desaparecimento da faixa. Por exemplo, você pode escolher o desaparecimento linear, facilitando a entrada e / ou saída. Neste tutorial, deixaremos a configuração padrão, ou seja, perda linear.
  • Eixo de bloqueio: usado para direcionar partículas em direção à captura de cena
  • Rotação inicial: usada para garantir que as partículas sejam orientadas ao longo dos eixos corretos (mais sobre isso abaixo)

Primeiro, precisamos definir o material. Selecione o módulo Necessário e defina Material como M_Direction . Defina também o Modo de classificação como PSORTMODE Age Newest First .


Este modo de classificação permite renderizar novas partículas sobre as antigas. Se isso não for feito, não será novo, mas as partículas antigas afetarão a grama.

A seguir, é a duração do rastreamento. Selecione o módulo Lifetime e defina Constant como 5 . Graças a isso, o rastreamento desaparecerá dentro de cinco segundos.


Agora vamos para o tamanho do rastreamento. Selecione o módulo Tamanho inicial e defina a constante como (150, 150, 0) . Devido a isso, cada partícula cobrirá uma área de 150 × 150.


Agora precisamos fazer com que pareça na direção de capturar a cena. Como a cena é capturada de cima, as partículas devem olhar na direção do eixo Z positivo. Para fazer isso, selecione o módulo Lock Axis e defina os Flags Lock Axis como Z.


Finalmente, precisamos definir a rotação das partículas. Atualmente, as cores do pincel não estão alinhadas com a direção que representam. Isso aconteceu porque, por padrão, o sistema de partículas é aplicado com uma rotação de 90 graus. Para corrigir isso, selecione o módulo Rotação Inicial e defina o valor Constante como -0,25 . Isso irá girar as partículas 90 graus no sentido anti-horário.


E é tudo o que precisamos para o sistema de partículas, então vamos fechá-lo.

Em seguida, precisamos anexar um sistema de partículas ao que é suposto criar traços. No nosso caso, precisamos anexá-lo ao personagem do jogador.

Anexando sistema de partículas


Vá para Characters \ Mannequin e abra BP_Mannequin . Em seguida, crie o componente Sistema de partículas e denomine GrassParticles .


Em seguida, precisamos definir um sistema de partículas. Vá para o painel Detalhes e defina Particles \ Template como PS_GrassTrail .


Seria estranho se o jogador pudesse ver a pista no jogo, então vale a pena escondê-la. Para fazer isso, ative Rendering \ Owner No See .


Como o sistema de partículas está conectado ao jogador (proprietário), o jogador não o verá, mas ficará visível para todo o resto.

Clique em Compilar e, em seguida, clique em Executar . Observe que as partículas não aparecem na câmera do jogador, mas são exibidas no alvo de renderização.


Até agora, a captura de cena está configurada para capturar tudo . Obviamente, isso não nos convém, porque apenas partículas afetam a grama. Na próxima seção, aprenderemos como capturar apenas partículas.

Captura de partículas


Se capturarmos partículas agora, realizaremos flexões desnecessárias em áreas sem partículas. Isso ocorre porque a cor de fundo do destino de renderização é preta. A flexão ocorre porque o preto denota um movimento em direção aos eixos XY negativos (após a redistribuição). Para que as áreas vazias não contenham movimento, precisamos renderizar o destino do plano de fundo (0,5, 0,5, 0) . A maneira mais fácil de fazer isso é criar um avião enorme e anexá-lo ao jogador.

Primeiro, crie material para o plano de fundo. Volte ao Navegador de conteúdo e abra Materials \ M_Background . Em seguida, conecte a constante (0,5, 0,5, 0) com a Emissive Color .


Nota: como no material de partículas, qualquer material que capturamos deve ter um modelo de shader apagado .

Clique em Aplicar e feche o material. Volte para BP_Mannequin e crie um novo componente de avião . Nomeie-o como plano de fundo .


Em seguida, defina as seguintes propriedades:

  • Localização: (0, 0, -5000). Colocamos o plano tão baixo que não sobrepõe nenhuma partícula.
  • Escala: (100, 100, 1). Então, escalamos para um tamanho suficiente para cobrir toda a área de captura.
  • Material: M_Background


Assim como as partículas, seria estranho se o jogador visse um enorme avião amarelo por baixo. Para ocultá-lo, ative Rendering \ Owner No See .


Agora que configuramos o plano de fundo, é hora de capturar as partículas. Podemos fazer isso adicionando um sistema de partículas à lista apenas de exibição da captura de cena. Esta é uma lista de componentes que capturam a captura de cena.

Usando a lista Show-Only


Antes de podermos adicionar à lista de exibição apenas, precisamos de uma maneira de obter todos os atores que afetam a grama. Uma maneira de obtê-los é usar tags . Tags são cadeias simples que podem ser atribuídas a atores e componentes. Em seguida, você pode usar o nó Obter todos os atores com tag para obter todos os atores com a tag correspondente.

Como o ator do jogador deve influenciar a grama, ele precisa de uma etiqueta. Para adicionar uma marca, clique no botão Padrões da classe . Em seguida, crie uma nova tag em Actor \ Tags e chame -a de GrassAffector .


Como apenas os componentes podem ser transferidos para a lista de exibição apenas, precisamos adicionar tags aos componentes que afetam a grama. Selecione o componente GrassParticles e adicione uma nova tag localizada na seção Tags . Nomeie-o GrassAffector também (não é necessário usar essa tag). Repita o mesmo para o componente Background .


Agora, precisamos adicionar componentes que influenciam a grama à lista apenas de exibição de captura de cena. Clique em Compilar e feche BP_Mannequin . Em seguida, abra Blueprints \ BP_Capture . Vá para Event BeginPlay e adicione os nós destacados. Verifique também se os pinos marcados estão conectados.


Este circuito percorrerá todos os atores com a tag GrassAffector . Depois disso, ela verificará se o ator tem componentes com essa tag e os adicionará à lista de exibição apenas.

Em seguida, precisamos dizer à captura de cena para usar apenas a lista de exibição apenas. Selecione o componente SceneCapture e vá para a seção Captura de cena . Defina o Modo de renderização primitivo para usar a lista ShowOnly .


Clique em Compilar e feche o blueprint. Se você clicar em Reproduzir , verá que o alvo de renderização agora captura apenas partículas e o plano de fundo.


Na próxima seção, chegamos ao que esperávamos. É hora de ensinar a grama a se curvar!

Dobre a grama


Primeiro, precisamos projetar o alvo de renderização na grama. Vá para a pasta Materiais e abra M_Grass . Em seguida, crie os nós mostrados abaixo. Defina a textura como RT_Capture .


Como redistribuímos as cores no intervalo de 0 a 1, antes de usá-las, precisamos redistribuir as cores novamente no intervalo de -1 a 1. Para fazer isso, adicione os nós destacados:


Agora que temos a direção de flexão, precisamos de uma maneira de girar a grama nessa direção. Felizmente, existe um nó chamado RotateAboutAxis para isso. Vamos criá-lo.


Vamos começar com o contato NormalizedRotationAxis . Como o nome indica, esse é o eixo em torno do qual o vértice girará. Para calcular, precisamos apenas de um produto vetorial com a direção da dobra por (0, 0, -1) . Para fazer isso, precisamos adicionar os nós selecionados:


Também precisamos especificar o RotationAngle , ou seja, a quantidade de rotação do vértice em relação ao ponto de rotação. Por padrão, o valor deve estar entre 0 e 1, onde 0 é 0 graus e 1 é 360 graus. Para obter o ângulo de rotação, podemos usar o comprimento da direção de flexão, multiplicado pela rotação máxima.


Multiplicar por uma rotação máxima de 0,2 significa que o ângulo máximo de rotação é de 72 graus.

O cálculo do PivotPoint é um pouco mais difícil, porque uma única malha de grama contém vários caules. Isso significa que não podemos usar algo como o nó Posição do objeto , porque ele retornará um único ponto para todas as hastes da grama.

Idealmente, você deve usar um editor 3D de terceiros para salvar pontos de articulação dentro dos canais UV. Mas para este tutorial, apenas aproximamos o ponto de articulação. Isso pode ser feito movendo-se de cima para baixo para um determinado deslocamento.


Para fazer isso, adicione os nós selecionados:


Neste tutorial, a grama tem cerca de 80 unidades de altura, então eu configurei esse valor para PivotOffset .

Em seguida, precisamos executar duas máscaras. A primeira máscara garante que a raiz da haste não se mova. A segunda máscara garante que nenhum campo de vetor atue na grama fora da área de captura.

Mascaramento


Para este tutorial, defino as cores dos topos da grama para que os vértices inferiores sejam pretos e os vértices superiores sejam brancos.


Para mascarar as raízes, simplesmente multiplicamos o resultado de RotateAboutAxis pelo nó Vertex Color .


Para mascarar a grama fora da área de captura, multiplicamos o resultado anterior pelo nó selecionado:


Clique em Aplicar e feche o material. Clique em Play e corra pela grama para deixar pegadas nela!


Para onde ir a seguir?


O projeto finalizado pode ser baixado aqui .

Embora o método mostrado no tutorial funcione muito bem para objetos simples, como grama, não é suficiente ao usar objetos que exigem mais dinamismo. Uma solução parcial para o problema é usar as versões físicas da folhagem. Veja este post sobre folhagem interativa para obter mais informações.

Finalmente, quero agradecer a Deathrey, da comunidade Unreal Engine, pela dica desse método de partículas!

Source: https://habr.com/ru/post/pt420079/


All Articles