Starfield
If you like this shader, you should check out Star Nest, a shadertoy port by Lyagva. It will likely produce better results than this shader.
This shader is a modification of iVader’s starfield shader for practice and personal use. Includes a lot more customizability via the shader parameters, and a few new effects. This is probably not the best written shader ever, I have very minimal experience inside Godot.
This shader doesn’t require any external scripts or textures, put the shader material in a compatible 2D node and it should work.
Various retroization effects included, methodology isn’t perfect. Updated 7/14/24 to incorporate dithering. Somewhat based off of Donitzo’s color dithering shader.
Shader code
shader_type canvas_item;
//starfield customization
uniform float anim_speed : hint_range(-5.0, 5.0) = 0.0;
uniform float star_brightness : hint_range(0.0, 0.5) = 0.05;
//generally you should keep the brightness below 0.1, unless your distance fade is below .2
uniform float dust : hint_range(0.0, 0.25) = 0.125;
uniform float dist_fade : hint_range(0.0, 1.0) = 0.35;
uniform float pixelation : hint_range(50, 1000) = 1000.0;
//this pixelation method might produce different results on screens of different resolutions
//keep it at 1000 to keep it off entirely
uniform int quantization_levels : hint_range(1, 256) = 256;
//colors
uniform vec3 dust_color : source_color = vec3(0.0, 55.0, 75.0);
uniform float saturation : hint_range(0.0, 1.0) = 1;
// turning the saturation to 0 will remove the space dust completely due to how the shader works.
// reccomend turning the color to white, then desaturating to about 0.1 to retain the space dust.
//if you turn the layers down below 7.0 you will need to adjust the distance fade to avoid pop-in
uniform float layers : hint_range(1.0, 9.0) = 7.0;
//rec. not going over 12
uniform int iterations : hint_range(1, 16) = 12;
//constants
const float formuparam2 = 0.79;
const float zoom = 1.0;
const float tile = 0.850;
const float stepsize = 0.29;
float triangle(float x, float a) {
return 2.0 * abs(3.0 * ((x / a) - floor((x / a) + 0.5))) - 1.0;
}
float field(in vec3 p) {
float strength = 7.0 + 0.03 * log(1.e-6 + fract(sin(TIME) * 373.11));
float accum = 0.0;
float prev = 0.0;
float tw = 0.0;
for (int i = 0; i < 6; ++i) {
float mag = dot(p, p);
p = abs(p) / mag + vec3(-0.5, -0.8 + 0.1 * sin(-TIME * 0.1 + 2.0), -1.1 + 0.3 * cos(TIME * 0.3));
float w = exp(-float(i) / 7.0);
accum += w * exp(-strength * pow(abs(mag - prev), 2.3));
tw += w;
prev = mag;
}
return max(0.0, 5.0 * accum / tw - 0.7);
}
//color quantization
vec3 quantizeColor(vec3 color, int levels) {
return floor(color * float(levels)) / float(levels);
}
//janky pixelation effect
// this will not translate well on screens of different resolutions and aspect ratios, keep it at 1000 to keep it off.
vec2 pixelate(vec2 uv) {
if (pixelation < 1000.0) {
return floor(uv * pixelation) / pixelation;
} else {
return uv;
}
}
void fragment() {
vec2 uv2 = pixelate(FRAGCOORD.xy / vec2(512));
vec2 uvs = uv2 * vec2(512) / 512.0;
float time = TIME;
float speed = anim_speed;
float formuparam = formuparam2;
vec2 uv = uvs;
float a_xz = 0.9;
float a_yz = -0.6;
float a_xy = 0.9 + time * 0.009;
mat2 rot_xz = mat2(vec2(cos(a_xz), sin(a_xz)), vec2(-sin(a_xz), cos(a_xz)));
mat2 rot_yz = mat2(vec2(cos(a_yz), sin(a_yz)), vec2(-sin(a_yz), cos(a_yz)));
mat2 rot_xy = mat2(vec2(cos(a_xy), sin(a_xy)), vec2(-sin(a_xy), cos(a_xy)));
float v2 = 1.0;
vec3 dir = vec3(uv * zoom, 1.0);
vec3 from = vec3(0.0, 0.0, 0.0);
from.x += cos(0.01 * time) + 0.001 * time;
from.y += sin(0.01 * time) + 0.001 * time;
from.z += 0.003 * time;
dir.xy *= rot_xy;
vec3 forward = vec3(0.0, 0.0, 1.0);
forward.xy *= rot_xy;
dir.xz *= rot_xz;
forward.xz *= rot_xz;
dir.yz *= rot_yz;
forward.yz *= rot_yz;
from.xy *= -1.0 * rot_xy;
from.xz *= rot_xz;
from.yz *= rot_yz;
float parallax = (time - 3311.0) * speed * 0.1;
from += forward * parallax;
float sampleShift = mod(parallax, stepsize);
float zoffset = -sampleShift;
sampleShift /= stepsize;
float s = 0.24;
float s3 = s + stepsize / 2.0;
vec3 v = vec3(0.0);
float t3 = 0.0;
vec3 backCol2 = vec3(0.0);
for (float r = 0.0; r < layers; r++) {
vec3 p2 = from + (s + zoffset) * dir;
vec3 p3 = from + (s3 + zoffset) * dir;
p2 = abs(vec3(tile) - mod(p2, vec3(tile * 2.0)));
p3 = abs(vec3(tile) - mod(p3, vec3(tile * 2.0)));
t3 = field(p3);
float pa, a = pa = 0.0;
for (int i = 0; i < iterations; i++) {
p2 = abs(p2) / dot(p2, p2) - formuparam;
float D = abs(length(p2) - pa);
a += i > 7 ? min(12.0, D) : D;
pa = length(p2);
}
a *= a * a;
float s1 = s + zoffset;
float fade = pow(dist_fade, max(0.0, float(r) - sampleShift));
v += fade;
if (r == 0.0)
fade *= (1.0 - sampleShift);
if (r == layers - 1.0)
fade *= sampleShift;
float brightness = mix(0.4, 1.0, v2);
vec3 starColor = dust_color * brightness * vec3(1.8 * t3 * t3 * t3, 1.4 * t3 * t3, t3) * fade;
v += vec3(s1, s1 * s1, s1 * s1 * s1 * s1) * a * star_brightness * fade;
backCol2 += starColor;
s += stepsize;
s3 += stepsize;
}
v = mix(vec3(length(v)), v, saturation);
backCol2 = mix(vec3(length(backCol2)), backCol2, saturation);
vec4 forCol2 = vec4(v * 0.01, 1.0);
backCol2 *= dust;
vec3 finalColor = forCol2.rgb + backCol2 * saturation;
finalColor = quantizeColor(finalColor, quantization_levels);
COLOR = vec4(finalColor, 1.0);
}
It’s so beautiful
This one should have more likes, the shader is much better than the many others I’ve seen here