본문 바로가기
유니티 엔진

Unity Standard Shader 분석

by 대마왕J 2015. 5. 28.

- 일단 기본적으로 Standard Shader는 Uber Shader로 짜여져 있다.

- 그래서 중간에 주요 라이팅 함수들이 분기가 된다. 특히 핵심 조명 코드인 BRDF 코드는 3.0 지원버전, 2.0 지원 버전, 모바일 버전으로 3가지로 분기된다 (어, 맞던가? 좀전에 봤는데 기억이 안나..)

- 지금 아래는 서피스 쉐이더로 구현하던 것이다. 분기는 없애고 걍 3.0 지원버전으로 ...

- 라이팅을 커스텀으로 한 것 뿐이다.

- 분석하다가 중간에 정지한 것. 지금 라이팅 구문에서는 light.ndotl이 부분을 찾아야 한다. 일단 결과물만 테스트 해 보게 만든 녀석이다. 이 녀석은 어디 숨어 있는 걸까...

- 그래서 지금 결과물 리턴은 NdotL이다.

- 하프 렘버트라도 구현하려면 일단 ndotl 을 saturate 시키지 않는 선에서 마무리되도록 만들어야 한다. 근데 일단 그냥 되어서 넘어오게 만들어져 있다. 음. 수동으로 값 받아서 구현해 버릴까?

- 분기까지 만들면 일이 너무 커지는데다가 귀차니즘에다가 지금 나가야 한다는게 문제.

- 차분히 앉아서 하루만 공부해보면 좋겠다 찌발 ㅜ

 

 

 

 

 

Shader "Custom/Standard" {
 Properties {
  _Color ("Color", Color) = (1,1,1,1)
  _MainTex ("Albedo (RGB)", 2D) = "white" {}
  _Glossiness ("Smoothness", Range(0,1)) = 0.5
  _Metallic ("Metallic", Range(0,1)) = 0.0
 }
 SubShader {
  Tags { "RenderType"="Opaque" }
  LOD 200
  cull off
 
  CGPROGRAM
  // Physically based Standard lighting model, and enable shadows on all light types
  #pragma surface surf JP fullforwardshadows
  // Use shader model 3.0 target, to get nicer looking lighting
  #pragma target 3.0
  #include "UnityPBSLighting.cginc"
 
 
 
//safe noramlize
   inline half3 Unity_SafeNormalize(half3 inVec)
   {
    half dp3 = max(0.001f, dot(inVec, inVec));
    return inVec * rsqrt(dp3);
   }
 
 
//BRDF1
  
   half4 BRDFjp_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,half3 normal, half3 viewDir,UnityLight light, UnityIndirect gi)
   {
    half roughness = 1-oneMinusRoughness;
    half3 halfDir = Unity_SafeNormalize (light.dir + viewDir);

    half nl = light.ndotl;
    half nh = BlinnTerm (normal, halfDir);
    half nv = DotClamped (normal, viewDir);
    half lv = DotClamped (light.dir, viewDir);
    half lh = DotClamped (light.dir, halfDir);

   #if UNITY_BRDF_GGX
    half V = SmithGGXVisibilityTerm (nl, nv, roughness);
    half D = GGXTerm (nh, roughness);
   #else
    half V = SmithBeckmannVisibilityTerm (nl, nv, roughness);
    half D = NDFBlinnPhongNormalizedTerm (nh, RoughnessToSpecPower (roughness));
   #endif

    half nlPow5 = Pow5 (1-nl);
    half nvPow5 = Pow5 (1-nv);
    half Fd90 = 0.5 + 2 * lh * lh * roughness;
    half disneyDiffuse = (1 + (Fd90-1) * nlPow5) * (1 + (Fd90-1) * nvPow5);
   
    // HACK: theoretically we should divide by Pi diffuseTerm and not multiply specularTerm!
    // BUT 1) that will make shader look significantly darker than Legacy ones
    // and 2) on engine side "Non-important" lights have to be divided by Pi to in cases when they are injected into ambient SH
    // NOTE: multiplication by Pi is part of single constant together with 1/4 now

    half specularTerm = max(0, (V * D * nl) * unity_LightGammaCorrectionConsts_PIDiv4);// Torrance-Sparrow model, Fresnel is applied later (for optimization reasons)
    half diffuseTerm = disneyDiffuse * nl;
   
    half grazingTerm = saturate(oneMinusRoughness + (1-oneMinusReflectivity));
       half3 color = diffColor * (gi.diffuse + light.color * diffuseTerm)
                       + specularTerm * light.color * FresnelTerm (specColor, lh)
        + gi.specular * FresnelLerp (specColor, grazingTerm, nv);

//    return float4 (light.ndotl.xxx+0.5,1);
    return half4(color, 1);
   }
  

 
 
 
 
    inline half4 LightingJP (SurfaceOutputStandard s, half3 viewDir, UnityGI gi)
   {
    s.Normal = normalize(s.Normal);

    half oneMinusReflectivity;
    half3 specColor;
    s.Albedo = DiffuseAndSpecularFromMetallic (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);

    // shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
    // this is necessary to handle transparency in physically correct way - only diffuse component gets affected by alpha
    half outputAlpha;
    s.Albedo = PreMultiplyAlpha (s.Albedo, s.Alpha, oneMinusReflectivity, /*out*/ outputAlpha);

    half4 c = BRDFjp_Unity_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
   // c.rgb += UNITY_BRDF_GI (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, s.Occlusion, gi);
    c.a = outputAlpha;
    return c;
   }


   inline void LightingJP_GI (
    SurfaceOutputStandard s,
    UnityGIInput data,
    inout UnityGI gi)
   {
    gi = UnityGlobalIllumination (data, s.Occlusion, s.Smoothness, s.Normal);
   }
  
  


 

  sampler2D _MainTex;

  struct Input {
   float2 uv_MainTex;
  };

  half _Glossiness;
  half _Metallic;
  fixed4 _Color;

  void surf (Input IN, inout SurfaceOutputStandard o) {
   // Albedo comes from a texture tinted by color
   fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
   o.Albedo = c.rgb;
   // Metallic and smoothness come from slider variables
   o.Metallic = _Metallic;
   o.Smoothness = _Glossiness;
   o.Alpha = c.a;
  }
  ENDCG
 }
 FallBack "Diffuse"
}

 

 

반응형

댓글