Standard Shader with Anisotropic Blend

Hey Guys,

I’m trying to make a shader that uses UnityStandard (specular or metatalic) surface shader lighting but that allows blending (additively) with an custom Anisotropic lighting setup. The idea is that you could have a slider/value that determines how much Anisotropic light to add on top of the standed lighting, if that makes any sense.

Currently I have what you see below. What seems to be happening is that the second pass (anisotropic) is being ignored/overriden by the first (Unity StandardSpecular) pass. The Weird thing is that in the Unity Inspector window when I adjust the Aniso Strength it seems to work correct but not in the game/scene view.

I’m also not entirely sure that it’s even possible to do this. Any info would be a great help!

Shader "Custom/AnisoBlend" {
    Properties {
        _Color("Color", Color) = (1,1,1,1)
        _MainTex("Albedo (RGB)", 2D) = "white" {}
        _BumpMap("Normal Map", 2D) = "Bump"{}
        _BumpScale("Normal Power", Float) = 1.0
        _SpecularMap("Specular (R) Gloss (G) Anisotropic Mask (B)", 2D) = "gray" {}
        _SpecularPower("Specular Power", float) = 1.0
        _SpecularColor("Specular Color", Color) = (1,1,1,1)
        _CustomOffset("Anisotropic Highlight Offset", Range(-1,1)) = 0.0
        _Glossiness("Gloss Power", float) = 128.0
        _AnisoStrength("Aniso Strength", float) = 1
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
       
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf StandardSpecular fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex, _SpecularMap, _BumpMap;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness, _BumpScale;
        fixed4 _SpecColor2;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandardSpecular o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
           
            fixed4 s = tex2D(_SpecularMap, IN.uv_MainTex) * _SpecColor2;
            o.Specular = s.rgb;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
            o.Normal = UnpackScaleNormal(tex2D(_BumpMap, IN.uv_MainTex), _BumpScale);
        }
        ENDCG

            //Aniso Pass

            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Custom

            // Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0

            struct SurfaceOutputCustom
        {
            fixed3 Albedo;
            fixed3 Normal;
            fixed3 Emission;
            half Specular;
            fixed Gloss;
            fixed Alpha;
            fixed CustomMask;

        };

        struct Input {
            float2 uv_MainTex;
        };

        sampler2D _MainTex, _SpecularMap, _BumpMap;
        float _CustomOffset, _SpecularPower, _Glossiness, _AnisoStrength;
        fixed4 _SpecularColor, _Color;
        half _BumpScale;

        void surf(Input IN, inout SurfaceOutputCustom o) {
            // Albedo comes from a texture tinted by color
            fixed4 a = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = lerp(a.rgb, a.rgb*_Color.rgb, 0.5);

            fixed3 spec = tex2D(_SpecularMap, IN.uv_MainTex).rgb;
            o.Specular = spec.r;
            o.Gloss = spec.g;
            o.CustomMask = spec.b;
            o.Alpha = a.a;
            o.Normal = UnpackScaleNormal(tex2D(_BumpMap, IN.uv_MainTex), _BumpScale);
        }

        inline fixed4 LightingCustom(SurfaceOutputCustom s, fixed3 lightDir, fixed3 viewDir, fixed atten)
        {
            s.Normal = normalize(s.Normal);
            fixed3 h = normalize(normalize(lightDir) + normalize(viewDir));
            float NdotL = saturate(dot(s.Normal, lightDir));

            fixed HdotA = dot(s.Normal, h);
            float aniso = max(0, sin(radians((HdotA + _CustomOffset) * 180)));

            float spec = saturate(dot(s.Normal, h));
            spec = saturate(pow(lerp(spec, aniso, s.CustomMask), s.Gloss * _Glossiness) * s.Specular);
            spec = spec * _SpecularPower;

            fixed4 c;
            c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL * _Color) + (_LightColor0.rgb * spec * _SpecularColor * NdotL)) * (atten * 2);
            c.a = s.Alpha;

            return c * _AnisoStrength;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

So I have tried another approach but still having problems.
Basically with this approach I plan to use an custom lighting function and in that get the standard lighting from “UnityPBSLighting.cginc” and then calculate the Aniso lighting and add it on top of that.
The Problem is that I need the LightDir (Light direction) and Atten (Attenuation) to be able to calculate the Anisotropic lighting but Unity’s PBS lighting function doesnt have those values.

Anyways heres the code for that.

Shader "Custom/LightBlend" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness("Smoothness", Range(0,1)) = 0.5
        _SpecularMap("Specular", 2D) = "white" {}
        _AnisoLevel("Aniso Level",Range(0,1)) = 0.0
        _Gloss("Gloss Multiplier", float) = 128.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
       
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Custom fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        #include "UnityPBSLighting.cginc"

        sampler2D _MainTex, _SpecularMap;

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
        float _AnisoLevel, _Gloss;
        inline half4 LightingCustom(SurfaceOutputStandardSpecular s, half3 viewDir, UnityGI gi )
        {
            half4 light = LightingStandardSpecular(s, viewDir, gi);

            //Anisotropic lighting --- requires lightDir and atten (like in Blinn Phong Model)


            fixed3 h = normalize(normalize(lightDir) + normalize(viewDir));
            float NdotL = saturate(dot(s.Normal, lightDir));

            fixed HdotA = dot(s.Normal, h);
            float aniso = max(0, sin(radians((HdotA + _CustomOffset) * 180)));

            float spec = saturate(dot(s.Normal, h));
            spec = saturate(pow(lerp(spec, aniso, s.CustomMask), s.Gloss * _Glossiness) * s.Specular);
            spec = spec * _SpecularPower;

            fixed4 c;
            c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL * _Color) + (_LightColor0.rgb * spec * _SpecularColor * NdotL)) * (atten * 2);
            c.a = s.Alpha;


            //blend (additive) Aniso lighiting to standard
            light += c * _anisoLevel;

            return light;
        }

        inline void LightingCustom_GI(
            SurfaceOutputStandardSpecular s,
            UnityGIInput data,
            inout UnityGI gi)
        {
            LightingStandardSpecular_GI(s, data, gi);
        }

       

        struct Input {
            float2 uv_MainTex;
        };

       

        void surf (Input IN, inout SurfaceOutputStandardSpecular o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;

            fixed4 s = tex2D(_SpecularMap, IN.uv_MainTex);
            o.Specular = s.rgb;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Sure it does, the standard lighting function needs that data too. It’s just in the UnityGI value.

Well, the attenuation is for sure, and the direction used to be but I can’t remember if it is still or not. They might be calculating it from _WorldSpaceLightPos0.

Right I thought that might be the case, I just havent been able to work out how to access / reference it.
Thanks! I’ll keep playing around with it and see what I can work out