2d Nebula Shader

I am still a beginner at shading, but I tried to put together something pretty.

Stars rendered using https://godotshaders.com/shader/stars-shader/ by https://godotshaders.com/author/gerardogc2378/

Using FBM on perlin noise to generate clouds, and parallax scrolling through in a circle.

Shader code
shader_type canvas_item;

//uniform vec3 color_replace = vec3(1.0,1.0,0.0);
uniform int OCTAVE = 12;
uniform float timescale = 5.0;
uniform vec4 CLOUD1_COL: hint_color = vec4(0.41,0.64,0.78,0.4);
uniform vec4 CLOUD2_COL: hint_color = vec4(0.99,0.79,0.46,0.2);
uniform vec4 CLOUD3_COL: hint_color = vec4(0.81,0.31,0.59,1.0);
uniform vec4 CLOUD4_COL: hint_color = vec4(0.27,0.15,0.33,1.0);
uniform vec4 SPACE: hint_color = vec4(0.09,0.06,0.28,0.3);
uniform float zoomScale = 6.0;
uniform float size = 10.0;
uniform float starscale = 20.0;
uniform float prob: hint_range(0.0,1.0) = 0.98;

float rand(vec2 input){
	return fract(sin(dot(input,vec2(23.53,44.0)))*42350.45);
}

float perlin(vec2 input){
	vec2 i = floor(input);
	vec2 j = fract(input);
	vec2 coord = smoothstep(0.,1.,j);
	
	float a = rand(i);
	float b = rand(i+vec2(1.0,0.0));
	float c = rand(i+vec2(0.0,1.0));
	float d = rand(i+vec2(1.0,1.0));

	return mix(mix(a,b,coord.x),mix(c,d,coord.x),coord.y);
}

float fbm(vec2 input){
	float value = 0.0;
	float scale = 0.5;
	
	for(int i = 0; i < OCTAVE; i++){
		value += perlin(input)*scale;
		input*=2.0;
		scale*=0.5;
	}
	return value;
}

float fbmCloud(vec2 input, float minimum){
	float value = 0.0;
	float scale = 0.5;
	
	for(int i = 0; i < OCTAVE; i++){
		value += perlin(input)*scale;
		input*=2.0;
		scale*=0.5;
	}
	return smoothstep(0.,1.,(smoothstep(minimum,1.,value)-minimum)/(1.0-minimum));
}

float fbmCloud2(vec2 input, float minimum){
	float value = 0.0;
	float scale = 0.5;
	
	for(int i = 0; i < OCTAVE; i++){
		value += perlin(input)*scale;
		input*=2.0;
		scale*=0.5;
	}
	return (smoothstep(minimum,1.,value)-minimum)/(1.0-minimum);
}

void fragment(){
	vec4 originalColor = texture(TEXTURE, UV);
	float timescaled = TIME * timescale;
	//vec2 zoomUV = vec2(zoomScale * UV.x + UV.x*0.04*TIME*sin(0.07*TIME), zoomScale * UV.y + UV.y*0.05*TIME*cos(0.06*TIME));
	vec2 zoomUV2 = vec2(zoomScale * UV.x + 0.03*timescaled*sin(0.07*timescaled), zoomScale * UV.y + 0.03*timescaled*cos(0.06*timescaled));
	vec2 zoomUV3 = vec2(zoomScale * UV.x + 0.027*timescaled*sin(0.07*timescaled), zoomScale * UV.y + 0.025*timescaled*cos(0.06*timescaled));
	vec2 zoomUV4 = vec2(zoomScale * UV.x + 0.021*timescaled*sin(0.07*timescaled), zoomScale * UV.y + 0.021*timescaled*cos(0.07*timescaled));
	float tide = 0.05*sin(TIME);
	float tide2 = 0.06*cos(0.3*TIME);
	//if(color_replace == originalColor.rgb){
		vec4 nebulaTexture = vec4(SPACE.rgb, 0.5+0.2*sin(0.23*TIME +UV.x-UV.y));
		nebulaTexture += fbmCloud2(zoomUV3, 0.24 + tide)*CLOUD1_COL;
		nebulaTexture += fbmCloud(zoomUV2*0.9, 0.33 - tide)*CLOUD2_COL;
		nebulaTexture = mix(nebulaTexture,CLOUD3_COL,fbmCloud(vec2(0.9*zoomUV4.x,0.9*zoomUV4.y), 0.25+tide2));
		nebulaTexture = mix(nebulaTexture,CLOUD4_COL,fbmCloud(zoomUV3*0.7+2.0, 0.4+tide2));
		vec2 zoomstar = starscale*zoomUV2;
		vec2 pos = floor(zoomstar / size);
		float starValue = rand(pos);
		if(starValue>prob){
			vec2 center = size * pos + vec2(size, size) * 0.5;
			float t = 0.9 + 0.2 * sin(TIME * 8.0 + (starValue - prob) / (1.0 - prob) * 45.0);
			float color = 1.0 - distance(zoomstar, center) / (0.5 * size);
			nebulaTexture = mix(nebulaTexture, vec4(1.0,1.0,1.0,1.0),smoothstep(0.,1.,color * t / (abs(zoomstar.y - center.y)) * t / (abs(zoomstar.x - center.x))));
		} else {
			zoomstar *= 5.0;
			pos = floor(zoomstar / size);
			float starValue2 = rand(pos + vec2(13.0,13.0));
			if(starValue2 >= 0.95){
				vec2 center = size * pos + vec2(size, size) * 0.5;
				float t = 0.9 + 0.2 * sin(TIME * 8.0 + (starValue - prob) / (1.0 - prob) * 45.0);
				float color = 1.0 - distance(zoomstar, center) / (0.5 * size);
				nebulaTexture = mix(nebulaTexture, vec4(1.0,1.0,1.0,1.0),fbmCloud(pos,0.0)*smoothstep(0.,1.,color * t / (abs(zoomstar.y - center.y)) * t / (abs(zoomstar.x - center.x))));
			}
		}
		COLOR = vec4(nebulaTexture.rgb, 1.0);
		//COLOR = vec4(nebulaTexture.rgb,nebulaTexture.a * 1.2)
	//} else {
	//	COLOR = originalColor;
	//}
}
Tags
2d, space
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.

More from flytrap

2D Sonar

2D Procedural Water

Related shaders

Nebula Stars Clouds

Dance Floor Shader

Grid shader tutorial

Subscribe
Notify of
guest

6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
maulinux
maulinux
1 year ago

cool shader, i use it

Seqxxxx
Seqxxxx
1 year ago

doesn’t seem to work with Godot 4.0? I get weird blocky artifacts. Was wondering if anybody has managed to fix this? I never really touch shaders.

Shadowblitz16
Shadowblitz16
1 year ago

your shader works differently depending on whether it’s ran in the editor or in game

DapperDragon
5 months ago

In Godot 4 “hint_color” is now “source_color”