the normal map for my material is super weak- only on one side- only on custom meshes

so i have this worldspace shader- i forget who i stole it from- that i modified to support normal maps. i just noticed that for some reason, all of my custom meshes (they’re all boxes or modified boxes) that i’ve applied this shader to have one axis (two opposite sides) where the normal map is just really weak? this is already weird because it’s a worldspace shader so the side shouldn’t matter, and when you rotate it around the texture is transformed accordingly but that side of the mesh still draws the normal really weak. this isn’t a problem with the actual color texture- just the normal map. and it’s not a problem with unity-generated shapes- here’s a side by side of a mesh cube and a unity cube:

This also happens if you generate a mesh manually with a script- only on sides that //start out// facing the z axis. I can’t imagine it’s a shader problem but here’s the code:

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" {}
    _BumpPowerSIDE("Side Normal Strength", Float) = 1
    _BumpMapTOP("Top Normal Map", 2D) = "bump" {}
    _BumpPowerTOP("Top Normal Strength", Float) = 1

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

CGPROGRAM
#pragma surface surf Lambert

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

sampler2D _BumpMapSIDE;
sampler2D _BumpMapTOP;
float _BumpPowerSIDE;
float _BumpPowerTOP;

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

void surf (Input IN, inout SurfaceOutput o)
{
    float2 UV;
    fixed4 c;
    float3 n;
   
    float _BumpPower = 0;
   
    IN.worldNormal = WorldNormalVector(IN, float3(0,0,1));
   
   
    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*_Scale));
        _BumpPower = _BumpPowerTOP;
    }
    else
    {
       
        if(abs(IN.worldNormal.x)>0.5){
            UV = IN.worldPos.zy; // 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*_Scale));
        _BumpPower = _BumpPowerSIDE;
    }
   
   


   
    o.Albedo = c.rgb * _Color;
    n.z = n.z / _BumpPower;
    o.Normal = normalize(n);
   
}
ENDCG
}

Fallback "VertexLit"
}

That’s because you can’t use normal maps with world position based UVs without doing additional work. Especially not with Surface Shaders because they always assume the o.Normal is a tangent space normal. Understand that “tangent space” is the orientation of the UVs, specifically the UVs the mesh itself has when it was imported! If you’re calculating dynamic UVs in a Surface Shader that don’t align exactly with the mesh’s existing UVs, then you have to convert the tangent space normals from the tangent space of the calculated normals to the tangent space the mesh has.

This article goes into how tangent space normal maps and triplanar normal mapping works, and has a short section and example shader for how to use world space triplanar normal maps in Surface Shaders.

wait wouldn’t that mean that the shader just fully wouldn’t work? it actually does work for all the other sides, you can rotate it and move it around and it transforms correctly. even on the broken sides it works but it’s just really weak for some reason

I mean it “works” in that you’re seeing normals being modified. Sure. But something like a checkerboard normal pattern it isn’t always going to be obvious when those normals aren’t correct… until it breaks completely.

The real take away is the tangents of the mesh you’re using still matter, and need to be valid. My guess is that mesh’s UVs for that particular face is messed up, so the tangents aren’t usable. What happens if you try to put a regular material on that mesh with a checkboard texture?

ooohhhhh i get what you mean. regular albedo textures work fine. how would i go about integrating the uv of the mesh into the shader

You’ll need to work through the article I posted above and understand how to transform your normal maps into world space first. Then you’ll need to transform them from world to the mesh’s tangent space.

An example function for the last part, WorldToTangentNormalVector(), is in my example surface shader which you can find linked to in that article. But it won’t be of any use until you understand the rest of what you need to do.