Unexpected shader behaviour and workarounds

My team and I have been working on a mobile game that involves fairly heavy use of shaders for both gameplay and visuals. One aspect of this is an infrared style view that is being produced by jury-rigging a custom forward-shading ‘lighting’ model into the materials. We’re passing in the position and temperature of the four nearest thermal emitters (a custom BP) into the shaders and working on them in there.

We had a lot of problems, because the shaders, once deployed on device, behaved completely differently to the mobile preview. Eventually I was able to work out just why this was happening. There were a few reasons.

  1. The Global World Position input is wrong. On our testing devices (Galaxy S4 and Nexus 7, both Adreno 320) visualizing the value of Global World Position. Our shader was doing everything in global coordinates, but these didn’t have any meaningful value once on device. Solution: Use Camera Relative World Position and the Camera Position to reconstruct the value.

  2. Division is extremely finicky. To produce a reasonable size falloff I was dividing by 100,000 at one point. Doing this seems to result in the number being zeroed on both devices (not reflected in mobile preview). The solution was truly mind-boggling:


Instead of dividing by 100,000 in one operation, I replaced it with three divisions by 100, 100 and 10. The result on desktop and preview is identical, as you’d expect. On mobile the results can be seen below (Top: Single division; Bottom: piece wise division)


I found a similar issue when I was trying to invert the output (1/x), it simply got zeroed. So I approximated it by clamping to 0-1 and doing 1-x.

I was unable to find any documentation suggesting this behavior could be expected or had been found before so I figured I’d post this in case anyone else encounters the same issues.