The Quest to Not Burn My Eyes

Fixing the blinding light

I ended the last post with an epileptic barrage of bright colors due to how the default implementation of Unity’s Eye Adaptation works. So my first task for this week was to figure out how the eye adaptation shader works, and modify it to ignore the pure black of space when calculating an average. Turns out it’s rather easy once you can find the correct place in the shader.

Inside of Assets/PostProcessing/Resources/Shaders/EyeHistogram.compute we can add an if statement around lines 47-50 (everything after float3 color until the curly brace) that will only add the sampled color to the histogram under certain conditions. For our case, we can make it ignore and not add any near black color by using the if statement if(length(color) > 0.01f).

Adding this code gives us a much less eye burning image:

Creating correct star colors

Now that we can see, I think it’s important to allow the stars to have different temperatures, and accurately recreate those temperature colors.

We can see from this Wikipedia article that stars range is temperature from about 2,000 Kelvin to 50,000 Kelvin. Getting a weighted value from within that range is trivial, but taking that temperature and converting it to the correct color (or chromaticity) is very non-trivial…

Thankfully, others have done some the work for me. I found this blog post outlining their method of converting temperature to color. I used their algorithm and converted it to a very simple C# function:

Color Temp2Color(int temp)
    Color ret = new Color();
    temp /= 100;
    ret.r = temp <= 66 ? 1f : Mathf.Clamp01(1.292936f * Mathf.Pow(temp - 60, -0.1332047f));
    ret.g = temp <= 66 ? Mathf.Clamp01(0.3900815f * Mathf.Log(temp) - 0.6318414f) : Mathf.Clamp01(1.129891f * Mathf.Pow(temp - 60, -0.07551484f));
    ret.b = temp >= 66 ? 1f : (temp <= 19 ? 0f : Mathf.Clamp01(0.5432067f * Mathf.Log(temp - 10) - 1.196254f));
    return ret;

Although maybe not the most readable implementation, it gets the job done in an efficient way.

Now that I have some pretty colors to apply to the stars, I want to apply these individual colors to the stars in the most efficient way. Instead of creating a material per star, we can use MaterialPropertyBlock to define a color for each star using the same material, allowing us to keep using the GPU Instancing.

When I first tried to use this, I forgot that I need to set the color of every LOD for it to work properly!

For the Future

I’ve now started work on doing optimizations for hiding objects that are too dim to be seen when using eye adaptation. This will allow me to hide planets and moons that are much dimmer than stars, stars that are too far away or too dim, and accumulate stars in a galaxy into a single bright object.

I will also start to be tweaking my generator settings towards more realistic settings so that I can better calibrate my my bloom and eye adaptation settings.