Optimizing shaders for iOS

How do you optimize a shader to run smoothly on iOS?

I’m using a planet shader right now and it seems to just suck all the performance out of my game. When i use Unity’s mobile shaders, the game’s framerate runs at a smooth 52-60 fps.
But the mobile shaders suck and its not the effect i want.

So, is there any way to change the components in a shader script to run nice on iOS.
Maybe changing the float values to fixed or simplifying the math function?
I don’t really care that much about a degrade in quality, I just want to achieve a similar effect without sacrificing any processing power.

This is the code for the shader i’m using:

Shader "Planet" {
    Properties {
      _MainTex ("Diffuse(RGB) Spec(A)", 2D) = "white" {}
      _BumpMap ("Bumpmap", 2D) = "bump" {}
      _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
      _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
      _SpecColor ("Specular Color", Color) = (0.5,0.5,0.5,1)
   _Shininess ("Shininess", Range (0.01, 1)) = 0.078125 
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      
       #pragma surface surf SimpleSpecular
   float _Shininess;
   
      half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
          half3 h = normalize (lightDir + viewDir);
          half diff = max (0, dot (s.Normal, lightDir));
          float nh = max (0, dot (s.Normal, h));
          float spec = pow (nh, 48.0);
          half4 c;
          c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec * s.Alpha * _Shininess * _SpecColor) * (atten * 2);
          c.a = s.Alpha;
          return c;
      }
            
      struct Input {
          float2 uv_MainTex;
          float2 uv_BumpMap;
          float3 viewDir;
      };
      sampler2D _MainTex;
      sampler2D _BumpMap;
      float4 _RimColor;
      float _RimPower;
      
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
          o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
          half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
          o.Emission = _RimColor.rgb * pow (rim, _RimPower);
          o.Alpha = tex2D (_MainTex, IN.uv_MainTex).a;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

The Images are examples the planet shader compared to the mobile shader(not very attractive).

Posted this thread in iOS Dev but got no answer.
Help’s EXTREMELY appreciated.




Hmm… Can’t really say how to help on the shader bit, but maybe if you were to use MIPS on your textures or maybe compress them it might increase the frame rate.

A lot of iOS games don’t have bump maps, (or if they do, I’m not seeing it :P) so you don’t really need to worry about keeping bumps, if you have any.

You might want to reduce the amount of polys of your sphere, maybe import a planet with fewer tris from another application.

Or else improve your lighting on the scene to “fake” the planet surface reflecting, as the iOS shader appears to not include reflection.

And if all else fails, reduce the default Quality of the game by going to Edit → Project Settings → Quality. Decreasing quality automatically creates MIPS and lowers quality of bumps, reflections, etc.

Hope this helps!

EDIT: Oh and these are just the “old-fashined” ways of doing it!

Yeah, thanks for the quick reply.

I’ve already optimized all the settings in “Edit” and my polys are pretty low: Tris-15k, Verts-8.8k. Plus there are only 15 draw calls.

Took out all bumps and reflections too and i got a 0.2 frame boost, ha.

It must be the shader itself but I know nothing on shaders.

I think I have to re-write it in Open GL instead of surface shader.

Any help?

Please don’t cross-post, its hard to help in two locations.

surface shaders are fine.
But what you would need to do is stop using alpha, that costs a lot of performance due to the overdraw and from what I see you don’t even need it as you assume it to be opaque going by the renderqueue

Thanks.
After removing the alpha components I get about a 1-2 framerate boost but that’s from 15 fps to 17 fps, still pretty laggy.
If I get it any higher I’ll post it along with the new code(aiming for at least 30+ fps out of the 60 available).

Can you say more on how the lights are setup (ie ensure to focus on a single directional not point lights as you are using pixel lights which are fillrate bound)

also, could you post your current shader to see if there are things left to do, to see if the “simple lighting” could be further simplified etc

Yeah that’s what I was getting at, as from my experience in CG rendering, it looks like you might have to use the iOS shader but fake the reflection by adding what’s called a “Fill Light” to get rid of those nasty shadows.

the shadows are easy that are mesh normal based ones (Unity mobile has no realtime shadows at all).

But pixel lights are very fillrate intense and there is also the computational effort of point lights vs directional light

I’m using a point light to simulate a glow coming out from the wormhole. Cant really afford to use a directional light because that would kill the effect and make it look unrealistic.

I’ve striped the shader of everything but the essentials to get the same effect.
This is my new code:

Shader "Planet" {
    Properties {
      _MainTex ("Base (RGB)", 2D) = "white" {}
      _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
      _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      
       #pragma surface surf Lambert
            
      struct Input {
          float2 uv_MainTex;
          float3 viewDir;
      };
      sampler2D _MainTex;
      float4 _RimColor;
      float _RimPower;
      
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex);
          half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
          o.Emission = _RimColor * pow (rim, _RimPower);
      }
      ENDCG
    } 
  }

This new code gave me about a 10 framerate boost but the final result is only 26 fps. Huge improvement but the game is still choppy.
I’m pretty sure I’m using a forward rendering path for max performance but I’m still pretty dull on shaders.

reduce the point light range seriously and let it work with a cookie only and see if that changes the performance … if so you know you are fillrate limited.

Yeah and you aren’t restricted to directional lamps, there’s the points and you could always add a flare or cookie to increase the quality or realism. But if you have a low Quality setting, cookies don’t work.

Fixed it. it wasn’t the lights, changing them only boosted the framerate by about .3. I reduced my tris and verts to 5.5k and 3.7k and now its running at 32 fps.

Thanks for the help

are you running on an iphone3g / iPod touch 2nd gen? doubt it otherwise the whole cgprogram stuff wouldn’t make any sense as its ignored anyway … but thats the only devices where reduction of tris to this level would make a difference that large