2D Spinning Sphere

A simple shader that makes a 2D canvas item look like a spinning sphere. Make sure to set the “Repeat” import flag for your texture!

In the first example (the animation below), I used a sprite with a 2D image supplied by Solar System Scope to create a spinning Earth.

In the second example, I used two more sprites, both with a 2D cloud texture also provided by Solar System Scope. One has the as_shadow shader param set to true, which creates dark, somewhat transparent shapes on the Earth. The non-shadow cloud sprite is scaled slightly larger than the other two sprites, so that the clouds float off the surface of the planet. As an aside, simply adding a radial gradient behind the planet to create an atmospheric glow can really sell the effect.

Note that the textures I used have an aspect ratio of 2:1. As such, the aspect_ratio shader param is set to 2.0. Additionally, I had to set the sprite scales to match the aspect ratio (e.g. scale = Vector2(0.5, 1.0)) to prevent an oval-like shape.

Shader code
shader_type canvas_item;

uniform float aspect_ratio = 2.0;
uniform float rotation_speed = 0.3;
uniform bool as_shadow = false;

const float PI = 3.141593;

void fragment() {
	float px = 2.0 * (UV.x - 0.5);
	float py = 2.0 * (UV.y - 0.5);
	
	if (px * px + py * py > 1.0) {
		// Outside of "sphere"
		COLOR.a = 0.0;
	} else {
		px = asin(px / sqrt(1.0 - py * py)) * 2.0 / PI;
		py = asin(py) * 2.0 / PI;
		
		COLOR = texture(TEXTURE, vec2(
			0.5 * (px + 1.0) / aspect_ratio - TIME * rotation_speed,
			0.5 * (py + 1.0)));
		if (as_shadow) {
			COLOR.rgb = vec3(0.0, 0.0, 0.0);
			COLOR.a *= 0.9;
		}
	}
}
Tags
orb, planet
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.
guest

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
ferdebb
ferdebb
6 months ago

Thank you for this!

I’m new to Godot and even newer to shaders so sorry if this is a stupid question. How can I make the planet rotate when I want it to? As rotating left when pressing left, right when pressing right and stop when not pressing anything.

I’ve managed to do it changing the rotation_speed variable but the texture “jumps” when changing direction, so I guess I should change something else but, as I said, I’m fairly new to this.

Thanks again!

ferdebb
ferdebb
6 months ago
Reply to  ferdebb

Found the answer!

On line 21

0.5 * (px + 1.0) / aspect_ratio - TIME * rotation_speed,

that 1.0 is the “planet position” and changing it you rotate the planet left or right. So I created a variable for it and now can move the planet when I want.

On the shader:

uniform float planet_position = 0.0;
...
...
      COLOR = texture(TEXTURE, vec2(
         0.5 * (px + planet_position) / aspect_ratio - TIME * rotation_speed,

And then in the GDScript whatever method you want to apply the movement and (I know this is not the best coding, it was just a fast test):

var planet_move = 0.0

...

func _process(delta: float) -> void: 
   if Input.is_action_pressed("left"):
      planet_move += 0.1
      self.material.set_shader_param("planet_position", planet_move)
elgodox
elgodox
6 months ago

Hi!, I am trying to make it move vertically too, but the UV is distorted, like the image is distorted at the top and bottom of the sphere. Any suggestion how to do it?

poklop
poklop
5 months ago

very epik shader <3