Setting the normal map scale (intensity) through code only works on editor, not in the build.

Hi, I’m using the next code to set the normal map intensity at the begining:

using UnityEngine;
using System.Collections;

public class MyScript : MonoBehaviour
{
    // The material is placed in the assets folder and attached here from Inspector
    public Material materialBody;

    void Awake()
    {
        materialBody.SetFloat("_BumpScale", 0.3f);
        materialBody.EnableKeyword("_NORMALMAP");
        materialBody.renderQueue = 3000;
    }
}

When I hit play I can see the material changes properly in the Inspector and also in the Scene view I see a 30% intensity.

The problem is that it only works on the editor, but when I make the build (Android) and install it in my phone it just doesn’t work, the normal map appears at full intensity.

I’m using the Standard material and only has a normal map assigned, no heightmap or others.

I also saw this post Unity - Manual: Using materials with C# scripts but I can figure out what am I doing wrong. Somebody facing the same problem?

I think it’s only supported in shader model 3.0+

1 Like

Hi @Farfarer thanks for your hint, I found my phone have only OpenGL2.0, so I borrow my friend’s phone to do some tests, it is a Galaxy S6 with OpenGl 3.1 and shader level 5.0. I configured the player settings like this:


This way all the textures are exported to work with OpenGL 3.0+
I built my app with this settings and installed both in my Opengl2.0 phone and my friend’s Opengl3.0 phone, and indeed in mine I see all my 3d models without textures (they appear in fuchsia color) while in my friend’s I can see all the textures properly, anyways the changes to the intensity of the normal map are not working yet, it continues showing at 100% intensity all the time.

Is there something I’m missing? Maybe this is not the proper way to export to OpenGL3.0? Maybe I need to change something in the shader’s import settings or create a custom shader? I really feel lost now, hope someone can help me.

I also made a custom shader from the Standard shader code, and set it to export to opengl3.0, as follows:

