¿Cómo combino 2 mapas de luz para el ciclo día / noche en Unity?

16

Antes de decir cualquier otra cosa: estoy usando mapas de luz duales, lo que significa que necesito mezclar tanto cerca como lejos.

Así que he estado trabajando en esto por un tiempo, tengo un ciclo de día / noche completo configurado para renderizadores e iluminación, y todo funciona bien y no requiere un proceso intensivo.

El único problema que tengo es descubrir cómo podría mezclar dos mapas de luz, he descubierto cómo cambiar los mapas de luz, pero el problema es que parece algo abrupto e interrumpe la experiencia.

He investigado durante horas sobre esto, probé todo tipo de sombreadores, combinación de píxeles por píxeles, y todo lo demás fue en vano. La combinación de píxel por píxel en C # resultó ser un proceso un poco intenso para mi gusto, aunque todavía estoy trabajando en limpiarlo y hacer que funcione más suavemente. Los sombreadores parecían prometedores, pero no pude encontrar un sombreador que pudiera combinar adecuadamente dos mapas de luz.

¿Alguien tiene pistas sobre cómo podría lograr esto? Solo necesito algún tipo de transición suave entre mi mapa de luz diurno y nocturno. ¿Quizás podría superponer las dos texturas y usar un canal alfa? ¿O algo así?

Timothy Williams
fuente
Si tiene Pro, ¿tal vez pueda renderizar las dos texturas de mapa de luz en un tercero y luego usar esta tercera textura como mapa de luz? Eso debería ser como la combinación de píxeles, pero masivamente más rápido.
importa
Tengo Pro. ¿Cómo haría para representar las dos texturas de mapa de luz juntas? Este fue mi líder principal, pero he estado tratando de descubrir el código / proceso para lograrlo.
Timothy Williams
Umm crea un material que combina dos texturas, ¿lo usas Graphics.Blit()para renderizarlo? Nunca he hecho esto, pero mirando el manual, debería funcionar.
importa
Entonces, ¿cree un nuevo material que pueda mezclar dos texturas en una salida, aplique Afar-1 y Bfar-1, luego use la textura saliente para la variable mapa de luz?
Timothy Williams
Si algo como eso. Lo probaría, pero no tengo acceso a la versión Pro en este momento.
importa

Respuestas:

3

Así que recientemente probé con esto y me encontré con muchos de los mismos problemas que ustedes tienen. La solución de textura de render es un poco de arenque rojo. Pude resolverlo usando la manipulación de píxeles de subprocesos múltiples en un hilo separado.

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

Por lo general, uno usaría graphics.blit()y pasaría la textura de renderizado a donde sea necesario, pero los datos del mapa de luz no admiten texturas, requieren texture2ds. El siguiente paso lógico sería copiar los datos a una texture2d y luego alimentarlos a los datos del mapa de luz. Esta técnica arruina las velocidades de cuadros porque está deteniendo la GPU para enviar datos a la CPU, en lugar de solo una referencia a los datos.

La solución es no utilizar la GPU.

Las transiciones del mapa de luz ocurren durante un largo período de tiempo, por lo que no es necesariamente importante actualizar el mapa de luz cada fotograma. De hecho, los jugadores probablemente no se darían cuenta si los mapas de luz solo se actualizan cada 20-40 minutos en el tiempo de juego.

Entonces, lo que haces es enviar la tarea a la CPU en subprocesos separados para cada mapa de luz.

Por lo general, Unity no admite subprocesos múltiples. Pero está bien, C # sí. Este tipo hace un trabajo fenomenal explicando el subproceso múltiple en Unity, por lo que si nunca has oído hablar de él o nunca has sabido cómo multiprocesar en Unity, este es el video:

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

Todo lo que necesita hacer es crear una clase de subproceso de trabajo que varíe las copias de los datos de píxeles del mapa de luz en matrices de colores y luego cree una función de mezcla.

Un simple salto de un color al siguiente servirá.

Luego cree el hilo, inícielo, y cuando todos los mapas de luz hayan terminado en los hilos separados, puede copiar los datos de píxeles nuevamente en la textura de datos del mapa de luz2d.

Publiqué un código de ejemplo a continuación. Ciertamente no es la versión completamente implementada, pero muestra los conceptos principales de hacer la clase, crear el hilo y luego configurar los datos de luz.

Las otras cosas que tendría que hacer es llamar a una función cada cierto tiempo para activar la actualización de los mapas de luz. También debe copiar todos los datos de píxeles en la clase de trabajo al inicio o en el momento de la compilación. Buena suerte a cualquiera que encuentre esto. Me imagino que la operación ha seguido adelante con su vida, pero sé que otras personas con problemas similares podrían tropezar con esto.

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;
}
Douglas Potesta
fuente
1

Hay un sombreador de skybox que combina dos conjuntos de texturas de skybox. ¡Piensa en el ciclo diurno y nocturno!

Si desea construir o animar el skybox desde el script, use skyboxmaterial.SetFloat("_Blend", yourBlend)para cambiar la combinación; También puede usar SetTexturefunciones de material para configurar o cambiar las texturas.

Video tutorial sobre el ciclo día / noche: http://www.youtube.com/watch?v=FTfv9JhkmIA

El código de ejemplo es el siguiente:

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
}
JA Corbal
fuente
2
La pregunta se hizo sobre mapas de luz, no sobre skybox. Sin embargo, gracias por el enlace, parece que me será útil.
jhocking
0

Si sabe cómo cambiar, ¿por qué no continuar creando una serie de mapas de luz de transición en el subproceso de fondo y luego habilitar las transiciones cuando los mapas de luz estén listos?

También puede echar un vistazo a un activo interesante en AssetStore: https://www.assetstore.unity3d.com/en/#!/content/5674

Supongo que incluye la combinación de mapas de luz, aunque no sé cómo.

tomekkie
fuente