twinkle twinkle little shader

September 26, 2019 Bram 0 Comments

In preparation for Ludum Dare 45 I put aside a little time this week to practice some Godot and a new area I have been building my skills in – shaders. What follows is a description of how I made a twinkling starry sky effect for an asteroids clone.

In order to start I required a base texture I created in photoshop. In future I would rather have this dynamically created with some simplex noise but for the moment a texture will do the trick. In photoshop I created a black background and added perlin noise over the top. I averaged it out with a gaussian blur and then altered the light levels so only the brightest points would be visible specks of white that fade out surrounded by the void of space.

starry sky

With this png imported into Godot and attached to a sprite we can attach a material with a shader to do the heavy duty twinkling business. My first thought was to create another starry sky texture to move around behind this one and when the stars overlap make the first textures stars brighter. This had one major problem in that as the texture didn’t tile; the edges would corrupt and create lines or blocks of colour rather than stars when moved around. However the principle behind this did work for highlighting. It only took a short while to realise I can pass in Simplex noise as a parameter to the shader instead of the second starry sky and it would tile.

Moving this noise in a constant motion however created visible patterns in which stars light up. So instead of moving in a constant direction I move the noise in a circle slowly in the background, this involves a simple alter in position by sin on the x axis and cos on the y axis. This does mean the pattern will loop, however we move it slowly enough that it would take an incredible ammount of time to.

vec2 newUV = UV;
newUV.x += sin(TIME * 0.005);
newUV.y += cos(TIME * 0.005);
vec4 normal = texture(noise, newUV);
parameters for simplex texture
the noise moving around in the background

In order to make the accentuation effect work I came up with an acceptable solution. I sum a channel from both the noise and the starry foreground. If it exceeds a threshold, we set the shader to pure white. Additionally I set it up so the noise was all on with points that were off to make the sky brighter in general, it also pronounces how bright they are and creates an attractive shifting effect on closer inspection.

if(COLOR.r + normal.r >  0.8){
	COLOR = starColor * (1.0-(starSpeed+1.0)*starVariance*0.5);
}

Without any further fanfare here is the code and how it looks.

full size
middle zoom
up close
shader_type canvas_item;

uniform sampler2D noise;

void fragment(){
	vec4 starColor = vec4(1.0,1.0,1.0,1.0);
	float starSpeed = 5.0;
	float starVariance = 1.0;
	vec2 newUV = UV;
	newUV.x += sin(TIME*0.005);
	newUV.y += cos(TIME*0.005);
	vec4 normal = texture(noise, newUV);
	COLOR = texture(TEXTURE, UV);
	
	if(COLOR.r + normal.r >  0.8){
		COLOR = starColor * (1.0-(starSpeed+1.0)*starVariance*0.5);
	}
}

I hope this has been of interest and hope to continue posting developments as they occur with my forays deeper into shader language.

Leave a Reply:

Your email address will not be published. Required fields are marked *