Shader "Standard2"
{
    Properties
    {
        _Color("Color", Color) = (1,1,1,1)
        _MainTex("Albedo", 2D) = "white" {}

        _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5

        _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
        [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
        _MetallicGlossMap("Metallic", 2D) = "white" {}

        _BumpScale("Scale", Float) = 1.0
        _BumpMap("Normal Map", 2D) = "bump" {}

        _Parallax("Height Scale", Range(0.005, 0.08)) = 0.02
        _ParallaxMap("Height Map", 2D) = "black" {}

        _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
        _OcclusionMap("Occlusion", 2D) = "white" {}

        _EmissionColor("Color", Color) = (0,0,0)
        _EmissionMap("Emission", 2D) = "white" {}

        _DetailMask("Detail Mask", 2D) = "white" {}

        _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
        _DetailNormalMapScale("Scale", Float) = 1.0
        _DetailNormalMap("Normal Map", 2D) = "bump" {}

        [Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0


            // Blending state
            [HideInInspector] _Mode("__mode", Float) = 0.0
            [HideInInspector] _SrcBlend("__src", Float) = 1.0
            [HideInInspector] _DstBlend("__dst", Float) = 0.0
            [HideInInspector] _ZWrite("__zw", Float) = 1.0
    }

        CGINCLUDE
#define UNITY_SETUP_BRDF_INPUT MetallicSetup
            ENDCG

            SubShader
        {
            Tags { "RenderType" = "Opaque" "PerformanceChecks" = "False" }
            LOD 300


            // ------------------------------------------------------------------
            //  Base forward pass (directional light, emission, lightmaps, ...)
            Pass
            {
                Name "FORWARD"
                Tags { "LightMode" = "ForwardBase" }

                Blend[_SrcBlend][_DstBlend]
                ZWrite[_ZWrite]

                CGPROGRAM
                #pragma target es3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            //#pragma exclude_renderers gles

            // -------------------------------------

            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog

            #pragma vertex vertBase
            #pragma fragment fragBase
            #include "UnityStandardCoreForward.cginc"

            ENDCG
        }
            // ------------------------------------------------------------------
            //  Additive forward pass (one light per pass)
            Pass
            {
                Name "FORWARD_DELTA"
                Tags { "LightMode" = "ForwardAdd" }
                Blend[_SrcBlend] One
                Fog { Color(0,0,0,0) } // in additive pass fog should be black
                ZWrite Off
                ZTest LEqual

                CGPROGRAM
                #pragma target es3.0
            // GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            //#pragma exclude_renderers gles

            // -------------------------------------


            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog

            #pragma vertex vertAdd
            #pragma fragment fragAdd
            #include "UnityStandardCoreForward.cginc"

            ENDCG
        }
            // ------------------------------------------------------------------
            //  Shadow rendering pass
            Pass {
                Name "ShadowCaster"
                Tags { "LightMode" = "ShadowCaster" }

                ZWrite On ZTest LEqual

                CGPROGRAM
                #pragma target es3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            //#pragma exclude_renderers gles

            // -------------------------------------


            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma multi_compile_shadowcaster

            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            #include "UnityStandardShadow.cginc"

            ENDCG
        }
            // ------------------------------------------------------------------
            //  Deferred pass
            Pass
            {
                Name "DEFERRED"
                Tags { "LightMode" = "Deferred" }

                CGPROGRAM
                #pragma target es3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            //#pragma exclude_renderers nomrt gles


            // -------------------------------------

            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            #pragma multi_compile ___ UNITY_HDR_ON
            #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
            #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
            #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON

            #pragma vertex vertDeferred
            #pragma fragment fragDeferred

            #include "UnityStandardCore.cginc"

            ENDCG
        }

            // ------------------------------------------------------------------
            // Extracts information for lightmapping, GI (emission, albedo, ...)
            // This pass it not used during regular rendering.
            Pass
            {
                Name "META"
                Tags { "LightMode" = "Meta" }

                Cull Off

                CGPROGRAM
                #pragma vertex vert_meta
                #pragma fragment frag_meta

                #pragma shader_feature _EMISSION
                #pragma shader_feature _METALLICGLOSSMAP
                #pragma shader_feature ___ _DETAIL_MULX2

                #include "UnityStandardMeta.cginc"
                ENDCG
            }
        }

            SubShader
        {
            Tags { "RenderType" = "Opaque" "PerformanceChecks" = "False" }
            LOD 150

            // ------------------------------------------------------------------
            //  Base forward pass (directional light, emission, lightmaps, ...)
            Pass
            {
                Name "FORWARD"
                Tags { "LightMode" = "ForwardBase" }

                Blend[_SrcBlend][_DstBlend]
                ZWrite[_ZWrite]

                CGPROGRAM
                #pragma target es3.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 ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP

            #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE

            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog

            #pragma vertex vertBase
            #pragma fragment fragBase
            #include "UnityStandardCoreForward.cginc"

            ENDCG
        }
            // ------------------------------------------------------------------
            //  Additive forward pass (one light per pass)
            Pass
            {
                Name "FORWARD_DELTA"
                Tags { "LightMode" = "ForwardAdd" }
                Blend[_SrcBlend] One
                Fog { Color(0,0,0,0) } // in additive pass fog should be black
                ZWrite Off
                ZTest LEqual

                CGPROGRAM
                #pragma target es3.0

                #pragma shader_feature _NORMALMAP
                #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
                #pragma shader_feature _METALLICGLOSSMAP
                #pragma shader_feature ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
            #pragma skip_variants SHADOWS_SOFT

            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog

            #pragma vertex vertAdd
            #pragma fragment fragAdd
            #include "UnityStandardCoreForward.cginc"

            ENDCG
        }
            // ------------------------------------------------------------------
            //  Shadow rendering pass
            Pass {
                Name "ShadowCaster"
                Tags { "LightMode" = "ShadowCaster" }

                ZWrite On ZTest LEqual

                CGPROGRAM
                #pragma target es3.0

                #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
                #pragma skip_variants SHADOWS_SOFT
                #pragma multi_compile_shadowcaster

                #pragma vertex vertShadowCaster
                #pragma fragment fragShadowCaster

                #include "UnityStandardShadow.cginc"

                ENDCG
            }

            // ------------------------------------------------------------------
            // Extracts information for lightmapping, GI (emission, albedo, ...)
            // This pass it not used during regular rendering.
            Pass
            {
                Name "META"
                Tags { "LightMode" = "Meta" }

                Cull Off

                CGPROGRAM
                #pragma vertex vert_meta
                #pragma fragment frag_meta

                #pragma shader_feature _EMISSION
                #pragma shader_feature _METALLICGLOSSMAP
                #pragma shader_feature ___ _DETAIL_MULX2

                #include "UnityStandardMeta.cginc"
                ENDCG
            }
        }


            FallBack "VertexLit"
            CustomEditor "StandardShaderGUI"
}

I basicly set the shader level target (#pragma target es3.0), this modified shader didn’t work either, now I’m guessing this feature of setting a normal map’s intensity is not working yet on mobile, maybe it is under development? Can anyone confim this please? I’m using the last stable version of Unity (5.3.4f1).

1 Like

An important requirement for bump scale beyond shader model 3.0 is DXTC support.

The bit of code that’s important is in UnityStandardUtils.cginc, specifically the UnpackScaleNormal function, and how normal maps are stored on mobile vs other platforms.

For desktop and consoles textures are compressed using DXTC (DirectX Texture Compression), specifically DXT1 or DXT5, and normal maps are stored as what’s referred to as DXT5nm, which is just a normal DXT5 texture with the normal map’s red channel stored in the alpha and the blue channel removed. The blue, or z value, is reconstructed from the red and green and this step makes scaling the normals fairly easy to add.

For mobile it’s assumed DXTC isn’t supported, and for most platforms this is true, so instead normal maps are stored as is. Since it doesn’t reconstruct the z supporting scaling would add a bunch of additional math that isn’t otherwise needed.

Now that function in question looks like this:

half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
{
    #if defined(UNITY_NO_DXT5nm)
        return packednormal.xyz * 2 - 1;
    #else
        half3 normal;
        normal.xy = (packednormal.wy * 2 - 1);
        #if (SHADER_TARGET >= 30)
            // SM2.0: instruction count limitation
            // SM2.0: normal scaler is not supported
            normal.xy *= bumpScale;
        #endif
        normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
        return normal;
    #endif
}

There is indeed a test for if the shader target is 3.0 or higher (SHADER_TARGET >= 30), and #pragma target es3.0 actually sets SHADER_TARGET to 35 so would pass that test … but it never gets to that code because the platform you’re running on (The Galaxy S6 w/ a Mali GPU) doesn’t support DXTC so instead the function just returns texture’s values “straight” and skips the bump scale.

If you wanted to implement this on your own using a custom standard surface shader it wouldn’t be too hard, but modifying the Standard.shader itself is going to be a bit more than just setting a #pragma someplace. You might be able to get away with putting a modified UnityStandardUtils.cginc in the same folder as your Standard2.shader and modifying the UnpackScaleNormal function there.

half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
{
    #if defined(UNITY_NO_DXT5nm)
        half3 normal = packednormal.xyz * 2 - 1;
        #if (SHADER_TARGET >= 30)
            normal.xy *= bumpScale;
            normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
        #endif
        return normal;
    #else
        half3 normal;
        normal.xy = (packednormal.wy * 2 - 1);
        #if (SHADER_TARGET >= 30)
            // SM2.0: instruction count limitation
            // SM2.0: normal scaler is not supported
            normal.xy *= bumpScale;
        #endif
        normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
        return normal;
    #endif
}
4 Likes

Hi @bgolus that did the trick! I really appreciate your help and the additional information, I’m a begginer in shaders programming and find this very useful, thank you so much.:slight_smile: