How to create an atmospheric glow effect on surface of globe/sphere

Hey folks,

I am trying to recreate something similar to the Github Globe. I’m wondering what the best approach would be to replicate this atmospheric glow effect:


I have created a simple example with the sphere https://codepen.io/ian-whitestone/pen/gOGLprx if it’s easier to demonstrate with a working example.

Any help / pointers would be greatly appreciated!

I’d try having two spheres, one for the Earth and the other for the atmosphere.
Then you need to write a custom fragment shader.
Calculate the dot product of the normal and vector that goes from the camera to the current point. The dot product is equal to 0 when the vectors are orthogonal ( perpendicular), so the closer it gets to 0 the closer your point is to the edge of the sphere.
Then you use that to determine the colour of the point.

Check the Google webgl globe out, it uses that technique: webgl-globe/globe.js at 8d746a3dbf95e57ec3c6c2c6effe920c95135253 · dataarts/webgl-globe · GitHub
(Looking at the code I made a mistake, you calculate the dot product between the normal and a vector (0,0,1)

1 Like

Thanks @Arthur, really appreciate the response. I was able to copy over that example into a new codepen. This is close to producing the effect I want but the custom shader does not reflect light as I would expect. The atmospheric glow is currently uniform around the sphere. It does not change based on the directional light source coming from the top left.

Ideally it would look more like the example below, where the glow is stronger on the left due to the light source and practically non-existent on the lower right where there is no light.

Any idea how to add that effect in?

All lights in the scene can be passed in as uniforms if you enable the lights on your shader material. Then you can get the lights’ position, etc. I would recommend diving into how the shader is implemented for the physical material to learn how to use these.

I modified your shader a bit to illustrate how the light’s position can be taken into account. Here I just hardcoded the position of the light (which might be good enough)

The variable dotNL is a value between 0 and 1 where 1 means that the varying normal of the fragment is directly facing the light source. By multiplying this with the intensity, it will only glow where the normals are facing the light.

var vertexShader = [
  'varying vec3 vNormal;',
  'varying vec3 vPosition;',
  'void main() {',
  'vNormal = normalize( normalMatrix * normal );',

  'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
  'vPosition = gl_Position.xyz;',
  '}'
].join('\n')

var fragmentShader = [
  'varying vec3 vNormal;',
  'varying vec3 vPosition;',

  'void main() {',
  'vec3 lightPosition = vec3(-10.0, 10.0, 0.0);',
  'vec3 lightDirection = normalize(lightPosition - vPosition);',
  'float dotNL = clamp(dot(lightDirection, vNormal), 0.0, 1.0);',
  'float intensity = pow( 0.8 - dot( vNormal, vec3( 0, 0, 1.0 ) ), 12.0 );',
  'gl_FragColor = vec4( 1, 1.0, 1.0, 1.0 ) * intensity * dotNL;',
  '}'
].join('\n')

1 Like