3D Pixelated Planet

Inspired by: https://www.youtube.com/shorts/7g5Cj_1XPkM

Shader code
shader_type canvas_item;

uniform float pixelation : hint_range(0.0, 250.0, 0.001) = 150;
uniform float radius : hint_range(0.0, 0.5, 0.001) = 0.5;
uniform float rotate_x : hint_range(0.0, 180.0, 0.01) = 90.0;
uniform float rotate_y : hint_range(0.0, 360.0, 0.01) = 30;
uniform float rotation_speed: hint_range(0.0, 1.0, 0.001) = 0.01;
uniform vec3 sun_direction = vec3(1.0, 0.15, 0.0);
uniform float sun_strength= 2.7;
uniform sampler3D terrain_map;
uniform sampler2D terrain_colors;

mat3 rotateX(float angle) {
    float s = sin(angle);
    float c = cos(angle);
    return mat3(
        vec3(1, 0, 0),
        vec3(0, c, -s),
        vec3(0, s, c)
    );
}

mat3 rotateY(float angle) {
    float s = sin(angle);
    float c = cos(angle);
    return mat3(
        vec3(c, 0, s),
        vec3(0, 1, 0),
        vec3(-s, 0, c)
    );
}

void fragment() {
    vec2 original_uv = UV - vec2(0.5);
    vec2 centered_uv = original_uv;
    float original_dist = length(original_uv);

    // Apply pixelation to the entire UV space
    if (pixelation > 0.0) {
        centered_uv = floor(centered_uv * pixelation) / pixelation;
    }

    if (original_dist <= radius) {
        // Normalize UV coordinates
        vec2 normalized_uv = centered_uv / radius;

        // Convert UV to 3D point on sphere
        vec3 sphere_point = vec3(
            normalized_uv.x,
            sqrt(max(0.0, 1.0 - dot(normalized_uv, normalized_uv))),
            normalized_uv.y
        );

        // Apply X and Y axis rotations
        float rot_x_r = radians(rotate_x);
        float rot_y_r = radians(rotate_y + 360.0 * TIME * rotation_speed);
        mat3 rot_matrix_x = rotateX(rot_x_r);
        mat3 rot_matrix_y = rotateY(rot_y_r);
        vec3 rotated_point = rot_matrix_y * rot_matrix_x * sphere_point;

		vec3 sphere_point_rotated_by_player = rotateY(radians(rotate_y)) * rot_matrix_x * sphere_point;
		float light = dot(normalize(sphere_point_rotated_by_player / length(sphere_point_rotated_by_player)), normalize(sun_direction));
		// Dithering
		light = min(0.5, floor(light * 30.0) / 10.0) * sun_strength;

        // Sample terrain and color
        vec3 sample_point = rotated_point * 0.5 + 0.5;
        float terrain_value = texture(terrain_map, sample_point).r;
        vec4 terrain_color = texture(terrain_colors, vec2(terrain_value, 0.0));

        float edge_smoothness = fwidth(original_dist) * 2.0;
        float alpha = 1.0 - smoothstep(radius - edge_smoothness, radius, original_dist);

        COLOR = vec4(terrain_color.rgb * light, alpha);
    } else {
        COLOR = vec4(0.0);
    }
}
Tags
3d, godot4, Pixelated, planet, 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.

Related shaders

Planet

Simple Spatial Planet

Pixelated Glitch PostEffect

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Erik
Erik
1 month ago

This is awesome!