Announcement

Collapse
No announcement yet.

Use of Low-Precision floats in Mobile Shaders breaks materials! (Affects Default Engine Materials)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [RENDERING] Use of Low-Precision floats in Mobile Shaders breaks materials! (Affects Default Engine Materials)

    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).

    Click image for larger version

Name:	simplesun.JPG
Views:	1
Size:	128.3 KB
ID:	1170489

    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.

    Click image for larger version

Name:	atmo.JPG
Views:	1
Size:	128.8 KB
ID:	1170486

    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.

    Click image for larger version

Name:	Vertex.JPG
Views:	1
Size:	75.3 KB
ID:	1170487
    Click image for larger version

Name:	Banding.JPG
Views:	1
Size:	133.4 KB
ID:	1170488

    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!
    Last edited by TheJamsh; 01-18-2016, 11:36 AM.

    #2
    I use the Custom node to write my own full precision HLSL code. Also, if you are normalizing large values, you should fist shrink the number ( like multiply by 1/1024 ) so that you don't lose all the precision during the normalize process.

    Comment


      #3
      Hey TheJamsh,

      I've entered a feature request for the ability to force full-precision math on materials. You can track this request here: https://issues.unrealengine.com/issue/UE-34055

      Have a great day!

      Comment


        #4
        Noice. Thankyou!

        Comment


          #5
          Sean L The issue URL no longer exists. Was that ever implemented?

          I came here because of a spherical projection problem that was solved by elecorn suggestion of dividing vectors before normalizing (thanks for that!!). But if we had a setting to enable precision in mobile shaders it would solve a lot of other issues, like the ones demonstrated by TheJamsh.
          Freelancer Game Dev Generalist and Unreal Consultant | Portfolio
          Unreal products: Dynamic Picture Frames, Neo Kinect

          Comment


            #6
            This has since been fixed I believe, in that there is now an option to force a shader to use high precision on mobile. I believe it's in the Mobile settings of the material itself, but if not it might be a global project-wide setting. I'd expect there to be some performance regressions though!

            NB: I got around this issue at the time by just adding a flat quad with a circle mask. Not the most elegant solution but it did the job!

            Comment


              #7
              It's in the material settings. Next time I'll read those one by one. lol
              Thanks a lot for the heads up, TheJamsh!
              Originally posted by TheJamsh View Post
              I got around this issue at the time by just adding a flat quad with a circle mask. Not the most elegant solution but it did the job!
              Fortunately I got around mine without activating full precision too. It's interesting the math/computing hacks people come up with!
              Attached Files
              Freelancer Game Dev Generalist and Unreal Consultant | Portfolio
              Unreal products: Dynamic Picture Frames, Neo Kinect

              Comment


                #8
                Keep in mind that everything that is calculated at vertex shader uses high precision by default. So most of the time you can get away without forcing full precision by calculating most of the stuff at vertex shader. Also with carefully trying to stay in half float range you can get away even in pixel shader. In your example normalize is the prolem. Absolute world position using centimeters so values are usually quite big. Max half float is 65504. Normalize is doing division by lenght of vector. So its xyz / x^2 + y^2 + z^2. So if sqrt of x,y or z is over sqrt(65504) ~= 256 which is just 2.56meters you get overflow. Just by premultiplying vector before normalization can get you in proper range and everything is fine again.

                Comment


                  #9
                  Originally posted by Kalle_H View Post
                  Keep in mind that everything that is calculated at vertex shader uses high precision by default. So most of the time you can get away without forcing full precision by calculating most of the stuff at vertex shader. Also with carefully trying to stay in half float range you can get away even in pixel shader. In your example normalize is the prolem. Absolute world position using centimeters so values are usually quite big. Max half float is 65504. Normalize is doing division by lenght of vector. So its xyz / x^2 + y^2 + z^2. So if sqrt of x,y or z is over sqrt(65504) ~= 256 which is just 2.56meters you get overflow. Just by premultiplying vector before normalization can get you in proper range and everything is fine again.
                  Awesome explanation, Kalle_H. Thanks a lot! I'll keep that vertex full precision info in mind. I already do a lot of stuff in vertex to save on processing power, even Fresnel.
                  I suppose you are exactly right about the problematic distance. In the projected objects that seemed to be the start distance of the projection problems.
                  Freelancer Game Dev Generalist and Unreal Consultant | Portfolio
                  Unreal products: Dynamic Picture Frames, Neo Kinect

                  Comment

                  Working...
                  X