16
\$\begingroup\$

Before I say anything else: I'm using dual lightmaps, meaning I need to blend both a near and a far.

So I've been working on this for a while now, I have a whole day/night cycle set up for renderers and lighting, and everything is working fine and not process intensive.

The only problem I'm having is figuring out how I could blend two lightmaps together, I've figured out how to switch lightmaps, but the problem is that looks kind of abrupt and interrupts the experience.

I've done hours of research on this, tried all kinds of shaders, pixel by pixel blending, and everything else to no real avail. Pixel by pixel blending in C# turned out to be a bit process intensive for my liking, though I'm still working on cleaning it up and making it run more smoothly. Shaders looked promising, but I couldn't find a shader that could properly blend two lightmaps.

Does anyone have any leads on how I could accomplish this? I just need some sort of smooth transition between my daytime and nighttime lightmap. Perhaps I could overlay the two textures and use an alpha channel? Or something like that?

\$\endgroup\$
  • \$\begingroup\$ If you have Pro, maybe you can render the two lightmap textures into a third, and then use this third texture as a lightmap? That should be just like pixel blending, but massively faster. \$\endgroup\$ – Nevermind Feb 20 '13 at 5:39
  • \$\begingroup\$ I do have Pro. How would I go about rendering the two lightmap textures together? This was my main lead but I've been trying to figure out the code/process to accomplish it. \$\endgroup\$ – Timothy Williams Feb 20 '13 at 6:17
  • \$\begingroup\$ Umm create a material that blends two textures, use Graphics.Blit() to render it? I've never done this, but looking in the manual, it should work. \$\endgroup\$ – Nevermind Feb 20 '13 at 7:29
  • \$\begingroup\$ So create a new material that can blend two textures to an output, apply the Afar-1 and Bfar-1, then use the outgoing texture for the lightmap variable? \$\endgroup\$ – Timothy Williams Feb 20 '13 at 22:59
  • \$\begingroup\$ Yeah, something like that. I'd test it, but I don't have access to Pro version at the moment. \$\endgroup\$ – Nevermind Feb 21 '13 at 8:09
3
\$\begingroup\$

So I recently tried my hand at this and ran into a lot of the same issues you guys have. The render texture solution is a bit of a red herring. I was able to solve it using multithreading pixel manipulation on a separate thread.

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

So ordinarily one would use graphics.blit() and pass the render texture in to wherever it needs to go, but lightmap data doesn't support textures, they require texture2ds. The next logical step would be to copy the data to a texture2d and then feed that to the lightmap data. This technique ruins frame rates because it is stalling the GPU to send data to the CPU, rather than just a reference to the data.

The solution is then to not use the GPU.

Light map transitions happen over a long period of time so it is not necessarily important to update the light map every frame. As a matter of fact, players probably wouldn't notice if the light maps were only updated every 20-40 minutes in game time.

So what you do is you issue the task out to the CPU on separate threads for each light map.

Ordinarily Unity does not support multithreading. But that's okay, C# does. This guy does a phenomenal job explain multithreading in Unity, so if you've never heard of it, or never knew how to multithread in Unity this is the video:

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

All you need to do is make a worker thread class that varies copies of the lightmap pixel data in Color arrays, and then create a blend function.

A simple lerp from one color to the next will do.

Then create the thread, start it, and when all the lightmaps are finished in the separate threads you can copy the pixel data back into the lightmap data texture2d.

I posted some example code below. It's certainly not the fully implemented version, but it shows you the main concepts of making the class, creating the thread, and then setting the lightdata.

The other things you would have to do is call a function every so often to trigger updating the lightmaps. Also you have to either copy all of the pixel data into the worker class at start or at compile time. Good luck to anyone who finds this. I figure the op has moved on with their life, but I know other people with similar problems might stumble upon this.

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;
}
\$\endgroup\$
1
\$\begingroup\$

There is a skybox shader that blends between two sets of skybox textures. Think day and night cycle!

If you want to build or animate the skybox from script, use skyboxmaterial.SetFloat("_Blend", yourBlend) to change the blending; can also use SetTexture material functions to setup or change the textures.

Video tutorial about day/night cycle: http://www.youtube.com/watch?v=FTfv9JhkmIA

The example code goes as follows:

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
}
\$\endgroup\$
  • 2
    \$\begingroup\$ The question asked about lightmaps, not skybox. Thanks for the link though, this looks like it'll be useful to me. \$\endgroup\$ – jhocking Jun 29 '13 at 16:44
0
\$\begingroup\$

If you know how to switch, why not to go on with creating a number of transition lightmaps on the background thread, and then enable the transitions when the lightmaps are ready?

You can also have a look at an interesting asset on AssetStore: https://www.assetstore.unity3d.com/en/#!/content/5674

I guess it includes the lightmaps blending, although I don't know the way how.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.