Como processar processualmente barras de saúde com formas irregulares?

35

A questão da barra de saúde tradicional retangular ou baseada no coração é algo bem compreendido e facilmente resolvido. Mas qual é a solução aceita para mais barras de saúde "de forma criativa", como a maquete que fiz abaixo?

Saúde vazia Saúde completa, saúde parcial

A maneira óbvia de fazer isso seria ter sprites "intermediários", para que a terceira imagem fosse seu próprio sprite, juntamente com muitas outras transições para diferentes níveis de saúde. Mas isso parece realmente deselegante e o número de entres necessários para criar uma transição suave entre os estados de saúde seria grande.

A única outra idéia que posso ter é sobrepor o sprite de "saúde completa" em cima do sprite de "saúde vazia" e pré-assar conjuntos de coordenadas de pixel para representar cada marca de saúde e torná-las opacas ou transparentes como saúde sobe ou desce.

Pretendo que esta pergunta seja independente da linguagem e da plataforma, mas fique à vontade para fornecer uma amostra concreta em qualquer idioma / biblioteca / estrutura, se isso ajudar na resposta.

msd7734
fonte
5
"N̶a̶n̶o̶m̶a̶c̶h̶i̶n̶e̶s̶ Shaders, filho"
Mukesh Ingham
Eu sinto que essa transição pode ser definida matematicamente, a partir daí você pode ter a calcular computador as coordenadas de pixel para exibir / ocultar em vez de prebaking deles
Richard Tingle
Como a barra de saúde em forma de coração é "facilmente resolvida"?
MooseBoys 28/02
11
@MooseBoys Eu estava falando sobre saúde baseada no coração, não em forma de coração. Pense nos jogos Legend of Zelda. Desculpe por não ser mais claro.
28416 msd7734
@RichardTingle, boa idéia :)
Jon

Respostas:

48

Existe uma maneira muito simples de conseguir isso com shaders, você precisa de três * texturas: barra de saúde vazia, textura e barra de saúde vazias e máscara com gradiente de distribuição de saúde com um extremo (por exemplo, valor alfa mais escuro, não preto ou mais transparente alfa) em uma extremidade e o outro do outro lado. É melhor mostrado na imagem. Atualmente, não consigo desenhar gradiente curvo apenas um linear - mas tenho certeza de que seus artistas não terão problemas: insira a descrição da imagem aqui Agora, no shader, experimente ambas as texturas e limpe o valor da máscara, descartando todos os pixels que não são mais brilhante que o limite de entrada (com base na% de entrada de shader da saúde).
Você poderiause uma fórmula matemática para mascarar em vez de uma textura, mas se você fizer isso, ainda estará muito limitado às formas que você é capaz (= formas simples) de criar com as referidas fórmulas - e encontrar uma não é trivial.
* ver comentários

wondra
fonte
9
Em muitos casos (incluindo o exemplo do OP), usar uma textura separada para cores é um exagero. Na maioria dos casos, você pode remapear apenas o gradiente da máscara em escala de cinza para cores especificadas como uniformes no sombreador, enquanto ainda descarta qualquer valor da máscara abaixo de um determinado limite.
bcrist
11
Na verdade, você não precisa mais escuro, nem preto; pode usar o canal alfa para filtrar os pixels que não deseja.
Jack Aidley
11
@JackAidley com certeza seria possível, mas eu queria a solução o mais flexível possível - na maioria dos títulos AAA, você não tem o hp apenas "vermelho", mas é texturizado.
284166Preço
11
@bistist bom ponto, considerei sugeri-lo como uma otimização. Como não consegui desenhá-lo corretamente, decidi mantê-lo o mais simples possível e deixar a otimização para implementação.
284166Preço
@wondra Em muitos casos, incluindo a aparência de exemplo no OP, você pode usar um gradiente de procedimento ou uma pesquisa de cores unidimensional (com o nível da máscara como entrada), em vez de uma textura.
Random832
34

Implementado matematicamente, como um pixel shader:

Na CPU, calcule o HealthDirection e seu 'produto pontual com V2 insira a descrição da imagem aqui

Na GPU, calcule uma direção normalizada para longe do ponto central de cada pixel. Compare cada produto de ponto com o HealthDirections 'para escolher se sombrear "fundo" ou em cores. insira a descrição da imagem aqui

Se você "inverteu" esse algoritmo e trabalhou na outra direção, poderá "desamarrar" a direção de cada pixel novamente em uma porcentagem e compará-los ao HealthPercent. Com o percentual de cada pixel calculado, a execução do desbotamento de vermelho para verde na GPU se torna trivial.

Desenhe a barra primeiro aplicando o algoritmo a um quad; cores de saída entre rangeMin e rangeMax (pode ser cozido) e clip () ou transparentes em todos os lugares. Em seguida, desenhe o sprite (modificado) sobre ele, usando alfa. Rastreei sua barra em CAD, a preenchi e depois "variei mágica" a forma da cor sólida no Paint para excluí-la. O meu parece uma merda devido à mistura manual do AutoCAD e do Paint; supondo que você combine as bordas internas com transparências, a sua ficará perfeita .

A borda branca é o limite do quad. Ele e os X vermelhos são apenas para referência:

insira a descrição da imagem aqui

O "sprite com furo" não precisa ser renderizado ao mesmo tempo que a barra de saúde. Eles devem ser instanciados e desenhados de uma só vez, depois que todas as barras de saúde estiverem completas. Como o algoritmo é independente no sombreador, você também pode adicionar instancias a ele e desenhar também todas as barras de saúde com uma chamada de instanciação. Desenhar todas as barras de saúde na tela deve receber 2 chamadas DrawInstanced (...) e ser "louco rápido".

Jon
fonte
11
Se você deseja mascarar de maneira circular como essa, pode implementá-lo de forma mais eficiente, alterando os triângulos que você planeja para um desbotamento circular.
Jack Aidley
@JackAidley, por favor, seja mais específico, porque não considero essa máscara; a barra de progresso é totalmente renderizada, no lugar, em apenas dois triângulos, sem amostragem, após a primeira passagem. O sprite tem um buraco nele e "encanta" a coisa toda no final. (É uma máscara do tipo, mas não como parte integrante do algoritmo?) Obrigado
Jon
O que você está fazendo é equivalente a desenhar uma versão mascarada colorida da barra colorida sobre um sprite de fundo que já tem a cor cinza no lugar. Como seu método requer um sombreador personalizado e grava em cada pixel, você acaba com um método mais lento do que desenhar apenas a parte desejada da forma.
Jack Aidley
@JackAidley, mas não há sprite em segundo plano? O arco-íris é desenhado usando apenas quatro posições mundiais float3; sem UV, sem "sprite de fundo". Além disso, você está preocupado com o fato de o pixel shader ficar atolado trabalhando em alguns quadríceps minúsculos? Além disso, RangeMin e RangeMax cortam () a maioria desses fragmentos instantaneamente.
28416 Jon
Você precisará de um sprite de fundo para obter as bordas, como mostra a imagem original; se você os omitir, sim, os métodos são diferentes.
Jack Aidley