unity中使用AO贴图和自发光emission的简单应用

注意点:
1.法线的归一化 normalize (如果shader光照效果怪怪的,请查看是否归一化)
2.在计算自发光emission 直接使用的normal : appdata 中的normal 转到世界空间中的normal。emission跟光照没有关系,不受光照的影响(不是所有的地方都有自发光:添加emissionMask)
3.在计算直接光照效果 diffuse 和specular的时候, 用切线空间转换到世界空间中的法线
4.AO贴图: 只作用在 间接光照中 : Indirectlight中的 diffuse 和specular
用AO来限制他们的亮度
5.用一张图的 rgba四个通道来存储相应的遮罩等值

unity中使用AO贴图和自发光emission的简单应用_第1张图片

下面是实现代码:

Shader "FishMan/12_AOE"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BumpMap ("Normal Map", 2D) = "bump"{}
        _Metallic_AO_MASK_Smoothness("_Metallic_AO_MASK_Smoothness", 2D) = "white" {}

        [HDR]_FresnelColor("FresnelColor", Color) = (0,0,0,0)
        _FresnelPower("FresnelPower", Range( 0 , 30)) = 0.8
        _FresnelScale("FresnelScale", Range( 0 , 1)) = 1
    }
    SubShader
    {
        Pass
        {
            Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0           
            #define _FORWADR_BASE
            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
            #include "../ExampleLibs/12_AOEimission.cginc"  
            ENDCG 
        }

        Pass
        {

            Tags { "RenderType"="Opaque" "LightMode" = "ForwardAdd" }
            Blend One One
            ZWrite Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdadd
            #pragma multi_compile_fog
            #pragma target 3.0 
            #include "../ExampleLibs/12_AOEimission.cginc" 
            ENDCG
        }

        Pass
        {
            Tags {"LightMode"="ShadowCaster"}
        
            CGPROGRAM
            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster
            #pragma multi_compile_shadowcaster
            #include "../../ShaderLibs/Shadow.cginc" 
            ENDCG
        }
    }
}

#ifndef FMST02_AO_EIMISSION
#define FMST02_AO_EIMISSION


#include "UnityCG.cginc"
#include "UnityPBSLighting.cginc" // PBS
#include "AutoLight.cginc"

struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    float3 normal : NORMAL;
    float4 tangent : TANGENT;
};

struct v2f
{
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD0;
    float3 normal : TEXCOORD1;
    float3 worldPos: TEXCOORD2;

    #if defined(VERTEXLIGHT_ON)
        float3 vertexLightColor : TEXCOORD3;
    #endif

    SHADOW_COORDS(4) 
    UNITY_FOG_COORDS(5) // 8 
    float3 T2WRow0 : TEXCOORD6;
    float3 T2WRow1 : TEXCOORD7;
    float3 T2WRow2 : TEXCOORD8;
};

sampler2D _MainTex;

float4 _MainTex_ST; 

sampler2D _BumpMap;
sampler2D _Metallic_AO_MASK_Smoothness;

float4 _FresnelColor;
float _FresnelScale;
float _FresnelPower;

UnityLight CreateDirectLight(v2f i){
    float3 lightDir;
    // float attenuation = 1;
     #if defined(DIRECTIONAL)
         lightDir = _WorldSpaceLightPos0.xyz;
     #else
         float3 lightVec= _WorldSpaceLightPos0.xyz - i.worldPos; 
         lightDir = normalize(lightVec);
     #endif
    UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos);  


    UnityLight light;
    light.color = _LightColor0.rgb * attenuation;
    light.dir = lightDir;
    light.ndotl = saturate(dot(lightDir,i.normal));
    return light;
}

UnityIndirect CreateIndirectLight (v2f i) {
    UnityIndirect indirectLight;
    indirectLight.diffuse = 0;
    indirectLight.specular = 0;
#if defined(VERTEXLIGHT_ON)
    indirectLight.diffuse = i.vertexLightColor;
#endif

#if defined(_FORWADR_BASE)
    indirectLight.diffuse += max(0, ShadeSH9(float4(i.normal, 1)));
#endif
    return indirectLight;
}


void CalcVertexLightColor(inout  v2f i){
#if defined(VERTEXLIGHT_ON)
    i.vertexLightColor = Shade4PointLights(
            unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
            unity_LightColor[0].rgb, unity_LightColor[1].rgb,
            unity_LightColor[2].rgb, unity_LightColor[3].rgb,
            unity_4LightAtten0, i.worldPos, i.normal
        );
#endif
}

v2f vert (appdata v)
{
    v2f o;
    UNITY_INITIALIZE_OUTPUT(v2f,o);
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.normal = UnityObjectToWorldNormal(v.normal)  ;
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);

    CalcVertexLightColor(o);
    TRANSFER_SHADOW(o)
    UNITY_TRANSFER_FOG(o,o.pos);

    fixed3 worldNormal = o.normal;
    fixed3 worldTangent = UnityObjectToWorldDir( v.tangent.xyz );
    fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
    fixed3 worldBinormal = cross( worldNormal, worldTangent ) * tangentSign;


    o.T2WRow0 = float3( worldTangent.x, worldBinormal.x, worldNormal.x); // * tNormal.xyz
    o.T2WRow1 = float3( worldTangent.y, worldBinormal.y, worldNormal.y);
    o.T2WRow2 = float3( worldTangent.z, worldBinormal.z, worldNormal.z);

    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    fixed4 albedo = tex2D(_MainTex, i.uv);
    float3 normalVal = UnpackNormal( tex2D(_BumpMap,i.uv));
    fixed4 metallic_AO_MASK_Smoothness = tex2D(_Metallic_AO_MASK_Smoothness, i.uv);

    float metallic = metallic_AO_MASK_Smoothness.r;
    float smoothness = metallic_AO_MASK_Smoothness.a;
    float occlusion = metallic_AO_MASK_Smoothness.g ;

    float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
#if defined(_FORWADR_BASE)
    float emissionMask = metallic_AO_MASK_Smoothness.b;
    float ndv = dot( normalize(i.normal), viewDir );
    float fresnel = pow(1 - ndv,_FresnelPower) * _FresnelScale ;
    float4 emission =  fresnel * emissionMask * _FresnelColor;
#endif  


    i.normal = fixed3(dot(i.T2WRow0,normalVal), dot(i.T2WRow1,normalVal), dot(i.T2WRow2,normalVal));
    i.normal = normalize(i.normal);
 
    float oneMinusReflectivity ;
    float3 specularTint;
    albedo.rgb = DiffuseAndSpecularFromMetallic(albedo,metallic,specularTint,oneMinusReflectivity);
    
    UnityLight light = CreateDirectLight(i);

    UnityIndirect indirectLight = CreateIndirectLight(i);
    indirectLight.diffuse *= occlusion;
    indirectLight.specular *= occlusion;

    //light.color *= occlusion;
    float4 col = UNITY_BRDF_PBS(albedo,specularTint,oneMinusReflectivity,smoothness,
        i.normal,viewDir,
        light,indirectLight
        );
    UNITY_APPLY_FOG(i.fogCoord, col); 
#if defined(_FORWADR_BASE)
    col += emission;
#endif  
    return col;
}
#endif

附资源百度云:
链接: https://pan.baidu.com/s/1UdDCnt6uEfhy5IPNnEam5g
提取码: 9b6s

你可能感兴趣的:(PBR,unity,AO,PBS,shader)