Search Unity

Unity Built-in Sky Box Shader "unity_ColorSpaceDouble"

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

  1. freehyan

    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):
    1. Shader "Skybox/Cubemap" {
    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.  
    9. SubShader {
    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?
     
  2. Olmi

    Olmi

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

    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.