zoukankan      html  css  js  c++  java
  • Unity Standard Shader代码

    下载Unity官方的提供的Shader资源,里面有个文件叫Standar.shader 就是Unity5.0的之后的用的基于BDRF的shader源代码。

    里面包含的多个SubShader 和Pass 这里我们挑 Shader2.0 和 ForwardBase Pass 具体Shader2.0 和ForwardBase Pass 后面文章说。

    File:Standard.shader

    Pass
            {
                Name "FORWARD"
                Tags { "LightMode" = "ForwardBase" }
    
                Blend [_SrcBlend] [_DstBlend]
                ZWrite [_ZWrite]
    
                CGPROGRAM
                #pragma target 2.0
    
                #pragma shader_feature _NORMALMAP
                #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
                #pragma shader_feature _EMISSION
                #pragma shader_feature _METALLICGLOSSMAP
                #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
                #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
                #pragma shader_feature _ _GLOSSYREFLECTIONS_OFF
                // SM2.0: NOT SUPPORTED shader_feature ___ _DETAIL_MULX2
                // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
    
                #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED
    
                #pragma multi_compile_fwdbase
                #pragma multi_compile_fog
    
                #pragma vertex vertBase
                #pragma fragment fragBase
                #include "UnityStandardCoreForward.cginc"
    
                ENDCG
            }

    这里看到,代码里面 

      #pragma vertex vertBase
      #pragma fragment fragBase

    可以看到顶点着色器和像素着色器
    File:UnityStandardCoreForward.cginc
    #if UNITY_STANDARD_SIMPLE
        #include "UnityStandardCoreForwardSimple.cginc"
        VertexOutputBaseSimple vertBase (VertexInput v) { return vertForwardBaseSimple(v); }
        VertexOutputForwardAddSimple vertAdd (VertexInput v) { return vertForwardAddSimple(v); }
        half4 fragBase (VertexOutputBaseSimple i) : SV_Target { return fragForwardBaseSimpleInternal(i); }
        half4 fragAdd (VertexOutputForwardAddSimple i) : SV_Target { return fragForwardAddSimpleInternal(i); }
    #else
        #include "UnityStandardCore.cginc"
        VertexOutputForwardBase vertBase (VertexInput v) { return vertForwardBase(v); }
        VertexOutputForwardAdd vertAdd (VertexInput v) { return vertForwardAdd(v); }
        half4 fragBase (VertexOutputForwardBase i) : SV_Target { return fragForwardBaseInternal(i); }
        half4 fragAdd (VertexOutputForwardAdd i) : SV_Target { return fragForwardAddInternal(i); }
    #endif

    这里分为两个分支,简单的和标准,我们这里看标准的。

     VertexOutputForwardBase vertBase (VertexInput v) { return vertForwardBase(v); }
     half4 fragBase (VertexOutputForwardBase i) : SV_Target { return fragForwardBaseInternal(i); }
    File:UnityStandardCore.cginc

    VertexOutputForwardBase vertForwardBase (VertexInput v)
    {
        UNITY_SETUP_INSTANCE_ID(v);
        VertexOutputForwardBase o;
        UNITY_INITIALIZE_OUTPUT(VertexOutputForwardBase, o);
        UNITY_TRANSFER_INSTANCE_ID(v, o);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    
        float4 posWorld = mul(unity_ObjectToWorld, v.vertex);
        #if UNITY_REQUIRE_FRAG_WORLDPOS
            #if UNITY_PACK_WORLDPOS_WITH_TANGENT
                o.tangentToWorldAndPackedData[0].w = posWorld.x;
                o.tangentToWorldAndPackedData[1].w = posWorld.y;
                o.tangentToWorldAndPackedData[2].w = posWorld.z;
            #else
                o.posWorld = posWorld.xyz;
            #endif
        #endif
        o.pos = UnityObjectToClipPos(v.vertex);
    
        o.tex = TexCoords(v);
        o.eyeVec = NormalizePerVertexNormal(posWorld.xyz - _WorldSpaceCameraPos);
        float3 normalWorld = UnityObjectToWorldNormal(v.normal);
        #ifdef _TANGENT_TO_WORLD
            float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
    
            float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w);
            o.tangentToWorldAndPackedData[0].xyz = tangentToWorld[0];
            o.tangentToWorldAndPackedData[1].xyz = tangentToWorld[1];
            o.tangentToWorldAndPackedData[2].xyz = tangentToWorld[2];
        #else
            o.tangentToWorldAndPackedData[0].xyz = 0;
            o.tangentToWorldAndPackedData[1].xyz = 0;
            o.tangentToWorldAndPackedData[2].xyz = normalWorld;
        #endif
    
        //We need this for shadow receving
        UNITY_TRANSFER_SHADOW(o, v.uv1);
    
        o.ambientOrLightmapUV = VertexGIForward(v, posWorld, normalWorld);
    
        #ifdef _PARALLAXMAP
            TANGENT_SPACE_ROTATION;
            half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(v.vertex));
            o.tangentToWorldAndPackedData[0].w = viewDirForParallax.x;
            o.tangentToWorldAndPackedData[1].w = viewDirForParallax.y;
            o.tangentToWorldAndPackedData[2].w = viewDirForParallax.z;
        #endif
    
        UNITY_TRANSFER_FOG(o,o.pos);
        return o;
    }
    half4 fragForwardBaseInternal (VertexOutputForwardBase i)
    {
        UNITY_APPLY_DITHER_CROSSFADE(i.pos.xy);
    
        FRAGMENT_SETUP(s)
    
        UNITY_SETUP_INSTANCE_ID(i);
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    
        UnityLight mainLight = MainLight ();
        UNITY_LIGHT_ATTENUATION(atten, i, s.posWorld);
    
        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 += Emission(i.tex.xy);
    
        UNITY_APPLY_FOG(i.fogCoord, c.rgb);
        return OutputForward (c, s.alpha);
    }

    像素着色器中UNITY_BRDF_PBS 这个函数有三挡的分支

    File:UnityPBSLighting.cginc

    // Default BRDF to use:
    #if !defined (UNITY_BRDF_PBS) // allow to explicitly override BRDF in custom shader
        // still add safe net for low shader models, otherwise we might end up with shaders failing to compile
        #if SHADER_TARGET < 30
            #define UNITY_BRDF_PBS BRDF3_Unity_PBS
        #elif defined(UNITY_PBS_USE_BRDF3)
            #define UNITY_BRDF_PBS BRDF3_Unity_PBS
        #elif defined(UNITY_PBS_USE_BRDF2)
            #define UNITY_BRDF_PBS BRDF2_Unity_PBS
        #elif defined(UNITY_PBS_USE_BRDF1)
            #define UNITY_BRDF_PBS BRDF1_Unity_PBS
        #elif defined(SHADER_TARGET_SURFACE_ANALYSIS)
            // we do preprocess pass during shader analysis and we dont actually care about brdf as we need only inputs/outputs
            #define UNITY_BRDF_PBS BRDF1_Unity_PBS
        #else
            #error something broke in auto-choosing BRDF
        #endif
    #endif

    我们看完全体的 

     UNITY_BRDF_PBS BRDF1_Unity_PBS 函数 在文件 UnityStandardBRDF.cginc中

    File:UnityStandardBRDF.cginc
    half4 BRDF1_Unity_PBS (half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
        half3 normal, half3 viewDir,
        UnityLight light, UnityIndirect gi)
    {
        half perceptualRoughness = SmoothnessToPerceptualRoughness (smoothness);
        half3 halfDir = Unity_SafeNormalize (light.dir + viewDir);
    
    // NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping
    // In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts.
    // but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too).
    // Following define allow to control this. Set it to 0 if ALU is critical on your platform.
    // This correction is interesting for GGX with SmithJoint visibility function because artifacts are more visible in this case due to highlight edge of rough surface
    // Edit: Disable this code by default for now as it is not compatible with two sided lighting used in SpeedTree.
    #define UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV 0
    
    #if UNITY_HANDLE_CORRECTLY_NEGATIVE_NDOTV
        // The amount we shift the normal toward the view vector is defined by the dot product.
        half shiftAmount = dot(normal, viewDir);
        normal = shiftAmount < 0.0f ? normal + viewDir * (-shiftAmount + 1e-5f) : normal;
        // A re-normalization should be applied here but as the shift is small we don't do it to save ALU.
        //normal = normalize(normal);
    
        half nv = saturate(dot(normal, viewDir)); // TODO: this saturate should no be necessary here
    #else
        half nv = abs(dot(normal, viewDir));    // This abs allow to limit artifact
    #endif
    
        half nl = saturate(dot(normal, light.dir));
        half nh = saturate(dot(normal, halfDir));
    
        half lv = saturate(dot(light.dir, viewDir));
        half lh = saturate(dot(light.dir, halfDir));
    
        // Diffuse term
        half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;
    
        // Specular term
        // HACK: theoretically we should divide diffuseTerm by Pi 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 too in cases when they are injected into ambient SH
        half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
    #if UNITY_BRDF_GGX
        // GGX with roughtness to 0 would mean no specular at all, using max(roughness, 0.002) here to match HDrenderloop roughtness remapping.
        roughness = max(roughness, 0.002);
        half V = SmithJointGGXVisibilityTerm (nl, nv, roughness);
        half D = GGXTerm (nh, roughness);
    #else
        // Legacy
        half V = SmithBeckmannVisibilityTerm (nl, nv, roughness);
        half D = NDFBlinnPhongNormalizedTerm (nh, PerceptualRoughnessToSpecPower(perceptualRoughness));
    #endif
    
        half specularTerm = V*D * UNITY_PI; // Torrance-Sparrow model, Fresnel is applied later
    
    #   ifdef UNITY_COLORSPACE_GAMMA
            specularTerm = sqrt(max(1e-4h, specularTerm));
    #   endif
    
        // specularTerm * nl can be NaN on Metal in some cases, use max() to make sure it's a sane value
        specularTerm = max(0, specularTerm * nl);
    #if defined(_SPECULARHIGHLIGHTS_OFF)
        specularTerm = 0.0;
    #endif
    
        // surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(roughness^2+1)
        half surfaceReduction;
    #   ifdef UNITY_COLORSPACE_GAMMA
            surfaceReduction = 1.0-0.28*roughness*perceptualRoughness;      // 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]
    #   else
            surfaceReduction = 1.0 / (roughness*roughness + 1.0);           // fade in [0.5;1]
    #   endif
    
        // To provide true Lambert lighting, we need to be able to kill specular completely.
        specularTerm *= any(specColor) ? 1.0 : 0.0;
    
        half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));
        half3 color =   diffColor * (gi.diffuse + light.color * diffuseTerm)
                        + specularTerm * light.color * FresnelTerm (specColor, lh)
                        + surfaceReduction * gi.specular * FresnelLerp (specColor, grazingTerm, nv);
    
        return half4(color, 1);
    }


  • 相关阅读:
    XmlDocument和XDocument转String
    C# 6.0 (C# vNext) 新功能之:Null-Conditional Operator(转)
    <%%>与<scriptrunat=server>,<%=%>与<%#%>的区别(转)
    WINDOWS的用户和用户组说明
    C#获取网页内容的三种方式(转)
    C#操作XML方法:新增、修改和删除节点与属性
    linq to xml操作XML(转)
    C#使用tesseract3.02识别验证码模拟登录(转)
    C#修饰符
    SQL语句备份和还原数据库(转)
  • 原文地址:https://www.cnblogs.com/wbaoqing/p/8931646.html
Copyright © 2011-2022 走看看