I’ve had a couple of threads going on the forums and on Answerhub for a few months now which in-detail describes a lot of the problems I’ve been having with materials on the Android mobile platform. In short, materials drawn on the device look nothing like they actually should. Some band and block up and some nodes don’t seem to work at all.
I have finally traced the cause of the problem down the the use of extremely low-precision floats in mobile shaders. In my case, this makes some very simple materials absolutely impossible to achieve on mobile, and this also affects some of the default engine materials. The Default Skydome for instance renders a sun-disc as part of the Shader. If you deploy to a mobile device, you’ll notice the sun disc is no longer there. This is because the ‘radius’ value of the sun disc is so small (0.0003f) that the device just sets it to ‘zero’, and therefore it never draws! Heres the simple material setup I was using to test this (on a skydome mesh).
Long story short, the engine is doing all those extra instructions for no result. If you make the sun radius large enough, it will start to draw (though it will band due to precision issues). If you make it even larger, it’ll start to draw smoothly. I haven’t found any documentation on this nor advice on how to avoid it, but most importantly how to switch this off if possible. Certain shaders or materials in my game need the full precision of floating point in order to draw correctly. It seems as though the range of floats on Android devices is heavily quantized (possibly at the hardware level?), which causes huge problems with many nodes.
This issue can be easily tested in the default engine. Create a new project with the default map and deploy to the device. You’ll notice that there is NO sun-disc on the skydome regardless of what you deploy to. If you then change the material and make the sun-disc size something larger (say 0.01), and deploy to device, the sun disc will render (but of course, will be enormous).
At the opposite end of the spectrum, values that are too large also seem to get quantized and get “a bit screwy” too. In this case I’m creating a soft-edge atmosphere effect using an inverted sphere. I’m generating the ‘Normals’ for the soft-edge using the world-position of the pixels and normalizing it (essentially giving me pixel-perfect spherical normals for a smooth surface). Unfortunately when deployed to a device, the atmosphere becomes solid.
This is for a low-poly sphere with a 6,800 unit radius. If I swap the world-position method and use vertex/pixel normals, everything draws fine but there are a lot of banding artifacts due to the low-precision of the surface normals, and my only option is to massively increase the polycount to avoid it.
So in short, what I need is a way to be able to force full-precision math on some materials for my game, or otherwise face a lot of horrifically ugly artefacts. If I have to make an engine change for this that’s fine, but I really need it!