Why geometric? Because the geometric mean "to" higher values , which means that brighter pixels will be selected (which we need, because we are interested in the light sources in the picture).
RenderTextureFormat rtFormat = RenderTextureFormat.ARGBFloat; if (lumBuffer == null) { lumBuffer = new RenderTexture (LuminanceGridSize, LuminanceGridSize, 0, rtFormat, RenderTextureReadWrite.Default); } RenderTexture currentTex = RenderTexture.GetTemporary (InitialSampling, InitialSampling, 0, rtFormat, RenderTextureReadWrite.Default); Graphics.Blit (source, currentTex, material, PASS_PREPARE); int currentSize = InitialSampling; while (currentSize > LuminanceGridSize) { RenderTexture next = RenderTexture.GetTemporary (currentSize / 2, currentSize / 2, 0, rtFormat, RenderTextureReadWrite.Default); Graphics.Blit (currentTex, next, material, PASS_DOWNSAMPLE); RenderTexture.ReleaseTemporary (currentTex); currentTex = next; currentSize /= 2; }
// Downsample pass Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragDownsample float4 fragDownsample(v2f i) : COLOR { float4 v1 = tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(-1,-1)); float4 v2 = tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(1,1)); float4 v3 = tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(-1,1)); float4 v4 = tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(1,-1)); float mn = min(min(v1.x,v2.x), min(v3.x,v4.x)); float mx = max(max(v1.y,v2.y), max(v3.y,v4.y)); float avg = (v1.z+v2.z+v3.z+v4.z) / 4; return float4(mn, mx, avg, 1); } ENDCG } // Prepare pass Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragPrepare float4 fragPrepare(v2f i) : COLOR { float v = tex2D(_MainTex, i.uv); float l = log(v + 0.001); return half4(l, l, l, 1); } ENDCG }
if (!lumBuffer.IsCreated ()) { Debug.Log ("Luminance map recreated"); lumBuffer.Create (); // , Graphics.Blit (currentTex, lumBuffer); } else { material.SetFloat ("_Adaptation", AdaptationCoefficient); Graphics.Blit (currentTex, lumBuffer, material, PASS_UPDATE); }
material.SetTexture ("_LumTex", lumBuffer); material.SetFloat ("_Key", Key); material.SetFloat ("_White", White); material.SetFloat ("_Limit", Limit); Graphics.Blit (source, destination, material, PASS_MAIN);
// Main pass Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag float4 frag(v2f i) : COLOR { half4 cColor = tex2D(_MainTex, i.uv); float4 cLum = tex2D(_LumTex, i.uv); float lMin = exp(cLum.x); float lMax = exp(cLum.y); float lAvg = exp(cLum.z); lAvg = max(lMax / 2, _Limit); // force override for dark scene float lum = max(0.000001, Luminance(cColor.rgb)); float scaled = _Key / lAvg * lum; scaled *= (1 + scaled / _White / _White) / (1+scaled); return scaled * cColor; } ENDCG }
Source: https://habr.com/ru/post/165669/