└── addons
└── planet2d
├── icons
├── PlanetLayer.svg
├── PlanetLayer.svg.import
├── PlanetLayers.svg
└── PlanetLayers.svg.import
├── palette
├── cosine_generator.gd
├── palette_generator.gd
└── palette_gradient.gd
├── planet.gdshader
├── planet_layer.gd
├── planet_layers.gd
├── plugin.cfg
└── plugin.gd
/addons/planet2d/icons/PlanetLayer.svg:
--------------------------------------------------------------------------------
1 |
2 |
147 |
--------------------------------------------------------------------------------
/addons/planet2d/icons/PlanetLayer.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b4yitophtuce5"
6 | path="res://.godot/imported/PlanetLayer.svg-ffadbba9170efb82a4910e12c61fbbbd.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/planet2d/icons/PlanetLayer.svg"
14 | dest_files=["res://.godot/imported/PlanetLayer.svg-ffadbba9170efb82a4910e12c61fbbbd.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/planet2d/icons/PlanetLayers.svg:
--------------------------------------------------------------------------------
1 |
2 |
147 |
--------------------------------------------------------------------------------
/addons/planet2d/icons/PlanetLayers.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bi21foirwb2mh"
6 | path="res://.godot/imported/PlanetLayers.svg-640ac274a582f0c56fbffaa642f9eb4d.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/planet2d/icons/PlanetLayers.svg"
14 | dest_files=["res://.godot/imported/PlanetLayers.svg-640ac274a582f0c56fbffaa642f9eb4d.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/planet2d/palette/cosine_generator.gd:
--------------------------------------------------------------------------------
1 | class_name CosineGenerator extends PaletteGenerator
2 |
3 | @export var offset := Vector3():
4 | set = _set_offset
5 | @export var amplitude := Vector3():
6 | set = _set_amplitude
7 | @export var frequency := Vector3():
8 | set = _set_frequency
9 | @export var phase := Vector3():
10 | set = _set_phase
11 |
12 | @export var alpha_enabled := false:
13 | set = _set_alpha_enabled
14 | @export var alpha := Vector4():
15 | set = _set_alpha
16 |
17 | func _generate_1d(t:float, offset:float, amplitude:float, frequency:float, phase:float)->float:
18 | return offset + amplitude * cos(2 * PI * (frequency * t + phase))
19 |
20 | func generate_color(t:float)->Color:
21 | return Color(
22 | _generate_1d(t, offset.x, amplitude.x, frequency.x, phase.x),
23 | _generate_1d(t, offset.y, amplitude.y, frequency.y, phase.y),
24 | _generate_1d(t, offset.z, amplitude.z, frequency.z, phase.z),
25 | _generate_1d(t, alpha.x, alpha.y, alpha.z, alpha.w) if alpha_enabled else 1.0,
26 | )
27 |
28 | func generate(gradient:Gradient):
29 | for i in gradient.get_point_count():
30 | var t := gradient.get_offset(i)
31 | var color := generate_color(t)
32 | gradient.set_color(i, color)
33 |
34 | func _set_offset(v:Vector3)->void:
35 | if offset == v: return
36 | offset = v
37 | emit_changed()
38 |
39 | func _set_amplitude(v:Vector3)->void:
40 | if amplitude == v: return
41 | amplitude = v
42 | emit_changed()
43 |
44 | func _set_frequency(v:Vector3)->void:
45 | if frequency == v: return
46 | frequency = v
47 | emit_changed()
48 |
49 | func _set_phase(v:Vector3)->void:
50 | if phase == v: return
51 | phase = v
52 | emit_changed()
53 |
54 | func _set_alpha_enabled(v:bool)->void:
55 | if alpha_enabled == v: return
56 | alpha_enabled = v
57 | emit_changed()
58 |
59 | func _set_alpha(a:Vector4)->void:
60 | if alpha == a: return
61 | alpha = a
62 | emit_changed()
63 |
--------------------------------------------------------------------------------
/addons/planet2d/palette/palette_generator.gd:
--------------------------------------------------------------------------------
1 | class_name PaletteGenerator extends Resource
2 |
3 | func generate_color(t:float)->Color:
4 | return Color()
5 |
6 | func generate(gradient:Gradient)->void:
7 | pass
8 |
--------------------------------------------------------------------------------
/addons/planet2d/palette/palette_gradient.gd:
--------------------------------------------------------------------------------
1 | class_name PaletteGradient extends Gradient
2 |
3 | @export var generator:PaletteGenerator:
4 | set = _set_generator
5 | @export var resolution:int:
6 | set = _set_resolution
7 |
8 | func _get_color(offset:float)->Color:
9 | return generator.generate_color(offset) if generator else Color()
10 |
11 | func create_resolution(resolution:int)->void:
12 | while get_point_count() > 2: remove_point(0)
13 | set_offset(0, 0.0)
14 | set_color(0, _get_color(0.0))
15 | set_offset(1, 1.0)
16 | set_color(1, _get_color(1.0))
17 | var step := 1.0 / float(resolution)
18 | for i in (resolution - 2):
19 | var offset := (i + 1) * step
20 | add_point(offset, generator.generate_color(offset) if generator else Color())
21 |
22 | func apply()->void:
23 | generator.generate(self)
24 |
25 | func _set_generator(g:PaletteGenerator)->void:
26 | if generator:
27 | generator.changed.disconnect(_on_generator_changed)
28 |
29 | generator = g
30 |
31 | if generator:
32 | apply()
33 | generator.changed.connect(_on_generator_changed)
34 |
35 | func _set_resolution(r:int)->void:
36 | create_resolution(r)
37 |
38 | func _on_generator_changed()->void:
39 | apply()
40 |
--------------------------------------------------------------------------------
/addons/planet2d/planet.gdshader:
--------------------------------------------------------------------------------
1 | shader_type canvas_item;
2 | render_mode unshaded;
3 |
4 | const float PI2 = PI / 2.0;
5 | const vec3 UP = vec3(0.0, 0.0, 1.0);
6 |
7 | uniform vec2 texture_scale = vec2(0.5, 0.5);
8 | uniform vec2 texture_offset = vec2(0.0, 0.0);
9 |
10 | uniform vec3 atmosphere_color = vec3(1.0, 1.0, 1.0);
11 | uniform float atmosphere_intensity = 0.0;
12 |
13 | uniform vec3 light_color = vec3(1.0, 1.0, 1.0);
14 | uniform vec3 light_direction = vec3(0.0, 0.0, 1.0);
15 | uniform float light_minimum = 0.0;
16 | uniform float light_maximum = 1.0;
17 |
18 | uniform vec3 specular_color = vec3(1.0, 1.0, 1.0);
19 | uniform float specular_intensity = 0.1;
20 | uniform float specular_shininess = 1.0;
21 |
22 | uniform float fade = 0.0;
23 |
24 | uniform bool pixelize_enabled = false;
25 | uniform float pixelize_scale = 1.0;
26 |
27 | float z_from_xy(vec2 vector) {
28 | return sqrt(1.0 - vector.x * vector.x - vector.y * vector.y);
29 | }
30 |
31 | vec2 transform_uv(vec2 uv, vec2 texel) {
32 | // Center uv coordinates
33 | uv = (uv - vec2(0.5, 0.5)) * 2.0;
34 | // Quantize UV resolution
35 | vec2 resolution = (1.0 / texel) * pixelize_scale;
36 | return mix(uv, round(uv * resolution) / resolution, float(pixelize_enabled));
37 | }
38 |
39 | vec2 spherical_distort(vec2 uv) {
40 | // Spherical Displacement
41 | float radius = length(uv);
42 | float displacement_scale = (radius != 0.0 ? asin(radius) / radius : 0.0) / PI2;
43 | vec2 displacement = uv * displacement_scale;
44 | return (displacement + texture_offset) * texture_scale;
45 | }
46 |
47 | mat3 generate_normal_matrix(vec3 normal) {
48 | vec3 T = normalize(cross(normal, vec3(normal.z, -normal.y, -normal.x)));
49 | vec3 B = normalize(cross(normal, T));
50 | vec3 N = normal;
51 | return mat3(T, B, N);
52 | }
53 |
54 | vec3 atmospherics(vec3 color, vec3 normal) {
55 | // Atmospherics
56 | float atmospheric_coefficient = 1.0 - max(dot(normal, UP), 0.0);
57 | float atmospheric_density = mix(atmosphere_intensity, 1.0, atmospheric_coefficient);
58 |
59 | return mix(color, atmosphere_color, atmospheric_density);
60 | }
61 |
62 | vec3 get_diffuse(vec3 normal, vec3 light_normal, vec3 color) {
63 | // Diffuse
64 | float light_dot = max(dot(normal, light_normal), 0.0);
65 | float diffuse_coefficient = mix(light_minimum, light_maximum, light_dot);
66 | return (color * diffuse_coefficient) * light_color;
67 | }
68 |
69 | vec3 get_specular(vec3 normal, vec3 light_normal, float shininess) {
70 | // Specular
71 | shininess = mix(1.0, specular_shininess * specular_shininess, shininess);
72 | float reflect_dot = dot(reflect(-light_normal, normal), UP);
73 | float specular_coefficient = specular_intensity * pow(max(0.0, reflect_dot), shininess);
74 | return (specular_color * specular_coefficient) * light_color;
75 | }
76 |
77 | void fragment() {
78 | vec2 uv = transform_uv(UV, TEXTURE_PIXEL_SIZE);
79 | vec3 normal = vec3(uv, z_from_xy(uv));
80 | float radius = length(uv);
81 |
82 | vec3 light_normal = normalize(light_direction);
83 |
84 | // Spherical Displacement
85 | vec2 displaced_uv = spherical_distort(uv);
86 |
87 | // Get inputs from samplers
88 | vec4 input_color = texture(TEXTURE, displaced_uv);
89 | vec4 input_shininess = texture(SPECULAR_SHININESS_TEXTURE, displaced_uv);
90 | vec3 input_normal = texture(NORMAL_TEXTURE, displaced_uv).xyz * 2.0 - 1.0;
91 | input_normal.xy = -input_normal.yx;
92 |
93 | // Adjust Normal to Normal Map
94 | mat3 normal_matrix = generate_normal_matrix(normal);
95 | vec3 displaced_normal = normal_matrix * input_normal;
96 |
97 | float light_dot = smoothstep(-0.4, 0.0, dot(normal, light_normal));
98 | float global_light = mix(light_minimum, light_maximum, light_dot);
99 |
100 | vec3 diffuse = get_diffuse(displaced_normal, light_normal, input_color.rgb);
101 | vec3 specular = get_specular(displaced_normal, light_normal, input_shininess.r);
102 |
103 | COLOR.rgb = (diffuse + specular) * global_light;
104 |
105 | float fade_texels = length(TEXTURE_PIXEL_SIZE) * fade;
106 | float alpha = 1.0 - smoothstep(1.0 - fade_texels, 1.0, radius);
107 | COLOR.a = alpha * input_color.a;
108 | }
109 |
--------------------------------------------------------------------------------
/addons/planet2d/planet_layer.gd:
--------------------------------------------------------------------------------
1 | @icon("res://addons/planet2d/icons/PlanetLayer.svg")
2 | class_name PlanetLayer extends Sprite2D
3 |
4 | ## A Sprite2D with a [ShaderMaterial] (using [constant PlanetLayerShader]), a spherical distort shader with additional lighting effects.
5 | ##
6 | ## Any [Texture2D] can be attached to this Sprite2D and it will spherically distort it, with lighting effects.
7 | ## To have the effect of spinning, modify the [member texture_offset] to scroll the texture. If using [NoiseTexture2D], consider using [member NoiseTexture2D.color_ramp] to give more interesting results.
8 |
9 | ## Spherical distort and lighting shader
10 | const PlanetLayerShader := preload("res://addons/planet2d/planet.gdshader")
11 |
12 | @export_group("Texture", "texture_")
13 |
14 | ## Scales texture itself in the spherical rendering. At [1.0], texture repetition could be visible at texture boundaries. [0.5] ensures no repetition is visible.
15 | ## This will affect the range of [member texture_offset]. When set to [0.5], the range of [member texture_offset] becomes [0.0 - 2.0].
16 | @export var texture_scale := Vector2(0.5, 0.5):
17 | set(ts):
18 | texture_scale = ts
19 | material.set_shader_parameter("texture_scale", texture_scale)
20 |
21 | ## The amount to scroll the texture by. The value is in UV coordinates, [0.0 - 1.0] is a full texture size scroll, if [member texture_scale] is 1.0.
22 | @export var texture_offset := Vector2():
23 | set(to):
24 | texture_offset = to
25 | material.set_shader_parameter("texture_offset", texture_offset * texture_offset_scale)
26 |
27 | ## Scales the effect of [member texture_offset]. A higher scale will result in faster scrolling for the same offset.
28 | @export var texture_offset_scale := 1.0:
29 | set(tos):
30 | texture_offset_scale = tos
31 | material.set_shader_parameter("texture_offset", texture_offset * texture_offset_scale)
32 |
33 | @export_group("Atmosphere", "atmosphere_")
34 |
35 | ## Color of the atmosphere, primarily at the edges of the sphere at low values. Gives a fog effect.
36 | @export var atmosphere_color := Color(1.0, 1.0, 1.0):
37 | set(ac):
38 | atmosphere_color = ac
39 | material.set_shader_parameter("atmosphere_color", atmosphere_color)
40 |
41 | ## Controls the density of the atmosphere. At higher values, the texture itself will become invisible as it is enveloped by the atmosphere.
42 | @export var atmosphere_intensity := 0.0:
43 | set(ai):
44 | atmosphere_intensity = ai
45 | material.set_shader_parameter("atmosphere_intensity", atmosphere_intensity)
46 |
47 | @export_group("Light", "light_")
48 |
49 | ## Color of the light affecting this layer.
50 | @export var light_color := Color(1.0, 1.0, 1.0):
51 | set(lc):
52 | light_color = lc
53 | material.set_shader_parameter("light_color", light_color)
54 |
55 | ## The direction to the light source. This vector is normalized in the shader.
56 | @export var light_direction := Vector3(0.0, 0.0, 1.0):
57 | set(ld):
58 | light_direction = ld
59 | material.set_shader_parameter("light_direction", light_direction)
60 |
61 | ## Minimum light level.
62 | @export var light_minimum := 0.1:
63 | set(lm):
64 | light_minimum = lm
65 | material.set_shader_parameter("light_minimum", light_minimum)
66 |
67 | ## Maximum light level.
68 | @export var light_maximum := 1.0:
69 | set(lm):
70 | light_maximum = lm
71 | material.set_shader_parameter("light_maximum", light_maximum)
72 |
73 | @export_group("Specular", "specular_")
74 |
75 | ## Color of the specular effect.
76 | @export var specular_color := Color(1.0, 1.0, 1.0):
77 | set(sc):
78 | specular_color = sc
79 | material.set_shader_parameter("specular_color", specular_color)
80 |
81 | ## Specular intensity, or brightness. Reasonable values are from [0.0 - 1.0].
82 | @export var specular_intensity := 0.2:
83 | set(si):
84 | specular_intensity = si
85 | material.set_shader_parameter("specular_intensity", specular_intensity)
86 |
87 | ## The shininess of the material. Lower values will result in very diffused specular highlights (ex: ground). Higher values will have a smaller highlight (ex: water).
88 | @export var specular_shininess := 1.0:
89 | set(ss):
90 | specular_shininess = ss
91 | material.set_shader_parameter("specular_shininess", specular_shininess)
92 |
93 | @export_group("Pixelize", "pixelize_")
94 | ## Enable planet rendering pixelization
95 | @export var pixelize_enabled := false:
96 | set(pe):
97 | pixelize_enabled = pe
98 | material.set_shader_parameter("pixelize_enabled", pixelize_enabled)
99 |
100 | ## Resolution scale of the render output. 0.5 means each pixel is 2x larger.
101 | @export var pixelize_scale := 1.0:
102 | set(ps):
103 | pixelize_scale = ps
104 | material.set_shader_parameter("pixelize_scale", pixelize_scale)
105 |
106 | func _init()->void:
107 | texture_repeat = CanvasItem.TEXTURE_REPEAT_ENABLED
108 |
109 | material = ShaderMaterial.new()
110 | material.shader = PlanetLayerShader
111 |
112 | func _ready()->void:
113 | update()
114 |
115 | ## Apply all parameters to the shader. Parameters should be applied as you set them, but in vector properties, you might need to update manually if setting member variables.
116 | func update()->void:
117 | material.set_shader_parameter("texture_scale", texture_scale)
118 | material.set_shader_parameter("texture_offset", texture_offset * texture_offset_scale)
119 |
120 | material.set_shader_parameter("atmosphere_color", atmosphere_color)
121 | material.set_shader_parameter("atmosphere_intensity", atmosphere_intensity)
122 |
123 | material.set_shader_parameter("light_color", light_color)
124 | material.set_shader_parameter("light_direction", light_direction)
125 | material.set_shader_parameter("light_minimum", light_minimum)
126 | material.set_shader_parameter("light_maximum", light_maximum)
127 |
128 | material.set_shader_parameter("specular_color", specular_color)
129 | material.set_shader_parameter("specular_intensity", specular_intensity)
130 | material.set_shader_parameter("specular_shininess", specular_shininess)
131 |
132 | material.set_shader_parameter("pixelize_enabled", pixelize_enabled)
133 | material.set_shader_parameter("pixelize_scale", pixelize_scale)
134 |
--------------------------------------------------------------------------------
/addons/planet2d/planet_layers.gd:
--------------------------------------------------------------------------------
1 | @icon("res://addons/planet2d/icons/PlanetLayers.svg")
2 | class_name PlanetLayers extends Node2D
3 |
4 | ## A simple container to control child [PlanetLayer] node properties should reasonably be the same for a single planet.
5 | ##
6 | ## Also provides an easy way to have a spinning effect for all child [PlanetLayer] nodes.
7 | ## Use [method add_layer] and [method remove_layer] to register the [PlanetLayer] with this node.
8 |
9 | ## All child [PlanetLayer] nodes.
10 | var layers:Array[PlanetLayer] = []
11 |
12 | ## Sets the spin mode, applied at this node's [method _process] event. Must have a non-zero [member spin] vector set to have any effect.
13 | @export var is_spinning := false
14 | ## Speed of the spinning. The values are effectively delta [member PlanetLayer.texture_offset] per second.
15 | @export var spin := Vector2()
16 |
17 | ## Controls the [member PlanetLayer.texture_offset] of all child [PlanetLayer] nodes.
18 | @export var texture_offset := Vector2():
19 | set(to):
20 | texture_offset = to
21 | set_parameter("texture_offset", texture_offset)
22 |
23 | @export_group("Light", "light_")
24 | ## Controls the [member PlanetLayer.light_color] of all child [PlanetLayer] nodes.
25 | @export var light_color := Color(1.0, 1.0, 1.0):
26 | set(lc):
27 | light_color = lc
28 | set_parameter("light_color", light_color)
29 |
30 | ## Controls the [member PlanetLayer.light_direction] of all child [PlanetLayer] nodes.
31 | @export var light_direction := Vector3(0.0, 0.0, 1.0):
32 | set(ld):
33 | light_direction = ld
34 | set_parameter("light_direction", light_direction)
35 |
36 | ## Controls the [member PlanetLayer.light_minimum] of all child [PlanetLayer] nodes.
37 | @export var light_minimum := 0.0:
38 | set(lm):
39 | light_minimum = lm
40 | set_parameter("light_minimum", light_minimum)
41 |
42 | ## Controls the [member PlanetLayer.light_maximum] of all child [PlanetLayer] nodes.
43 | @export var light_maximum := 1.0:
44 | set(lm):
45 | light_maximum = lm
46 | set_parameter("light_maximum", light_maximum)
47 |
48 | @export_group("Pixelize", "pixelize_")
49 | ## Enable planet rendering pixelization
50 | @export var pixelize_enabled := false:
51 | set(pe):
52 | pixelize_enabled = pe
53 | set_parameter("pixelize_enabled", pixelize_enabled)
54 |
55 | ## Resolution scale of the render output. 0.5 means each pixel is 2x larger.
56 | @export var pixelize_scale := 1.0:
57 | set(ps):
58 | pixelize_scale = ps
59 | set_parameter("pixelize_scale", pixelize_scale)
60 |
61 | func _ready()->void:
62 | for c in get_children():
63 | if not c is PlanetLayer:
64 | continue
65 | layers.push_back(c as PlanetLayer)
66 | update()
67 |
68 | func _process(delta):
69 | if is_spinning:
70 | texture_offset += spin * delta
71 |
72 | ## Applies all properties to all child [PlanetLayer] nodes.
73 | func update()->void:
74 | set_parameter("texture_offset", texture_offset)
75 |
76 | set_parameter("light_color", light_color)
77 | set_parameter("light_direction", light_direction)
78 | set_parameter("light_minimum", light_minimum)
79 | set_parameter("light_maximum", light_maximum)
80 |
81 | set_parameter("pixelize_enabled", pixelize_enabled)
82 | set_parameter("pixelize_scale", pixelize_scale)
83 |
84 | ## Utility method to set a property on child [PlanetLayer] nodes.
85 | func set_parameter(name:String, value:Variant)->void:
86 | for l in layers:
87 | l.set(name, value)
88 |
89 | ## Utility method to set a Shader uniform on child [PlanetLayer] nodes.
90 | func set_shader_parameter(name:String, value:Variant)->void:
91 | for l in layers:
92 | l.material.set_shader_parameter(name, value)
93 |
94 | ## Add a new [PlanetLayer] to this node. It must not have a parent, as it is with [method Node.add_child].
95 | func add_layer(layer:PlanetLayer)->void:
96 | if layers.has(layer) || layer.get_parent():
97 | return
98 |
99 | add_child(layer)
100 | layers.push_back(layer)
101 |
102 | update()
103 |
104 | ## Remove a [PlanetLayer].
105 | func remove_layer(layer:PlanetLayer)->void:
106 | if !layers.has(layer):
107 | return
108 | layers.erase(layer)
109 | remove_child(layer)
110 |
--------------------------------------------------------------------------------
/addons/planet2d/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Planet2D"
4 | description="Utility classes as a Shader wrapper to create pseudo-3D planets from 2D textures."
5 | author="PDeveloper"
6 | version="1.0"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/planet2d/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
--------------------------------------------------------------------------------