Tonemapper.shader 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  2. Shader "Hidden/Tonemapper" {
  3. Properties {
  4. _MainTex ("", 2D) = "black" {}
  5. _SmallTex ("", 2D) = "grey" {}
  6. _Curve ("", 2D) = "black" {}
  7. }
  8. CGINCLUDE
  9. #include "UnityCG.cginc"
  10. struct v2f {
  11. float4 pos : SV_POSITION;
  12. float2 uv : TEXCOORD0;
  13. };
  14. sampler2D _MainTex;
  15. sampler2D _SmallTex;
  16. sampler2D _Curve;
  17. float4 _HdrParams;
  18. float2 intensity;
  19. float4 _MainTex_TexelSize;
  20. float _AdaptionSpeed;
  21. float _ExposureAdjustment;
  22. float _RangeScale;
  23. v2f vert( appdata_img v )
  24. {
  25. v2f o;
  26. o.pos = UnityObjectToClipPos(v.vertex);
  27. o.uv = v.texcoord.xy;
  28. return o;
  29. }
  30. float4 fragLog(v2f i) : SV_Target
  31. {
  32. const float DELTA = 0.0001f;
  33. float fLogLumSum = 0.0f;
  34. fLogLumSum += log( Luminance(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(-1,-1)).rgb) + DELTA);
  35. fLogLumSum += log( Luminance(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(1,1)).rgb) + DELTA);
  36. fLogLumSum += log( Luminance(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(-1,1)).rgb) + DELTA);
  37. fLogLumSum += log( Luminance(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(1,-1)).rgb) + DELTA);
  38. float avg = fLogLumSum / 4.0;
  39. return float4(avg, avg, avg, avg);
  40. }
  41. float4 fragExp(v2f i) : SV_Target
  42. {
  43. float2 lum = float2(0.0f, 0.0f);
  44. lum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(-1,-1)).xy;
  45. lum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(1,1)).xy;
  46. lum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(1,-1)).xy;
  47. lum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * float2(-1,1)).xy;
  48. lum = exp(lum / 4.0f);
  49. return float4(lum.x, lum.y, lum.x, saturate(0.0125 * _AdaptionSpeed));
  50. }
  51. float3 ToCIE(float3 FullScreenImage)
  52. {
  53. // RGB -> XYZ conversion
  54. // http://www.w3.org/Graphics/Color/sRGB
  55. // The official sRGB to XYZ conversion matrix is (following ITU-R BT.709)
  56. // 0.4125 0.3576 0.1805
  57. // 0.2126 0.7152 0.0722
  58. // 0.0193 0.1192 0.9505
  59. float3x3 RGB2XYZ = {0.5141364, 0.3238786, 0.16036376, 0.265068, 0.67023428, 0.06409157, 0.0241188, 0.1228178, 0.84442666};
  60. float3 XYZ = mul(RGB2XYZ, FullScreenImage.rgb);
  61. // XYZ -> Yxy conversion
  62. float3 Yxy;
  63. Yxy.r = XYZ.g;
  64. // x = X / (X + Y + Z)
  65. // y = X / (X + Y + Z)
  66. float temp = dot(float3(1.0,1.0,1.0), XYZ.rgb);
  67. Yxy.gb = XYZ.rg / temp;
  68. return Yxy;
  69. }
  70. float3 FromCIE(float3 Yxy)
  71. {
  72. float3 XYZ;
  73. // Yxy -> XYZ conversion
  74. XYZ.r = Yxy.r * Yxy.g / Yxy. b;
  75. // X = Y * x / y
  76. XYZ.g = Yxy.r;
  77. // copy luminance Y
  78. XYZ.b = Yxy.r * (1 - Yxy.g - Yxy.b) / Yxy.b;
  79. // Z = Y * (1-x-y) / y
  80. // XYZ -> RGB conversion
  81. // The official XYZ to sRGB conversion matrix is (following ITU-R BT.709)
  82. // 3.2410 -1.5374 -0.4986
  83. // -0.9692 1.8760 0.0416
  84. // 0.0556 -0.2040 1.0570
  85. float3x3 XYZ2RGB = { 2.5651,-1.1665,-0.3986, -1.0217, 1.9777, 0.0439, 0.0753, -0.2543, 1.1892};
  86. return mul(XYZ2RGB, XYZ);
  87. }
  88. // NOTE/OPTIMIZATION: we're not going the extra CIE detour anymore, but
  89. // scale with the OUT/IN luminance ratio,this is sooooo much faster
  90. float4 fragAdaptive(v2f i) : SV_Target
  91. {
  92. float avgLum = tex2D(_SmallTex, i.uv).x;
  93. float4 color = tex2D (_MainTex, i.uv);
  94. float cieLum = max(0.000001, Luminance(color.rgb)); //ToCIE(color.rgb);
  95. float lumScaled = cieLum * _HdrParams.z / (0.001 + avgLum.x);
  96. lumScaled = (lumScaled * (1.0f + lumScaled / (_HdrParams.w)))/(1.0f + lumScaled);
  97. //cie.r = lumScaled;
  98. color.rgb = color.rgb * (lumScaled / cieLum);
  99. //color.rgb = FromCIE(cie);
  100. return color;
  101. }
  102. float4 fragAdaptiveAutoWhite(v2f i) : SV_Target
  103. {
  104. float2 avgLum = tex2D(_SmallTex, i.uv).xy;
  105. float4 color = tex2D(_MainTex, i.uv);
  106. float cieLum = max(0.000001, Luminance(color.rgb)); //ToCIE(color.rgb);
  107. float lumScaled = cieLum * _HdrParams.z / (0.001 + avgLum.x);
  108. lumScaled = (lumScaled * (1.0f + lumScaled / (avgLum.y*avgLum.y)))/(1.0f + lumScaled);
  109. //cie.r = lumScaled;
  110. color.rgb = color.rgb * (lumScaled / cieLum);
  111. //color.rgb = FromCIE(cie);
  112. return color;
  113. }
  114. float4 fragCurve(v2f i) : SV_Target
  115. {
  116. float4 color = tex2D(_MainTex, i.uv);
  117. float3 cie = ToCIE(color.rgb);
  118. // Remap to new lum range
  119. float newLum = tex2D(_Curve, float2(cie.r * _RangeScale, 0.5)).r;
  120. cie.r = newLum;
  121. color.rgb = FromCIE(cie);
  122. return color;
  123. }
  124. float4 fragHable(v2f i) : SV_Target
  125. {
  126. const float A = 0.15;
  127. const float B = 0.50;
  128. const float C = 0.10;
  129. const float D = 0.20;
  130. const float E = 0.02;
  131. const float F = 0.30;
  132. const float W = 11.2;
  133. float3 texColor = tex2D(_MainTex, i.uv).rgb;
  134. texColor *= _ExposureAdjustment;
  135. float ExposureBias = 2.0;
  136. float3 x = ExposureBias*texColor;
  137. float3 curr = ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
  138. x = W;
  139. float3 whiteScale = 1.0f/(((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F);
  140. float3 color = curr*whiteScale;
  141. // float3 retColor = pow(color,1/2.2); // we have SRGB write enabled at this stage
  142. return float4(color, 1.0);
  143. }
  144. // we are doing it on luminance here (better color preservation, but some other problems like very fast saturation)
  145. float4 fragSimpleReinhard(v2f i) : SV_Target
  146. {
  147. float4 texColor = tex2D(_MainTex, i.uv);
  148. float lum = Luminance(texColor.rgb);
  149. float lumTm = lum * _ExposureAdjustment;
  150. float scale = lumTm / (1+lumTm);
  151. return float4(texColor.rgb * scale / lum, texColor.a);
  152. }
  153. float4 fragOptimizedHejiDawson(v2f i) : SV_Target
  154. {
  155. float4 texColor = tex2D(_MainTex, i.uv );
  156. texColor *= _ExposureAdjustment;
  157. float4 X = max(float4(0.0,0.0,0.0,0.0), texColor-0.004);
  158. float4 retColor = (X*(6.2*X+.5))/(X*(6.2*X+1.7)+0.06);
  159. return retColor*retColor;
  160. }
  161. float4 fragPhotographic(v2f i) : SV_Target
  162. {
  163. float4 texColor = tex2D(_MainTex, i.uv);
  164. return 1-exp2(-_ExposureAdjustment * texColor);
  165. }
  166. float4 fragDownsample(v2f i) : SV_Target
  167. {
  168. float4 tapA = tex2D(_MainTex, i.uv + _MainTex_TexelSize * 0.5);
  169. float4 tapB = tex2D(_MainTex, i.uv - _MainTex_TexelSize * 0.5);
  170. float4 tapC = tex2D(_MainTex, i.uv + _MainTex_TexelSize * float2(0.5,-0.5));
  171. float4 tapD = tex2D(_MainTex, i.uv - _MainTex_TexelSize * float2(0.5,-0.5));
  172. float4 average = (tapA+tapB+tapC+tapD)/4;
  173. average.y = max(max(tapA.y,tapB.y), max(tapC.y,tapD.y));
  174. return average;
  175. }
  176. ENDCG
  177. Subshader {
  178. // adaptive reinhhard apply
  179. Pass {
  180. ZTest Always Cull Off ZWrite Off
  181. CGPROGRAM
  182. #pragma vertex vert
  183. #pragma fragment fragAdaptive
  184. ENDCG
  185. }
  186. // 1
  187. Pass {
  188. ZTest Always Cull Off ZWrite Off
  189. CGPROGRAM
  190. #pragma vertex vert
  191. #pragma fragment fragLog
  192. ENDCG
  193. }
  194. // 2
  195. Pass {
  196. ZTest Always Cull Off ZWrite Off
  197. Blend SrcAlpha OneMinusSrcAlpha
  198. CGPROGRAM
  199. #pragma vertex vert
  200. #pragma fragment fragExp
  201. ENDCG
  202. }
  203. // 3
  204. Pass {
  205. ZTest Always Cull Off ZWrite Off
  206. Blend Off
  207. CGPROGRAM
  208. #pragma vertex vert
  209. #pragma fragment fragExp
  210. ENDCG
  211. }
  212. // 4 user controllable tonemap curve
  213. Pass {
  214. ZTest Always Cull Off ZWrite Off
  215. CGPROGRAM
  216. #pragma vertex vert
  217. #pragma fragment fragCurve
  218. ENDCG
  219. }
  220. // 5 tonemapping in uncharted
  221. Pass {
  222. ZTest Always Cull Off ZWrite Off
  223. CGPROGRAM
  224. #pragma vertex vert
  225. #pragma fragment fragHable
  226. ENDCG
  227. }
  228. // 6 simple tonemapping based reinhard
  229. Pass {
  230. ZTest Always Cull Off ZWrite Off
  231. CGPROGRAM
  232. #pragma vertex vert
  233. #pragma fragment fragSimpleReinhard
  234. ENDCG
  235. }
  236. // 7 OptimizedHejiDawson
  237. Pass {
  238. ZTest Always Cull Off ZWrite Off
  239. CGPROGRAM
  240. #pragma vertex vert
  241. #pragma fragment fragOptimizedHejiDawson
  242. ENDCG
  243. }
  244. // 8 Photographic
  245. Pass {
  246. ZTest Always Cull Off ZWrite Off
  247. CGPROGRAM
  248. #pragma vertex vert
  249. #pragma fragment fragPhotographic
  250. ENDCG
  251. }
  252. // 9 Downsample with auto white detection
  253. Pass {
  254. ZTest Always Cull Off ZWrite Off
  255. CGPROGRAM
  256. #pragma vertex vert
  257. #pragma fragment fragDownsample
  258. ENDCG
  259. }
  260. // 10 adaptive reinhhard apply with auto white
  261. Pass {
  262. ZTest Always Cull Off ZWrite Off
  263. CGPROGRAM
  264. #pragma vertex vert
  265. #pragma fragment fragAdaptiveAutoWhite
  266. ENDCG
  267. }
  268. }
  269. Fallback off
  270. } // shader