can't write to o.Normal without undoing shader code?

so i’m trying to add normal bump map support to this shader

Shader "Diffuse - Worldspace" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTexSIDE ("Side Base (RGB)", 2D) = "white" {}
    _MainTexTOP ("Top Base (RGB)", 2D) = "white" {}
    _Scale ("Texture Scale", Float) = 1.0
  
  
  

}
SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200

CGPROGRAM
#pragma surface surf Lambert

sampler2D _MainTexSIDE;
sampler2D _MainTexTOP;
fixed4 _Color;
float _Scale;


struct Input
{
    float3 worldPos;
    float3 worldNormal;

  
   
};

void surf (Input IN, inout SurfaceOutput o)
{
    float2 UV;
    fixed4 c;

  
  
    if(abs(IN.worldNormal.y)>0.5)
    {
        UV = IN.worldPos.xz; // top
        c = tex2D(_MainTexTOP, UV* _Scale); // use FLR texture
    }
    else
    {
      
        if(abs(IN.worldNormal.x)>0.5){
            UV = IN.worldPos.yz; // side
            c = tex2D(_MainTexSIDE, UV* _Scale); // use WALLSIDE texture
        } else {
            UV = IN.worldPos.xy; // side
            c = tex2D(_MainTexSIDE, UV* _Scale); // use WALLSIDE texture
        } 
    }
  

    o.Albedo = c.rgb * _Color;
}
ENDCG
}

Fallback "VertexLit"
}

this means i have to write to o.Normal, so I have to use INTERNAL_DATA

Shader "Diffuse - Worldspace" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTexSIDE ("Side Base (RGB)", 2D) = "white" {}
    _MainTexTOP ("Top Base (RGB)", 2D) = "white" {}
    _Scale ("Texture Scale", Float) = 1.0
  
  
    _BumpMapSIDE("Side Normal Map", 2D) = "bump" {}
    _BumpMapTOP("Top Normal Map", 2D) = "bump" {}
  

}
SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200

CGPROGRAM
#pragma surface surf Lambert

sampler2D _MainTexSIDE;
sampler2D _MainTexTOP;
fixed4 _Color;
float _Scale;

sampler2D _BumpMapSIDE;
sampler2D _BumpMapTOP;

struct Input
{
    float3 worldPos;
    float3 worldNormal;
     INTERNAL_DATA
  
   
};

void surf (Input IN, inout SurfaceOutput o)
{
    float2 UV;
    fixed4 c;
    fixed3 n;
  
  
    if(abs(IN.worldNormal.y)>0.5)
    {
        UV = IN.worldPos.xz; // top
        c = tex2D(_MainTexTOP, UV* _Scale); // use FLR texture
        n = UnpackNormal (tex2D (_BumpMapTOP, UV));
    }
    else
    {
      
        if(abs(IN.worldNormal.x)>0.5){
            UV = IN.worldPos.yz; // side
            c = tex2D(_MainTexSIDE, UV* _Scale); // use WALLSIDE texture
        } else {
            UV = IN.worldPos.xy; // side
            c = tex2D(_MainTexSIDE, UV* _Scale); // use WALLSIDE texture
        } 
        n = UnpackNormal (tex2D (_BumpMapSIDE, UV));
    }
  

    o.Albedo = c.rgb * _Color;
    o.Normal = n;
}
ENDCG
}

Fallback "VertexLit"
}

the original shader is able to detect the angle of the surface normal “if(abs(IN.worldNormal.y)>0.5)” etc, and it uses that to determine which texture to use, but for some reason when i switch to INTERNAL_DATA, it’s able to render the normal map, but can no longer detect IN.worldNormal (it defaults to the ‘else’ statement so the first two cases must be returning false). what am i supposed to be using with INTERNAL_DATA enabled?

There is a long time bug with Surface Shaders that the IN.worldNormal isn’t set if the shader writes to o.Normal, even if you add INTERNAL_DATA. But there is a work around. That INTERNAL_DATA also enables the WorldNormalVector() function which can be used to get the surface normal, like this:

IN.worldNormal = WorldNormalVector(IN, float3(0,0,1));

However, the next issue is using normal maps like you’re attempting to wont really work. Check out this article on triplanar normal maps.

And here’s a Surface Shader using the techniques described above: