Como misturo 2 mapas de luz para o ciclo dia / noite no Unity?


16

Antes de dizer qualquer outra coisa: estou usando mapas de luz duplos, o que significa que preciso misturar um perto e um longe.

Então, eu estou trabalhando nisso há um tempo, tenho um ciclo dia / noite inteiro configurado para renderizadores e iluminação, e tudo está funcionando bem e não exige muitos processos.

O único problema que estou tendo é descobrir como combinar dois mapas de luz. Eu descobri como alternar mapas de luz, mas o problema é que parece meio abrupto e interrompe a experiência.

Eu fiz horas de pesquisa sobre isso, tentei todos os tipos de shaders, mistura de pixel por pixel e tudo o mais sem sucesso. A mistura de pixel por pixel em C # acabou sendo um pouco intensiva para o meu gosto, embora ainda esteja trabalhando para limpá-lo e fazê-lo funcionar de maneira mais suave. Os shaders pareciam promissores, mas não consegui encontrar um shader capaz de combinar adequadamente dois mapas de luz.

Alguém tem alguma pista sobre como eu poderia fazer isso? Eu só preciso de algum tipo de transição suave entre meu mapa de luz diurno e noturno. Talvez eu possa sobrepor as duas texturas e usar um canal alfa? Ou algo assim?


Se você possui o Pro, talvez seja possível renderizar as duas texturas do lightmap em uma terceira e usar essa terceira textura como um lightmap? Isso deve ser como a mistura de pixels, mas muito mais rápido.
Nevermind

Eu tenho Pro. Como eu processaria as duas texturas de lightmap juntas? Essa foi minha principal liderança, mas tenho tentado descobrir o código / processo para realizá-la.
Timothy Williams

Umm cria um material que combina duas texturas, use Graphics.Blit()para renderizá-lo? Eu nunca fiz isso, mas olhando no manual, ele deve funcionar.
Nevermind

Então, crie um novo material que possa misturar duas texturas em uma saída, aplique o Afar-1 e Bfar-1 e use a textura de saída para a variável lightmap?
Timothy Williams

Sim algo assim. Eu testaria, mas não tenho acesso à versão Pro no momento.
Nevermind

Respostas:


3

Então, eu tentei recentemente e encontrei muitos dos mesmos problemas que vocês têm. A solução de textura de renderização é um pouco de um arenque vermelho. Consegui resolvê-lo usando a manipulação de pixels multithreading em um thread separado.

https://www.youtube.com/watch?v=T_zpFk1mdCI

Então, normalmente, alguém usaria graphics.blit()e passaria a textura de renderização para onde quer que fosse, mas os dados do lightmap não suportam texturas, eles exigem texture2ds. O próximo passo lógico seria copiar os dados para um texture2d e depois alimentá-los com os dados do lightmap. Essa técnica arruina as taxas de quadros porque está impedindo a GPU de enviar dados para a CPU, em vez de apenas uma referência aos dados.

A solução é então não usar a GPU.

As transições do mapa de luz acontecem por um longo período de tempo, portanto, não é necessariamente importante atualizar o mapa de luz a cada quadro. Por uma questão de fato, os jogadores provavelmente não notariam se os mapas de luz eram atualizados apenas a cada 20-40 minutos no tempo do jogo.

Então, o que você faz é emitir a tarefa para a CPU em threads separados para cada mapa de luzes.

Normalmente, o Unity não suporta multithreading. Mas tudo bem, C # faz. Esse cara faz um trabalho fenomenal ao explicar multithreading no Unity, por isso, se você nunca ouviu falar ou nunca soube multithread no Unity, este é o vídeo:

https://www.youtube.com/watch?v=ja63QO1Imck

Tudo o que você precisa fazer é criar uma classe de encadeamento de trabalho que varie cópias dos dados de pixel do lightmap nas matrizes Color e criar uma função de mesclagem.

Um simples lerp de uma cor para a próxima serve.

Em seguida, crie o encadeamento, inicie-o e, quando todos os mapas de luz estiverem concluídos nos encadeamentos separados, você poderá copiar os dados de pixel de volta na textura de dados lightmap2d.

Publiquei um código de exemplo abaixo. Certamente não é a versão totalmente implementada, mas mostra os principais conceitos de criação da classe, criação do thread e configuração dos dados da luz.

