Normal Mapping Precision on iOS

Posts: 86
Joined: 2008.04
Post: #1
I was using ZBrush alot lately, and want to get normal mapping working on ios.

I have implemented a normal mapping glsl shader that works, but I see subtle "banding" on the lit parts of the model.

The shader works great when I run it on the mac with no banding - it's only on ios that I see the effect.

I am thinking it might be a problem with the precision of the texture sampler on ios.

Is this a known issue - should I look into encoding the normals in a more effecient fashion...

I am using the stock tangent space normal map coming out of zbrush, which I think encodes nx,ny,nz in r,g,b and ignores a.

Thanks for any advice...
Quote this message in a reply
Posts: 5,143
Joined: 2002.04
Post: #2
GLSL ES has the concept of "precision" within the shader. This allows you to potentially sacrifice precision in your results to run faster.

Long story short, the default precision for the fragment shader is "mediump"; did you change it?
Quote this message in a reply
Posts: 86
Joined: 2008.04
Post: #3
Yes - I have tried using highp for everything...
still same banding is present.

It is like the actual sampler is returning lower precision normals.
on mac:
[Image: normalmappingmac.png]
on ios:
[Image: normalmappingios.png]

Thanks again for any advice....
Quote this message in a reply
Posts: 5,143
Joined: 2002.04
Post: #4
Samplers also have associated precision, did you set the precision on the sampler? Additionally, the default precision for samplers is "lowp".

Maybe you should post your shader code.
Quote this message in a reply
Posts: 1,234
Joined: 2002.10
Post: #5
What texture format are you using?
Quote this message in a reply
Posts: 86
Joined: 2008.04
Post: #6
I tried it with the samplers explicitly set to highp - same issue...

I tried limiting the fragcolor to just a solid color modulated by nDotL...
and I still see the seems to be an artifact of how I am calculating nDotL.

Here are the shaders (sorry I haven't taken time to clean them up)

Vertex Shader
attribute vec4 position;
attribute vec3 normal;
attribute vec3 binormal;
attribute vec3 tangent;
attribute vec2 texcoord0;
attribute vec4 color;

varying vec4 colorVarying;
varying vec2 texOut0;
varying vec3 v_viewDirection;
varying vec3 v_lightDirection;
varying vec3 v_normal;

uniform float translate;
uniform mat4 u_mvp_matrix;
uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat4 ModelviewInverse;
uniform mat3 NormalMatrix;
uniform vec3 LightPosition;
uniform vec3 EyePosition;

void main()
    vec3 vRed = vec3(1,0,0);
    gl_Position = Projection * Modelview * position;
    texOut0 = texcoord0;

    vec3 worldPosition = (Modelview * position).xyz;    
    vec3 normalWorld = normalize((NormalMatrix * normal).xyz);
    vec3 eyePositionWorld = (    ModelviewInverse *    vec4(EyePosition,1.0)).xyz;
    vec3 viewDirectionWorld = eyePositionWorld -;
    vec3 lightPositionWorld = (    ModelviewInverse *    vec4(LightPosition,1.0)).xyz;
    vec3 lightDirectionWorld = lightPositionWorld -;                
    mat3 tangentMat = mat3(tangent,binormal,;
    v_viewDirection = viewDirectionWorld * tangentMat;
    v_lightDirection = lightDirectionWorld * tangentMat;


Fragment Shader
precision highp float;
varying lowp vec4 colorVarying;
varying lowp vec2 texOut0;
varying mediump vec3 v_normal;

uniform sampler2D textureMap;
uniform sampler2D normalMap;
varying mediump vec3 v_viewDirection;
varying mediump vec3 v_lightDirection;

void main()
    highp vec3 baseColor = texture2D( textureMap,;
    //lowp vec4 baseColor = vec4(1,1,1,1);
    highp vec3 nl = texture2D( normalMap,;    
    highp vec3 normal = normalize(nl.yxz * 2.0 -1.0);
    highp vec3 lightDirection = normalize(v_lightDirection);
    highp vec3 viewDirection = normalize(v_viewDirection);
    highp float nDotL = dot(normal, lightDirection);
    highp vec3 reflection = (2.0 * normal * nDotL) - lightDirection;
    highp float rDotV = max( 0.0,dot(reflection, viewDirection));
//    mediump vec4 ambient = vec4(0.1,0.1,0.1,1.0) * baseColor;
//    mediump vec4 diffuse = vec4(0.8,0.8,0.8,1.0) * nDotL * baseColor;
//    mediump vec4 specular = vec4(1,1,1,1) * pow(rDotV, 100.0);    
    //gl_FragColor= ambient + diffuse + specular;
    highp vec3 ambient = vec3(0.1,0.1,0.1) * baseColor;
    highp vec3 diffuse = vec3(1.0,1.0,1.0) * nDotL * baseColor;
    highp vec3 specular = vec3(1,1,1) * pow(rDotV, 100.0);
    gl_FragColor= vec4(ambient + diffuse + specular,1);
    //gl_FragColor= diffuse;
    //gl_FragColor = vec4(nl,1);


Thanks again for any advice....
Quote this message in a reply
Posts: 86
Joined: 2008.04
Post: #7
arekkusu - You are Open GL master!

I was using a Texture loader that was incorrectly picking RGB565!

Once I used rgba8888 all was perfect!

Thank you - I have been struggling with this all day :-)

And thank you too OSC !

Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Getting the Normal for a polygon. Jaden 3 8,203 May 1, 2009 01:47 PM
Last Post: Nosredna
  Poor precision in depth texture TomorrowPlusX 59 61,492 Jul 3, 2007 12:23 AM
Last Post: Ciaran
  Vector (Normal) Map blending operations? kelvin 10 11,247 Mar 16, 2007 04:31 PM
Last Post: OneSadCookie
  drawing or displaying vertex normal shru_ani 3 5,765 Oct 29, 2006 06:04 AM
Last Post: shru_ani
  Gouraud vs Normal maps for dinamic terrains sohta 6 7,332 Oct 11, 2006 12:55 AM
Last Post: sohta