Estou tentando implementar um efeito de iluminação em um jogo HTML5 / JavaScript usando a substituição de blocos. O que tenho agora é meio que trabalho, mas as transições não parecem suficientemente suaves / naturais à medida que a fonte de luz se move. Aqui está onde estou agora:
- No momento, tenho um mapa de plano de fundo que possui uma planilha PNG de espectro de luz / sombra aplicada, passando do azulejo mais escuro ao transparente. Por padrão, o bloco mais escuro é desenhado em todo o nível no lançamento, cobrindo todas as outras camadas, etc.
- Estou usando meus tamanhos predeterminados de bloco (40 x 40px) para calcular a posição de cada bloco e armazenar suas coordenadas xey em uma matriz.
- Em seguida, estou gerando uma entidade "bloco de grade" transparente de 40 x 40px em cada posição na matriz
- O mecanismo que estou usando (ImpactJS) permite calcular a distância da minha entidade de fonte de luz a todas as instâncias dessa entidade de bloco de grade.
- Posso então substituir o ladrilho embaixo de cada um desses ladrilhos de bloco de grade por um ladrilho da transparência apropriada.
Atualmente, estou fazendo o cálculo como este em cada instância da entidade do bloco de grade que é gerada no mapa:
var dist = this.distanceTo( ig.game.player );
var percentage = 100 * dist / 960;
if (percentage < 2) {
// Spawns tile 64 of the shadow spectrum tilesheet at the specified position
ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, 64 );
}
else if (percentage < 4) {
ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, 63 );
}
else if (percentage < 6) {
ig.game.backgroundMaps[2].setTile( this.pos.x, this.pos.y, 62 );
}
// etc...
O problema é que, como eu disse, esse tipo de cálculo não faz a fonte de luz parecer muito natural. A mudança de lado a lado parece muito nítida, enquanto, idealmente, eles entrariam e sairiam suavemente usando a folha de espetro (copiei a folha de outro jogo que consegue fazer isso, por isso sei que não há problema com as tonalidades dos ladrilhos.) como o outro jogo está fazendo isso). Eu estou pensando que talvez meu método de usar porcentagens para trocar de lado a lado possa ser substituído por um fórum de proximidade melhor / mais dinâmico de algum tipo que permita transições mais suaves? Alguém pode ter alguma idéia do que eu posso fazer para melhorar o visual aqui, ou uma maneira melhor de calcular a proximidade com as informações que estou coletando sobre cada bloco?
(PS: Estou reeditando isso do Stack Overflow por sugestão de alguém, desculpe pela duplicação!)
fonte
Respostas:
Antes de tudo, desculpe-me por não poder ajudá-lo com sua plataforma específica, pois nunca fiz esse tipo de trabalho em HTML5. Então, tentarei abordar isso de uma maneira independente da linguagem.
Eu não acho que você conseguirá transições suaves se estiver calculando a luz em uma base por peça . Isso é análogo às diferenças entre o uso de sombreamento simples, sombreamento gouraud ou sombreamento phong:
O que você está fazendo é semelhante ao sombreamento plano, ou seja, você está atribuindo uma luz diferente por bloco, o que resulta em transições nítidas entre os blocos, conforme demonstrado na figura acima.
Para obter melhores resultados, você terá que calcular suas luzes por vértice (ou seja, gouraud). Não sei quais são as capacidades do seu mecanismo, mas o caso ideal seria se cada um de seus blocos fosse um quad e você tivesse acesso direto aos seus vértices. Então você seria capaz de calcular a distância da luz para cada vértice e armazenar sua cor de tonalidade bem dentro do vértice. Finalmente, o pipeline de renderização cuidaria automaticamente da interpolação das sombras nas superfícies do ladrilho, resultando em uma aparência mais suave (também conhecida como sombreamento de gouraud ).
Para obter resultados ainda melhores, embora um pouco mais caros, você pode calcular a luz por pixel (isto é, phong) dentro do shader de fragmento. A abordagem básica funciona bem se você tiver apenas algumas luzes para provar, como parece ser o caso do seu exemplo.
Por fim, outra alternativa que pode funcionar muito bem é renderizar todas as suas luzes (e somente suas luzes) em um destino de renderização separado primeiro, opcionalmente embaçar o resultado e misturá-lo com o restante da cena no final. Verifique esta pergunta para algumas idéias sobre isso.
fonte
Você parece estar iluminando com uma atenuação linear (sua intensidade de luz está diminuindo linearmente). Você pode tentar usar a lei do quadrado inverso . Ou uma simples queda exponencial.
O código acima também ajuda você a se livrar da
if
else if
coisa atroz que está acontecendo.Uso apenas uma queda exponencial básica e obtenho resultados como este (posso postar uma imagem melhor posteriormente de uma única fonte de luz, só não tenho uma no momento):
Também devo mencionar que um programa como o Excel é ótimo para coisas como essa. Você pode testar as alterações de fórmula rapidamente e fazer um gráfico delas ou usar regras condicionais para alterar a cor de uma célula.
fonte
if else if
cadeia. Crie um método que mapeie a porcentagem para indexar o bloco e substitua todas as ramificações por uma única chamada,setTile
como no exemplo do Byte56.