Help implementing spherical atmospheric shader

Hi, I got this old atmospheric shader by martinish working in UPBGE 0.2.5, but it only works at world origin. If you move the planet away from origin, it glitches out. Any help would be appreciated!

here’s a .blend
https://drive.google.com/file/d/1Hy5iJWLWgBUgoiYOZPAnp5hCKLk5HD2S/view?usp=sharing

I don’t have too much experience with GLSL, but I guess some value in the shader has to be displaced by the planet’s world position?

The position of the camera has to be relative to the planet. The camera distance will be the length of the camera position vector:

objpos = obj.worldPosition
camerapos = camera.worldPosition - objpos
lightpos = lamp.worldPosition

m_fOuterRadius = 10.25
m_fInnerRadius = 10.00

cameraDistance = camerapos.length

#xOffset = objpos[0] - camerapos[0]
#yOffset =  objpos[1] - camerapos[1]
#zOffset = objpos[2] - camerapos[2]
#dSquared = xOffset**2 + yOffset**2 + zOffset**2
#cameraDistance = math.sqrt(dSquared)
#cameraDistanceSq = dSquared

Now you need to consider how do you want the sunlight to work. Currently, the shader uses the lamp’s world position as light vector. If you want the light direction to change when you move the planet, you need to make the light position relative to the planet too:

lightpos = lightpos - objpos
lightDistance = lightpos.length

#xOffset1 = objpos[0] - lightpos[0]
#yOffset1 = objpos[1] - lightpos[1]
#zOffset1 = objpos[2] - lightpos[2]
#dSquared1 = xOffset1**2 + yOffset1**2 + zOffset1**2
#lightDistance = math.sqrt(dSquared1)

Or, if you want to use the lamp’s orientation as light vector:

lightpos = lamp.getAxisVect([0.0, 0.0, 1.0])
lightDistance = 1.0 # lightpos is already a normalized vector

#xOffset1 = objpos[0] - lightpos[0]
#yOffset1 = objpos[1] - lightpos[1]
#zOffset1 = objpos[2] - lightpos[2]
#dSquared1 = xOffset1**2 + yOffset1**2 + zOffset1**2
#lightDistance = math.sqrt(dSquared1)
1 Like

Thank you so much! It works perfectly. I was trying to mess around inside the glsl, but it seems that wasn’t needed at all :smiley:

Could I also ask how to get the shader to still work even if you rescale the planet? Because right now it’s too small to use… I tried multiplying some things by the scale factor but it didn’t seem to work.

The shader works with local coordinates, that’s why you need to subtract the planet’s position to the camera and light. To make the camera position relative when the planet is scaled, you must divide the position by the scale. Also, if you are going to rotate the planet, you will have to multiply the positions of the camera and the light by the world orientation matrix of the planet.

radius = obj.worldScale
objpos = obj.worldPosition
camerapos = camera.worldPosition - objpos
lightpos = lamp.worldPosition - objpos

m_fOuterRadius = 10.25
m_fInnerRadius = 10.00

camerapos = camerapos / radius[0] * obj.worldOrientation
cameraDistance = camerapos.length

lightpos.normalize()
lightpos = lightpos * obj.worldOrientation # no need to divide by radius[0] as it is a normalized vector
lightDistance = 1.0

The lightDistance it is not really necessary anymore, the light position is already normalized; you can change the line that updates the uniform with:

shader.setUniform3f('v3LightPos', *lightpos)
1 Like

Thanks for all the help! :smile:
One more question - the shader works perfectly now, but the ground doesn’t seem to receive any shadows from any objects in the scene (for example, a ship landing on the planet doesn’t cast any shadow so it’s hard to tell how close you are to the ground). Is there a fix for that?