ok. while moka’s example looks awesome, i discovered with my work that if you rotate the sphere then the lighting doesn’t work any more. this is because the normal calculation is only valid for a plane, where the original normals are all pointing in the same direction (0,0,1). and instead it’s being wrapped onto a sphere where all the normals point out from the centre of the sphere to the point of the vertex on the sphere’s surface.

to fix this, if you rotate your new calculated normal by the different between the previous normal (this is the direction from the centre of the sphere to the un-displaced position on the sphere) and the object z-axis (0,0,1) then you get the correct results for the whole sphere. there is still a simplification but it is now assuming that the only the local 3x3 neighbourhood of vertices is planar rather than the whole sphere.

i’m simply calculating the axis and angle of rotation and converting it to a rotation matrix.

```
// compute new normal from displaced vector neighbourhood
// rotate calculated normal by gl_Normal i.e. rotation from (0,0,1) to gl_Normal
// axis = norm(gl_Normal x (0,0,1))
// angle = acos(gl_Normal . (0,0,1))
vec3 dispNorm;
vec3 axis = normalize(cross(gl_Normal,vec3(0.,0.,1.)));
float c = dot(gl_Normal,vec3(0.,0.,1.));
if(c>0.99999) {
dispNorm = nm;
} else if (c < -0.99999) {
dispNorm = -nm;
} else {
float s = sin(acos(c));
float t = 1. - c;
mat3 transform = mat3(t*axis.x*axis.x + c, t*axis.x*axis.y - s*axis.z, t*axis.x*axis.z + s*axis.y,
t*axis.x*axis.y + s*axis.z, t*axis.y*axis.y + c, t*axis.y*axis.z - s*axis.x,
t*axis.x*axis.z - s*axis.y, t*axis.y*axis.z + s*axis.x, t*axis.z*axis.z + c);
dispNorm = transform * nm;
}
normal = normalize(gl_NormalMatrix * dispNorm);
```

replaces

```
norm = normalize(gl_NormalMatrix * ((gl_Normal+nm)/2.0));
```

obviously there’s a bit more calculation involved but it makes it work properly.