# Unity Built-in Sky Box Shader "unity_ColorSpaceDouble"

Discussion in 'General Graphics' started by freehyan, Dec 9, 2019.

1. ### freehyan

Joined:
Nov 27, 2017
Posts:
6
Hello, everyone. I'm studying the unity built-in skybox shader. In the meantime, I have a question, why do I need to multiply variables unity_ColorSpaceDouble

Code (CSharp):
2. Properties {
3.     _Tint ("Tint Color", Color) = (.5, .5, .5, .5)
4.     [Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
5.     _Rotation ("Rotation", Range(0, 360)) = 0
6.     [NoScaleOffset] _Tex ("Cubemap   (HDR)", Cube) = "grey" {}
7. }
8.
10.     Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
11.     Cull Off ZWrite Off
12.
13.     Pass {
14.
15.         CGPROGRAM
16.         #pragma vertex vert
17.         #pragma fragment frag
18.         #pragma target 2.0
19.
20.         #include "UnityCG.cginc"
21.
22.         samplerCUBE _Tex;
23.         half4 _Tex_HDR;
24.         half4 _Tint;
25.         half _Exposure;
26.         float _Rotation;
27.
28.         float3 RotateAroundYInDegrees (float3 vertex, float degrees)
29.         {
30.             float alpha = degrees * UNITY_PI / 180.0;
31.             float sina, cosa;
32.             sincos(alpha, sina, cosa);
33.             float2x2 m = float2x2(cosa, -sina, sina, cosa);
34.             return float3(mul(m, vertex.xz), vertex.y).xzy;
35.         }
36.
37.         struct appdata_t {
38.             float4 vertex : POSITION;
39.             UNITY_VERTEX_INPUT_INSTANCE_ID
40.         };
41.
42.         struct v2f {
43.             float4 vertex : SV_POSITION;
44.             float3 texcoord : TEXCOORD0;
45.             UNITY_VERTEX_OUTPUT_STEREO
46.         };
47.
48.         v2f vert (appdata_t v)
49.         {
50.             v2f o;
51.             UNITY_SETUP_INSTANCE_ID(v);
52.             UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
53.             float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation);
54.             o.vertex = UnityObjectToClipPos(rotated);
55.             o.texcoord = v.vertex.xyz;
56.             return o;
57.         }
58.
59.         fixed4 frag (v2f i) : SV_Target
60.         {
61.             half4 tex = texCUBE (_Tex, i.texcoord);
62.             half3 c = DecodeHDR (tex, _Tex_HDR);
63.             [B]c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;[/B]
64.             c *= _Exposure;
65.             return half4(c, 1);
66.         }
67.         ENDCG
68.     }
69. }
70.
71. Fallback Off
72.
73. }
The variable unity_ColorSpaceDouble, What does it mean?

Joined:
Nov 29, 2012
Posts:
620
3. ### bgolus

Joined:
Dec 7, 2012
Posts:
7,887
Not exactly.

It's a value that is perceptually twice as bright as "1.0". For gamma color space rendering it's just 2.0 as gamma space rendering is already being done in perceptual color space. For linear color space rendering it's 4.5947 (2^2.2) because a value of 2.0 in linear color space isn't twice as bright as 1.0, instead it's only about 40% brighter. This is because the human eye doesn't perceive brightness linearly. ~4.6x more photons need to hit your eye for it to be perceived twice as bright.

Using a single multiplier here is an approximation to handle the way many Unity shaders use a tint value that is multiplied by "2". Using the unity_ColorSpaceDouble instead of a hard coded 2.0 is supposed to make using the same values in gamma space and linear space rendering match more closely. Color values set on a material are automatically gamma corrected if you're using linear color space rendering, so the default middle grey of (0.5, 0.5, 0.5) ends up as a value of (0.21586, 0.21586, 0.21586) in the shader. That multiplied by 4.5947 gets very close to the ideal of a multiplier of 1.0 at around 0.99183. Wrong, but close enough most people won't easily notice.

Darker tints will be more obviously wrong as the curve between linear and gamma will be more significantly different than the simple multiply approximation being used.

freehyan and Olmi like this.