As outras coisas que você teria que fazer é chamar uma função de vez em quando para acionar a atualização dos mapas de luz. Além disso, você deve copiar todos os dados de pixel na classe worker no início ou no tempo de compilação. Boa sorte para quem encontrar isso. Eu acho que a operação mudou sua vida, mas sei que outras pessoas com problemas semelhantes podem tropeçar nisso.

public class work
{
    Color[] fromPixels;
    Color[] toPixels;

    public float LerpValue = 0;
    public bool Finished = false;
    public Color[] mixedPixels;

    public work(Color[] FromPix, Color[] ToPix)
    {
        fromPixels= FromPix;
        toPixels= ToPix;
        Finished = false;
        mixedPixels = new Color[FromPix.Length];
    }
    public void DoWork()
    {
        for (int x = 0; x < fromPixels.Length; x++)
        {
            mixedPixels[x] = Color.Lerp(fromPixels[x], toPixels[x], LerpValue);
        }
        Finished = true;
    }
}

IEnumerator LightMapSet()
{
    Thread workerThread = new Thread(someworker.DoWork);
    someworker.LerpValue = lerpValue;
    workerThread.Start();
    yield return new WaitUntil(() => someworker.Finished);
    mixedMap.SetPixels(someworker.mixedPixels);
    mixedMap.Apply(true);
    LightmapData someLightmapData;
    someLightmapData.lightmapColor = mixedMap;
    lightDatas = { someLightmapData};
    LightmapSettings.lightmaps = lightDatas;
}

1

Existe um shader do skybox que combina entre dois conjuntos de texturas do skybox. Pense ciclo dia e noite!

Se você deseja criar ou animar a skybox a partir do script, use skyboxmaterial.SetFloat("_Blend", yourBlend)para alterar a mistura; também pode usar SetTexturefunções de material para configurar ou alterar as texturas.

Tutorial em vídeo sobre o ciclo dia / noite: http://www.youtube.com/watch?v=FTfv9JhkmIA

O código de exemplo é o seguinte:

Shader "RenderFX/Skybox Blended" {
Properties {
    _Tint ("Tint Color", Color) = (.5, .5, .5, .5)
    _Blend ("Blend", Range(0.0,1.0)) = 0.5
    _FrontTex ("Front (+Z)", 2D) = "white" {}
    _BackTex ("Back (-Z)", 2D) = "white" {}
    _LeftTex ("Left (+X)", 2D) = "white" {}
    _RightTex ("Right (-X)", 2D) = "white" {}
    _UpTex ("Up (+Y)", 2D) = "white" {}
    _DownTex ("Down (-Y)", 2D) = "white" {}
    _FrontTex2("2 Front (+Z)", 2D) = "white" {}
    _BackTex2("2 Back (-Z)", 2D) = "white" {}
    _LeftTex2("2 Left (+X)", 2D) = "white" {}
    _RightTex2("2 Right (-X)", 2D) = "white" {}
    _UpTex2("2 Up (+Y)", 2D) = "white" {}
    _DownTex2("2 Down (-Y)", 2D) = "white" {}
}

SubShader {
    Tags { "Queue" = "Background" }
    Cull Off
    Fog { Mode Off }
    Lighting Off        
    Color [_Tint]
    Pass {
        SetTexture [_FrontTex] { combine texture }
        SetTexture [_FrontTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_FrontTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_BackTex] { combine texture }
        SetTexture [_BackTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_BackTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_LeftTex] { combine texture }
        SetTexture [_LeftTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_LeftTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_RightTex] { combine texture }
        SetTexture [_RightTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_RightTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_UpTex] { combine texture }
        SetTexture [_UpTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_UpTex2] { combine previous +- primary, previous * primary }
    }
    Pass {
        SetTexture [_DownTex] { combine texture }
        SetTexture [_DownTex2] { constantColor (0,0,0,[_Blend]) combine texture lerp(constant) previous }
        SetTexture [_DownTex2] { combine previous +- primary, previous * primary }
    }
}

Fallback "RenderFX/Skybox", 1
}

2
A pergunta feita sobre mapas de luz, não skybox. Obrigado pelo link, porém, parece que será útil para mim.
Jhocking

0

Se você sabe como alternar, por que não continuar criando vários mapas de luzes de transição no encadeamento em segundo plano e ativar as transições quando os mapas de luz estiverem prontos?

Você também pode dar uma olhada em um ativo interessante no AssetStore: https://www.assetstore.unity3d.com/en/#!/content/5674

Eu acho que inclui os mapas de luz que se misturam, embora eu não saiba como.

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.