Como posso implementar uma iluminação suave baseada em ladrilhos?


8

Eu tenho trabalhado em um jogo de peças 2D e implementei iluminação com arestas:

insira a descrição da imagem aqui

Eu quero que seja suavizado um pouco. Não preciso de sombras nem nada, apenas iluminação simples. Eu gostaria que parecesse mais com isso:

insira a descrição da imagem aqui

Meu sistema atual usa níveis de luz para cada bloco do mundo e eles são recalculados quando um bloco é colocado ou removido. Estou usando batch.setColor(...)para sombrear os azulejos. Qual é uma boa maneira de obter essa iluminação suave?

Não quero usar o método de sobreposição de mapas leves, já tentei e não fiquei satisfeito com o resultado. Quero poder definir quanta luz é capaz de passar através de um bloco. Por exemplo, um bloco de terra deve absorver um pouco da luz, mas um bloco de vidro não deve bloquear nenhuma luz. Isso não era realmente possível com o método de sobreposição do mapa de luz. UPDATE: Eu não entendi o que esse método realmente é. Eu entendo agora. Eu estava pensando da maneira errada. Desculpa!


Para ser honesto, parece mais elegante com iluminação de arestas.
S. Tarık Çetin 27/07/16

Eu não gosto muito, também é um pouco difícil diferenciar os ladrilhos de fundo e os de primeiro plano com esse estilo.
ProRed 27/07/16

Respostas:


15

Uma maneira simples de obter uma iluminação suave em um jogo baseado em blocos é desenhar um "mapa de luz" para um alvo de renderização e, em seguida, desenhar esse alvo de renderização por cima de sua cena enquanto o alfa é misturado.

O destino de renderização do seu mapa claro seria do tamanho do seu mapa de blocos, mas em pixels. Cada pixel representaria a cor clara de seu bloco correspondente. Essa textura de renderização ficaria assim: (textura superior esquerda em preto e branco):

insira a descrição da imagem aqui

Depois de ter essa textura leve do mapa, você pode desenhá-la como uma sobreposição no seu mundo de jogo (estendido). Você terá que prendê-lo adequadamente, para que ele se estenda perfeitamente sobre suas peças no mundo do jogo.

Então é uma questão de alfa misturar essa textura no seu mundo de jogo no libGDX. Para se misturar ao LibGDX (eu pessoalmente não sei como), você pode precisar examinar a Gdx.gl.glBlendFuncfunção.


2
Você pode controlar a iluminação da maneira que desejar com este sistema. Não sabe ao que você está se referindo quando diz que não pode bloquear a luz. Além disso, não sabe ao certo como planeja suavizar seu sistema atual, pois você está literalmente apenas colorindo seus ladrilhos.
jgallant

4
A propósito, esse sistema é o que a Starbound faz.
Qqwy

2
Essa é uma ótima abordagem e permite flexibilidade onde é necessária. Eu uso isso no meu jogo baseado em blocos, onde não tenho acesso a shaders, e funciona muito bem!
21416 Typedpi_77 às

11
ATUALIZAÇÃO : Este parece ser o caminho a seguir, eu não entendi esse método e agora entendo completamente! Vou tentar implementar esse método agora e vou marcar como a melhor resposta e dar a você a recompensa!
ProRed 27/07/16

2
Se você tiver mais perguntas sobre como fazê-lo, não hesite em perguntar. Eu implementei isso, e o @ Tyyppi_77 também o fez recentemente. Eu fiz isso no XNA / Monogame e no Unity. Tyyppi fez isso em SDL.
precisa saber é

4

Uma maneira independente de fazer isso é usar o mapeamento médio da luz. Primeiro, você precisa gerar um mapa em preto e branco como uma matriz 2D de booleanos que é do tamanho do mundo em que os blocos são True e vazios são False.

Assim (1 é preto, 0 é branco): mapa

Em seguida, você precisa criar uma nova matriz 2D que tenha o mesmo tamanho da primeira matriz, mas que seja uma matriz de flutuadores. Depois, você passa do bloco preto (True) para o bloco preto na matriz e calcula a média do valor amostrado próximo (explicado abaixo)

Esta imagem ajudará: média

Esta imagem representa a amostragem (onde + significa falso e | significa verdadeiro). o que fazemos é tratar valores verdadeiros como 1 e valores falsos como 0. Então você calcula a média dos 9 números e os coloca na parte correta da matriz. NOTA: Certifique-se de que, quando estiver amostrando arestas, use valores externos como sensíveis ao contexto. Por exemplo: no subsolo o mapa fora do mundo pode ser 1 e o céu deve ser 0.

Deve ficar assim (tirado de outra postagem):fim

