Comment est-ce que je mélange 2 lightmaps pour le cycle jour / nuit dans Unity?


16

Avant de dire autre chose: j'utilise des cartes lumineuses doubles, ce qui signifie que je dois mélanger à la fois un proche et un lointain.

Donc, je travaille sur cela depuis un certain temps maintenant, j'ai un cycle jour / nuit complet configuré pour les rendus et l'éclairage, et tout fonctionne bien et ne demande pas beaucoup de processus.

Le seul problème que j'ai est de trouver comment mélanger deux lightmaps ensemble, j'ai compris comment changer de lightmaps, mais le problème est que ça a l'air plutôt brutal et interrompt l'expérience.

J'ai fait des heures de recherche à ce sujet, essayé toutes sortes de shaders, mélange pixel par pixel, et tout le reste en vain. Le mélange pixel par pixel en C # s'est avéré être un peu intensif en processus à mon goût, bien que je travaille toujours à le nettoyer et à le faire fonctionner plus facilement. Les shaders avaient l'air prometteurs, mais je n'ai pas pu trouver un shader capable de mélanger correctement deux lightmaps.

Quelqu'un at-il des pistes sur la façon dont je pourrais y parvenir? J'ai juste besoin d'une sorte de transition en douceur entre mon lightmap diurne et nocturne. Peut-être que je pourrais superposer les deux textures et utiliser un canal alpha? Ou quelque chose comme ça?


Si vous avez Pro, vous pouvez peut-être rendre les deux textures de lightmap en une troisième, puis utiliser cette troisième texture comme lightmap? Cela devrait être exactement comme le mélange de pixels, mais massivement plus rapide.
Nevermind

J'ai Pro. Comment pourrais-je procéder pour rendre les deux textures lightmap ensemble? C'était ma principale piste mais j'ai essayé de comprendre le code / processus pour y parvenir.
Timothy Williams

Umm créer un matériau qui mélange deux textures, utiliser Graphics.Blit()pour le rendre? Je n'ai jamais fait ça, mais en regardant dans le manuel, ça devrait marcher.
Nevermind

Donc, créez un nouveau matériau qui peut mélanger deux textures à une sortie, appliquez Afar-1 et Bfar-1, puis utilisez la texture sortante pour la variable lightmap?
Timothy Williams

Oui quelque chose comme ça. Je le testerais, mais je n'ai pas accès à la version Pro pour le moment.
Nevermind

Réponses:


3

J'ai donc récemment essayé cela et j'ai rencontré beaucoup des mêmes problèmes que vous. La solution de texture de rendu est un peu un hareng rouge. J'ai pu le résoudre en utilisant la manipulation de pixels multithreads sur un thread séparé.

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

Donc, normalement, on utilise graphics.blit()et transmet la texture de rendu là où elle doit aller, mais les données lightmap ne prennent pas en charge les textures, elles nécessitent texture2ds. La prochaine étape logique serait de copier les données dans un texture2d, puis de les alimenter dans les données lightmap. Cette technique ruine les fréquences d'images car elle bloque le GPU pour envoyer des données au CPU, plutôt qu'une simple référence aux données.

La solution est alors de ne pas utiliser le GPU.

Les transitions de la carte de lumière se produisent sur une longue période de temps, il n'est donc pas nécessairement important de mettre à jour la carte de lumière à chaque image. En fait, les joueurs ne remarqueraient probablement pas si les cartes lumineuses n'étaient mises à jour que toutes les 20 à 40 minutes en temps de jeu.

Donc, ce que vous faites, vous lancez la tâche vers le CPU sur des threads séparés pour chaque carte de lumière.

Ordinairement, Unity ne prend pas en charge le multithreading. Mais ça va, C # le fait. Ce gars fait un travail phénoménal pour expliquer le multithreading dans Unity, donc si vous n'en avez jamais entendu parler, ou si vous n'avez jamais su comment multithread dans Unity, voici la vidéo:

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

Tout ce que vous devez faire est de créer une classe de threads de travail qui varie les copies des données de pixels du plan optique dans les tableaux de couleurs, puis de créer une fonction de fusion.

Un simple lerp d'une couleur à l'autre fera l'affaire.

Créez ensuite le fil, démarrez-le, et lorsque toutes les lightmaps sont terminées dans les threads séparés, vous pouvez recopier les données de pixels dans la texture de données lightmap2d.

J'ai posté un exemple de code ci-dessous. Ce n'est certainement pas la version entièrement implémentée, mais elle vous montre les principaux concepts de création de la classe, de création du thread, puis de définition des données de lumière.

Les autres choses que vous devriez faire sont d'appeler une fonction de temps en temps pour déclencher la mise à jour des lightmaps. Vous devez également copier toutes les données de pixels dans la classe de travail au démarrage ou au moment de la compilation. Bonne chance à tous ceux qui trouveront ça. Je suppose que l'op a changé sa vie, mais je sais que d'autres personnes ayant des problèmes similaires pourraient tomber dessus.

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

Il existe un shader skybox qui se fond entre deux ensembles de textures skybox. Pensez au cycle jour et nuit!

Si vous souhaitez créer ou animer la skybox à partir d'un script, utilisez skyboxmaterial.SetFloat("_Blend", yourBlend)pour modifier le mélange; peut également utiliser SetTexturedes fonctions matérielles pour configurer ou modifier les textures.

Tutoriel vidéo sur le cycle jour / nuit: http://www.youtube.com/watch?v=FTfv9JhkmIA

L'exemple de code se présente comme suit:

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
La question portait sur les lightmaps, pas sur skybox. Merci pour le lien cependant, cela semble être utile pour moi.
jhocking

0

Si vous savez comment changer, pourquoi ne pas continuer à créer un certain nombre de lightmaps de transition sur le thread d'arrière-plan, puis activer les transitions lorsque les lightmaps sont prêtes?

Vous pouvez également consulter un actif intéressant sur AssetStore: https://www.assetstore.unity3d.com/en/#!/content/5674

Je suppose que cela inclut le mélange des lightmaps, bien que je ne sache pas comment.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.