首页 > 技术文章 > standard pbr(二)

marcher 2018-08-25 19:16 原文

下一步看像素着色器代码

 half4 fragBase (VertexOutputForwardBase i) : SV_Target { return fragForwardBaseInternal(i); }

half4 fragForwardBaseInternal (VertexOutputForwardBase i)
{
    FRAGMENT_SETUP(s)
#if UNITY_OPTIMIZE_TEXCUBELOD
    s.reflUVW       = i.reflUVW;
#endif

    UnityLight mainLight = MainLight ();
    half atten = SHADOW_ATTENUATION(i);


    half occlusion = Occlusion(i.tex.xy);
    UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, mainLight);

    half4 c = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect);
    c.rgb += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, occlusion, gi);
    c.rgb += Emission(i.tex.xy);

    UNITY_APPLY_FOG(i.fogCoord, c.rgb);
    return OutputForward (c, s.alpha);
}
FRAGMENT_SETUP(s)等价于

FragmentCommonData s= FragmentSetup(i.tex, i.eyeVec, IN_VIEWDIR4PARALLAX(i), i.tangentToWorldAndParallax, IN_WORLDPOS(i));

struct FragmentCommonData
{
    half3 diffColor, specColor;
    // Note: smoothness & oneMinusReflectivity for optimization purposes, mostly for DX9 SM2.0 level.
    // Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots.
    half oneMinusReflectivity, smoothness;
    half3 normalWorld, eyeVec, posWorld;
    half alpha;

#if UNITY_OPTIMIZE_TEXCUBELOD || UNITY_STANDARD_SIMPLE
    half3 reflUVW;
#endif

#if UNITY_STANDARD_SIMPLE
    half3 tangentSpaceNormal;
#endif
};
 

去掉分支

struct FragmentCommonData
{
    half3 diffColor, specColor;
    // Note: smoothness & oneMinusReflectivity for optimization purposes, mostly for DX9 SM2.0 level.
    // Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots.
    half oneMinusReflectivity, smoothness;
    half3 normalWorld, eyeVec, posWorld;
    half alpha;
    half3 reflUVW;
};
oneMinusReflectivity 看单词意思反射率,不知道干嘛的,存疑
看函数FragmentSetup
inline FragmentCommonData FragmentSetup (float4 i_tex, half3 i_eyeVec, half3 i_viewDirForParallax, half4 tangentToWorld[3], half3 i_posWorld)
{
    i_tex = Parallax(i_tex, i_viewDirForParallax);

    half alpha = Alpha(i_tex.xy);
    #if defined(_ALPHATEST_ON)
        clip (alpha - _Cutoff);
    #endif

    FragmentCommonData o = UNITY_SETUP_BRDF_INPUT (i_tex);
    o.normalWorld = PerPixelWorldNormal(i_tex, tangentToWorld);
    o.eyeVec = NormalizePerPixelNormal(i_eyeVec);
    o.posWorld = i_posWorld;

    // NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
    o.diffColor = PreMultiplyAlpha (o.diffColor, alpha, o.oneMinusReflectivity, /*out*/ o.alpha);
    return o;
}
i_tex = Parallax(i_tex, i_viewDirForParallax);忽略,没用视差贴图,这句等于没用
half alpha = Alpha(i_tex.xy);
    #if defined(_ALPHATEST_ON)
        clip (alpha - _Cutoff);
    #endif

 clip不需要去掉

走进UNITY_SETUP_BRDF_INPUT ,默认是SpecularSetup

inline FragmentCommonData SpecularSetup (float4 i_tex)
{
    half4 specGloss = SpecularGloss(i_tex.xy);
    half3 specColor = specGloss.rgb;
    half smoothness = specGloss.a;

    half oneMinusReflectivity;
    half3 diffColor = EnergyConservationBetweenDiffuseAndSpecular (Albedo(i_tex), specColor, /*out*/ oneMinusReflectivity);

    FragmentCommonData o = (FragmentCommonData)0;
    o.diffColor = diffColor;
    o.specColor = specColor;
    o.oneMinusReflectivity = oneMinusReflectivity;
    o.smoothness = smoothness;
    return o;
}

但是在standard.shader里有#define UNITY_SETUP_BRDF_INPUT MetallicSetup,所以其实是

inline FragmentCommonData MetallicSetup (float4 i_tex)
{
    half2 metallicGloss = MetallicGloss(i_tex.xy);
    half metallic = metallicGloss.x;
    half smoothness = metallicGloss.y; // this is 1 minus the square root of real roughness m.

    half oneMinusReflectivity;
    half3 specColor;
    half3 diffColor = DiffuseAndSpecularFromMetallic (Albedo(i_tex), metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);

    FragmentCommonData o = (FragmentCommonData)0;
    o.diffColor = diffColor;
    o.specColor = specColor;
    o.oneMinusReflectivity = oneMinusReflectivity;
    o.smoothness = smoothness;
    return o;
}

  把

FragmentSetup 和
FragmentGI 合并到一块
fixed4 frag(v2f i) : SV_Target
            {
            
                UnityLight mainLight = MainLight ();
                half atten = SHADOW_ATTENUATION(i);
                
                UnityGIInput d;
                d.light = mainLight;
                d.worldPos = i.posWorld;
                half3 worldViewDir  = -normalize(i.eyeVec);
                d.worldViewDir = worldViewDir
                d.atten = atten;
                d.ambient = i_ambientOrLightmapUV.rgb;
                d.lightmapUV = 0;
                d.probeHDR[0] = unity_SpecCube0_HDR;
                d.probeHDR[1] = unity_SpecCube1_HDR;
                fixed metallic = _MetallicMin + channel.g * ( _Metallic - _MetallicMin );
                half oneMinusReflectivity;
                half3 specColor;
                half3 diffColor = DiffuseAndSpecularFromMetallic (mainTex.rgb, metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);
                fixed smoothness = ( _GlossinessMin + channel.r * (_Glossiness-_GlossinessMin)  )* 0.99h;
                half3 normalWorld = PerPixelWorldNormal(i.tex, i.tangentToWorldAndParallax )
                Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(smoothness, worldViewDir, s.normalWorld, specColor);
                // Replace the reflUVW if it has been compute in Vertex shader. Note: the compiler will optimize the calcul in UnityGlossyEnvironmentSetup itself
                g.reflUVW = i.reflUVW;
                UnityGI gi = UnityGlobalIllumination (d, 1, normalWorld, g);                
                 half4 c = BRDF(diffColor, specColor, oneMinusReflectivity, smoothness, normalWorld, worldViewDir, gi.light, gi.indirect);
                c.rgb += BRDF_GI (diffColor, specColor, oneMinusReflectivity, smoothness, normalWorld, worldViewDir, 1, gi);
                fixed emimask = tex2D(_EmissiveMap, i.uv).r;
                fixed3 Emissive = emimask * _EmissiveColor.rgb * _EmissiveIntensity;
                float3 _Rim = pow(1.0 - max(0, dot(normalWorld, worldViewDir)), _RimArea)*_RimColor.rgb*_RimPower;
                c.rgb += Emissive + _Rim;
                UNITY_APPLY_FOG(i.fogCoord, c.rgb);
                return OutputForward (c, 1);
            }

后面部分加了自发光和边缘光

现在只剩下BRDF和BRDF_GI 了

推荐阅读