Então tudo o que você precisa fazer é colorir cada bloco na matriz com

rgba(tint,tint,tint,1)

(matiz = o valor médio atual do bloco na segunda matriz e alfa não importa). Nota: isto pressupõe que a pseudo-função rgba recebe flutuadores de 0-1 em vez de 0-255, se o fizer, faça o seguinte:

rgba(tint*255,tint*255,tint*255,255)

Espero que isso faça um pouco de sentido :) Se você quiser código, pergunte!


Primeiro, obrigado pela sua resposta, mas o problema é que eu já tenho iluminação de ponta no meu jogo ( aqui ). Eu perguntei como eu poderia mudar isso para parecer mais suave ( assim ).
ProRed 26/07/16

1

Como você está falando sobre coisas bloqueando a luz, suponho que você tenha algum modelo de como a luz deve se espalhar. Por exemplo, tudo sem blocos acima está completamente aceso, a luz se espalha para todas as células vizinhas, mas perde uma certa quantidade de brilho.

Você deve ser capaz de implementar essas regras com bastante facilidade no lado do software, pelo menos a parte de suavização é apenas uma questão de jogar shader no mapa de luz que você gerou.

Os métodos sugeridos por outras pessoas sobrepondo um mapa claro é algo que você deve fazer de qualquer maneira. Mas você pode mudar a forma como gera esse mapa de luz. Inicialmente, você pode preenchê-lo apenas com as informações do bloco, mas pode escaloná-lo e suavizá-lo em um sombreador, por exemplo. Um benefício adicional da abordagem do mapa de luzes é que você pode simplesmente atrair luzes dinâmicas para o seu mapa de luzes, assim como destacar as explosões ou o que você tem e ele naturalmente se misturará com o resto do seu mundo.

Aditivo mistura coisas em seu mapa de luz, em seguida, multiplicativo mistura seu mapa de luz com o mundo do jogo.

Eu fiz isso há um tempo atrás, que usa os mesmos princípios. Este sistema não suporta ter queda de luz diferente para diferentes tipos de terreno, mas pelo menos deve ilustrar a utilidade de sobrepor um mapa de luz.


Entendo, então eu renderizaria os níveis de luz em forma de retângulos exatamente do tamanho do bloco correspondente a um segundo destino de renderização? E como eu suavizaria isso?
ProRed 27/07/16

Você pode permitir que a GPU lide com ela, reduzindo a amostragem, pois, ao renderizá-la, será interpolada linearmente para você. Se isso não for bom o suficiente, você pode executar algum tipo de desfoque em um sombreador. Você também pode considerar renderizar com granularidade mais fina que a resolução do bloco, se desejar desenhá-lo de maneira diferente, dependendo dos blocos adjacentes. Basicamente, a parte difícil é apresentar as regras específicas que você deseja para qual área deve ser iluminada quanto. Se você escrever essas regras, geralmente encontrará uma maneira bastante direta de fazer isso.
Nils Ole Timm

1

É muito fácil para uma tocha: usando um sombreador de pixel personalizado, você calcula a distância entre cada fragmento e a tocha; você pode calcular onde o primeiro bloco denso que bloqueia a luz proveniente da tocha. Em seguida, você calcula a distância em que a luz não está bloqueada, multiplique por algo <1 para que a tocha não acenda o sol, subtraia-o da distância total e repita o restante da distância (onde a luz foi bloqueada por menos um bloco) com um valor multiplicado bem menor ... Eu sei como fazer essa matemática e não é muito complicado de implementar em opengl.

EDIT: para uma fonte de luz simples com um ponto central específico, meu método é extremamente simples. No entanto, o meu não funciona com a luz do sol, mas, embora o mapa alfa funcione muito bem para a luz do sol, NÃO seria uma boa idéia para uma tocha, uma vez que é potencialmente um objeto em movimento, e fazer um novo mapa a cada quadro não é agradável. experiência de vida. A melhor solução na minha opinião é uma mistura: cálculo da distância para luzes específicas que são realmente objetos no jogo, um sombreador separado que você coloca no topo do mapa alfa que você gerou processualmente usando a técnica mencionada acima: uma textura de tudo os azulejos alfas do seu sombreamento rígido, como muitos quadrados, e mexem com técnicas para suavizá-lo.


0

Sua renderização usa cores de vértice (ou você pode alterá-la)?

Supondo que cada bloco seja um quadrado de 4 vértices, você daria algumas opções, por exemplo:

Se o seu algoritmo de iluminação atual fornecer um valor de luz por bloco, você poderá alterá-lo para fornecer um valor por vértice. Como alternativa, em cada vértice você pode calcular a média da cor clara do bloco atual mais seus três vizinhos. Qualquer solução seria barata.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.