Unity Normal Maps not working on Android device

I am a seasoned iOS developer building my first Android output via Unity. I'm trying to tweak a custom shader but I'm having problems with Normal maps. I work them perfectly in the Unity simulator on my computer, but when I create a real device (Samsung Galaxy S8 +) the Normal maps don't work at all.

I am using Mars as a test. Here's the model running in a simulator on my computer:

Computer version

And here's a screenshot from my device running exactly the same code.

Android device version

I've done a lot of research and it seems that using regular maps on Android with Unity is not so easy. There are many people who ask this, but almost every answer I found said the trick is to override the texture import options and make it be "Truecolor" which seems to be "RGBA 32 Bit" according to Unity Documentation ... However, that didn't work for me.

Another thread suggested reducing the Asino level to zero, while another suggested turning off Mip Maps. I don't know what it is, but it didn't help.

Texture import options

Here's my shader code, simplified but containing all references to normal display:

void surf (Input IN, inout SurfaceOutputStandard o) {
        half4 d = tex2D (_MainTex , IN.uv_MainTex);
        half4 n = tex2D (_BumpMap , IN.uv_BumpMap);

        o.Albedo = d.rgb;
        o.Normal = UnpackNormal(n);
        o.Metallic = 0.0;
        o.Smoothness = 0.0;
    }

      

I've seen several threads suggesting replacements for the "UnpackNormal ()" function in the shader code, which indicates that it can't be the case on Android or mobile at all, but none of the suggested replacements changed anything for better or worse: normal maps continue to work in the simulator, but not on the device.

I even tried to make my own normal maps programmatically from a grayscale heightmap to try and bypass any import options I might have done wrong. Here is the code I used and again it works in the simulator but not on the device.

public Texture2D NormalMap(Texture2D source, float strength = 10.0f) {
    Texture2D normalTexture;
    float xLeft;
    float xRight;
    float yUp;
    float yDown;
    float yDelta;
    float xDelta;

    normalTexture = new Texture2D (source.width, source.height, TextureFormat.RGBA32, false, true);

    for (int y=0; y<source.height; y++) {
        for (int x=0; x<source.width; x++) {
            xLeft = source.GetPixel (x - 1, y).grayscale * strength;
            xRight = source.GetPixel (x + 1, y).grayscale * strength;
            yUp = source.GetPixel (x, y - 1).grayscale * strength;
            yDown = source.GetPixel (x, y + 1).grayscale * strength;
            xDelta = ((xLeft - xRight) + 1) * 0.5f;
            yDelta = ((yUp - yDown) + 1) * 0.5f;
            normalTexture.SetPixel(x,y,new Color(xDelta,yDelta,1.0f,yDelta));
        }
    }
    normalTexture.Apply();

    return normalTexture;
}

      

Finally, in build settings, I have Android platform installed and tried it with texture compression set to both "Do not reinstall" and "ETC (default)". The first was the original setting, and the last seemed to be the Oneness proposal both in name and in the documentation.

I'm sure there is only some flag that I didn't check, or some switch that I didn't flip, but I can't for life understand what I am doing wrong here, or why such a stubborn distinction between a simulator and device.

Can anyone help a Unity newbie and show me how these damn normal maps are supposed to work on Android?

+3


source to share


1 answer


Note:

Edit -> Project Settings -> Quality



Android is usually set to "Fastest".

+4


source







All Articles