├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── addons
└── hoimar.planetgen
│ ├── LICENSE
│ ├── planet_presets
│ ├── alien_planet_settings.tres
│ ├── earthlike_planet_settings.tres
│ ├── moon_settings.tres
│ ├── sun_settings.tres
│ └── test_planet_settings.tres
│ ├── plugin.cfg
│ ├── plugin.gd
│ ├── resources
│ ├── icons
│ │ ├── globe.svg
│ │ ├── globe.svg.import
│ │ ├── planet.svg
│ │ ├── planet.svg.import
│ │ ├── solar_system.svg
│ │ ├── solar_system.svg.import
│ │ ├── sun.svg
│ │ └── sun.svg.import
│ ├── materials
│ │ ├── alien_planet_material.tres
│ │ ├── atmosphere.gdshader
│ │ ├── atmosphere.shader
│ │ ├── atmosphere.tres
│ │ ├── earthlike_planet_material.tres
│ │ ├── moon_material.tres
│ │ ├── sun_bloom_material.tres
│ │ ├── sun_material.tres
│ │ ├── test_planet_material.tres
│ │ ├── water.gdshader
│ │ ├── water.shader
│ │ └── water.tres
│ ├── models
│ │ ├── Hull.material
│ │ ├── Ship.blend
│ │ ├── Ship.blend1
│ │ ├── ship_model.glb
│ │ ├── ship_model.glb.import
│ │ └── thruster_particle_mesh.tres
│ ├── screenshots
│ │ ├── .gdignore
│ │ ├── in_editor.png
│ │ ├── rising_moon.png
│ │ └── terrain_from_orbit.png
│ ├── space_environment.tres
│ ├── textures
│ │ ├── space_hdri.jpg
│ │ ├── space_hdri.jpg.import
│ │ ├── stars_hdri.png
│ │ ├── stars_hdri.png.import
│ │ ├── thruster_particle.png
│ │ ├── thruster_particle.png.import
│ │ ├── water_normal_1.png
│ │ ├── water_normal_1.png.import
│ │ ├── water_normal_2.png
│ │ └── water_normal_2.png.import
│ └── thruster_particles.tres
│ ├── scenes
│ ├── celestial_bodies
│ │ ├── atmosphere.tscn
│ │ ├── planet.tscn
│ │ └── sun.tscn
│ ├── gui
│ │ └── gui.tscn
│ ├── spacecraft
│ │ ├── player_ship.tscn
│ │ ├── player_ship_kinematic.tscn
│ │ └── ship.tscn
│ ├── terrain
│ │ └── terrain_patch.tscn
│ └── utils
│ │ ├── benchmark.tscn
│ │ ├── orbiting_camera.tscn
│ │ ├── origin_shifter.tscn
│ │ └── third_person_camera.tscn
│ └── scripts
│ ├── atmosphere
│ └── planet_atmosphere.gd
│ ├── celestial_bodies
│ ├── planet.gd
│ ├── planet_settings.gd
│ ├── solar_system.gd
│ └── sun.gd
│ ├── constants.gd
│ ├── gui
│ └── gui.gd
│ ├── quadtree
│ ├── cube_quadtree.gd
│ └── quadnode.gd
│ ├── spacecraft
│ ├── camera.gd
│ ├── player_controller.gd
│ ├── player_ship_kinematic.gd
│ └── ship.gd
│ ├── terrain
│ ├── job_queue.gd
│ ├── min_max.gd
│ ├── noise_generator.gd
│ ├── patch_data.gd
│ ├── ridged_noise_generator.gd
│ ├── shape_generator.gd
│ ├── terrain_job.gd
│ ├── terrain_manager.gd
│ ├── terrain_patch.gd
│ └── worker_thread.gd
│ └── utils
│ ├── benchmark.gd
│ ├── logger.gd
│ ├── orbiting_camera.gd
│ ├── origin_shifter.gd
│ ├── pg_globals.gd
│ └── third_person_camera.gd
├── default_env.tres
├── demos
├── quadtree_terrain_demo.gd
├── quadtree_terrain_demo.tscn
└── solar_system_demo.tscn
└── project.godot
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 | export.cfg
7 | export_presets.cfg
8 |
9 | # Imported translations (automatically generated from CSV files)
10 | *.translation
11 |
12 | # Mono-specific ignores
13 | .mono/
14 | data_*/
15 | mono_crash.*.json
16 |
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Hoimar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 | ====================================
24 |
25 | Other works used in this project:
26 |
27 |
28 | Atmosphere shader for Godot Engine
29 | -------------------------------------
30 | Copyright (c) 2021 Marc Gilleron
31 | MIT License
32 |
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Planet-Generator
3 | This is a procedural planet generator addon for the [Godot Engine](https://godotengine.org/) using layered noise functions and dynamic LOD (terrain chunks), written in GDScript.
4 |
5 | It's licensed unter MIT, so you can use it for pretty much anything as long as you retain the original license file.
6 |
7 | **Table of Contents**
8 | * [Features and Roadmap](#features-and-roadmap)
9 | * [Usage](#usage)
10 | * [Contributing](#contributing)
11 | * [Screenshots](#screenshots)
12 | * [Credits](#credits)
13 |
14 |
15 | ## Features and Roadmap
16 |
17 | List of completed features and planned features:
18 |
19 | * [ ] editor integration
20 | * [x] configurable `ShapeGenerator` resource
21 | * [x] configurable `PlanetSettings` resource
22 | * [x] configurable `NoiseGenerator` resources to layer noise
23 | * [ ] context-aware editor plugin to ease creation of new planets (settings, noise layers, materials?)
24 | * [ ] custom inspector plugin for creating and editing above resources
25 | * [ ] preview texture for NoiseGenerator resource
26 | * [ ] node based editor for terrain shape / noise generators to allow mixing etc.
27 | * [ ] graphics
28 | * [x] basic terrain coloring based on height using a gradient texture
29 | * [x] basic atmosphere shader
30 | * [x] basic water
31 | * [ ] texture mapping (triplanar)
32 | * [ ] better water with reflections and adjustable sea level
33 | * [ ] cloud layer around planet
34 | * [ ] bloom and lens flare effects
35 | * [ ] terrain generation
36 | * [x] quadtree for automatic LOD subdivision of terrain patches
37 | * [x] seamless terrain patches
38 | * [x] terrain collision using `PhysicsServer`
39 | * [ ] height curve for fine-tuning height levels
40 | * [ ] different types of `NoiseGenerators`
41 | * [x] `NoiseGenerator` (standard)
42 | * [x] `RidgedNoiseGenerator` (generates mountainous ridges)
43 | * [ ] simple erosion (morphological erosion, dilation, etc.)
44 | * [ ] generators for other interesting terrain patterns
45 | * [ ] multiple noise maps:
46 | * [ ] height map
47 | * [ ] biome / terrain type map
48 | * [ ] rivers
49 | * [ ] more detail on ground level: vegetation, rocks, etc. using instancing
50 | * [ ] allow generator to output not just straight to geometry but also to heightmaps, values, etc. for offline use
51 | * [ ] allow building terrain from different inputs like procedural noise but also heightmaps, values, files, etc.
52 | * [ ] allow mixing of inputs, see also "editor integration" (e.g. heightmap and noise)
53 | * [ ] documentation
54 | * [x] installing the addon
55 | * [ ] basic usage
56 | * [ ] creating new planets
57 | * [ ] extending the addon
58 | * [x] demo scenes with a spaceship to explore planets
59 | * [ ] other improvements
60 | * [ ] allow for larger scale (1 Godot unit = 1m? 1km?)
61 | * [x] use a scene origin shifter to keep player close to origin and thus mitigate lack float precision
62 | * [ ] enlarge scale, but shrink the universe while inside the editor to make it more maneuverable
63 | * [ ] use another atmosphere shader which doesn't glitch at higher scale
64 | * [ ] add simple planetary orbits
65 | * [ ] add gravity
66 | * [x] graceful loading and unloading of the addon, solar systems and planets
67 | * [x] simple benchmark and diagnostics HUD
68 | * [ ] performance optimization:
69 | * [x] multithreaded terrain generation using `WorkerThread`
70 | * [x] `JobQueue` for `TerrainJob` which feeds the worker threads with jobs
71 | * [ ] explore computing terrain data on the GPU (shaders, rendering to a viewport)
72 | * [ ] rewrite core parts in C#? (as parallel branch?)
73 | * [ ] rewrite core parts as GDNative module with C or C++? (as parallel branch?)
74 |
75 |
76 | ## Usage
77 |
78 | You need the Godot Engine to use this addon (tested with Godot 3.x.x).
79 |
80 | ### Quick Start
81 |
82 | To quickly get started, open the downloaded folder like a normal project in Godot and run it. You can then navigate a spaceship around the solar system demo scene. The keys are:
83 | * Mouse to rotate ship
84 | * WASD for movement
85 | * hold Shift for faster speed increment
86 | * hold Control to rotate the camera
87 | * Esc to release/capture the mouse
88 | * F1 to switch generating wireframe meshes on/off
89 | * F2 to switch random coloring of terrain patches on/off
90 |
91 | ### Using the addon
92 |
93 | Download and install the addon as described here [Installing plugins - Godot Engine documentation](https://docs.godotengine.org/en/stable/tutorials/plugins/editor/installing_plugins.html).
94 |
95 |
96 | **TODO:** Add detailed documentation for setting up planets and their parameters.
97 |
98 | For now, check out the solar system demo in `demos/solar_system_demo.tscn` to see how the planets are configured and play around with the settings. A planets needs a `PlanetSettings` resource, which contains a `ShapeGenerator` resource, which in turn has a list of one or more `NoiseGenerator` resources where you can define what the terrain will look like.
99 |
100 |
101 | ## Contributing
102 |
103 | * Found a bug? Please open an issue and add all relevant details.
104 | * Got an idea for the project? Open an issue or, if you want to implement it, open a pull request with your feature.
105 | * Want to help out with anything? Clone/Fork the repository and start coding! Pull requests are very welcome.
106 |
107 |
108 | ## Screenshots
109 |
110 | Click to enlarge:
111 |
112 |
113 |
114 |
115 |
116 |
117 | ## Credits
118 |
119 | * Contributors: [@creative-brain](https://github.com/creative-brain) (code, ideas), [@Valinakova](https://github.com/Valinakova) (ideas)
120 | * [atmosphere shader](https://github.com/Zylann/godot_atmosphere_shader) by Zylann aka Marc Gilleron, shared under the MIT license, slightly adapted
121 | * icons are CC0 from [svgrepo.com](https://svgrepo.com/)
122 | * inspired by [this amazing tutorial](https://www.youtube.com/watch?v=QN39W020LqU&index=2&t=0s&list=PLFt_AvWsXl0cONs3T0By4puYy6GM22ko8) for creating procedural planets by Sebastian Lague
123 |
124 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Hoimar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/planet_presets/alien_planet_settings.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" script_class="PlanetSettings" load_steps=9 format=3 uid="uid://bfhq5kbvtn36a"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/shape_generator.gd" id="1"]
4 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/ridged_noise_generator.gd" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/noise_generator.gd" id="3"]
6 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/planet_settings.gd" id="4"]
7 |
8 | [sub_resource type="Resource" id="1"]
9 | resource_name = "Large Ridges"
10 | script = ExtResource("2")
11 | enabled = true
12 | use_first_as_mask = false
13 | seed_value = 3
14 | strength = 0.003
15 | fractal_octaves = 4
16 | period = 0.2
17 | frequency = 0.6
18 | center = Vector3(1, 1, 0)
19 |
20 | [sub_resource type="Resource" id="2"]
21 | resource_name = "Details & Peaks"
22 | script = ExtResource("3")
23 | enabled = true
24 | use_first_as_mask = true
25 | seed_value = 13
26 | strength = 2.0
27 | fractal_octaves = 4
28 | period = 0.1
29 | frequency = 0.6
30 | center = Vector3(0.133, 0, 0)
31 |
32 | [sub_resource type="Resource" id="3"]
33 | resource_name = "Fine Detail"
34 | script = ExtResource("3")
35 | enabled = true
36 | use_first_as_mask = true
37 | seed_value = 0
38 | strength = 0.05
39 | fractal_octaves = 4
40 | period = 0.001
41 | frequency = 0.6
42 | center = Vector3(1, 2, 3)
43 |
44 | [sub_resource type="Resource" id="4"]
45 | script = ExtResource("1")
46 | noise_generators = [SubResource("1"), SubResource("2"), SubResource("3")]
47 |
48 | [resource]
49 | script = ExtResource("4")
50 | resolution = 77
51 | radius = 150.0
52 | has_water = false
53 | has_atmosphere = true
54 | has_collisions = true
55 | atmosphere_thickness = 8.0
56 | atmosphere_density = 0.02
57 | shape_generator = SubResource("4")
58 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/planet_presets/earthlike_planet_settings.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" script_class="PlanetSettings" load_steps=10 format=3 uid="uid://dd88lsn35g60e"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/shape_generator.gd" id="1"]
4 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/ridged_noise_generator.gd" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/noise_generator.gd" id="3"]
6 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/planet_settings.gd" id="4"]
7 |
8 | [sub_resource type="Resource" id="1"]
9 | resource_name = "Continents"
10 | script = ExtResource("3")
11 | enabled = true
12 | use_first_as_mask = false
13 | seed_value = 9
14 | strength = 0.005
15 | fractal_octaves = 4
16 | period = 0.4
17 | frequency = 0.6
18 | center = Vector3(-1, 0, 1)
19 |
20 | [sub_resource type="Resource" id="2"]
21 | resource_name = "Large Ridges"
22 | script = ExtResource("2")
23 | enabled = true
24 | use_first_as_mask = true
25 | seed_value = 4
26 | strength = 4.0
27 | fractal_octaves = 4
28 | period = 0.5
29 | frequency = 0.6
30 | center = Vector3(0, 0, 0)
31 |
32 | [sub_resource type="Resource" id="3"]
33 | resource_name = "Coarse Detail"
34 | script = ExtResource("3")
35 | enabled = true
36 | use_first_as_mask = true
37 | seed_value = 1
38 | strength = 5.0
39 | fractal_octaves = 4
40 | period = 0.03
41 | frequency = 0.6
42 | center = Vector3(0, 0, 0)
43 |
44 | [sub_resource type="Resource" id="4"]
45 | resource_name = "Fine Detail"
46 | script = ExtResource("3")
47 | enabled = true
48 | use_first_as_mask = true
49 | seed_value = 123
50 | strength = 0.1
51 | fractal_octaves = 4
52 | period = 0.0005
53 | frequency = 0.6
54 | center = Vector3(0, 0, 0)
55 |
56 | [sub_resource type="Resource" id="5"]
57 | script = ExtResource("1")
58 | noise_generators = [SubResource("1"), SubResource("2"), SubResource("3"), SubResource("4")]
59 |
60 | [resource]
61 | script = ExtResource("4")
62 | resolution = 60
63 | radius = 200.0
64 | has_water = true
65 | has_atmosphere = true
66 | has_collisions = true
67 | atmosphere_thickness = 10.0
68 | atmosphere_density = 0.02
69 | shape_generator = SubResource("5")
70 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/planet_presets/moon_settings.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" script_class="PlanetSettings" load_steps=8 format=3 uid="uid://c15gyg7nxeyuj"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/shape_generator.gd" id="1"]
4 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/ridged_noise_generator.gd" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/noise_generator.gd" id="3"]
6 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/planet_settings.gd" id="4"]
7 |
8 | [sub_resource type="Resource" id="1"]
9 | resource_name = "Continents"
10 | script = ExtResource("3")
11 | enabled = true
12 | use_first_as_mask = false
13 | seed_value = 0
14 | strength = 0.02
15 | fractal_octaves = 4
16 | period = 0.5
17 | frequency = 0.6
18 | center = Vector3(0, 0, 0)
19 |
20 | [sub_resource type="Resource" id="2"]
21 | resource_name = "Large Ridges"
22 | script = ExtResource("2")
23 | enabled = true
24 | use_first_as_mask = false
25 | seed_value = 0
26 | strength = 0.01
27 | fractal_octaves = 4
28 | period = 0.2
29 | frequency = 0.6
30 | center = Vector3(0, 0, 0)
31 |
32 | [sub_resource type="Resource" id="3"]
33 | script = ExtResource("1")
34 | noise_generators = [SubResource("1"), SubResource("2")]
35 |
36 | [resource]
37 | script = ExtResource("4")
38 | resolution = 40
39 | radius = 30.0
40 | has_water = false
41 | has_atmosphere = false
42 | has_collisions = true
43 | atmosphere_thickness = 1.1
44 | atmosphere_density = 0.1
45 | shape_generator = SubResource("3")
46 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/planet_presets/sun_settings.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" load_steps=6 format=3 uid="uid://rqk4xpb2vqwo"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/noise_generator.gd" id="1"]
4 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/shape_generator.gd" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/planet_settings.gd" id="3"]
6 |
7 | [sub_resource type="Resource" id="1"]
8 | resource_name = "Sun Surface"
9 | script = ExtResource("1")
10 | enabled = true
11 | use_first_as_mask = false
12 | seed_value = 0
13 | strength = 0.01
14 | fractal_octaves = 4
15 | period = 0.1
16 | persistence = 0.4
17 | center = Vector3(0, 0, 0)
18 |
19 | [sub_resource type="Resource" id="2"]
20 | script = ExtResource("2")
21 | noise_generators = [SubResource("1")]
22 |
23 | [resource]
24 | script = ExtResource("3")
25 | resolution = 21
26 | radius = 200.0
27 | has_water = false
28 | has_atmosphere = false
29 | has_collisions = true
30 | atmosphere_thickness = 1.1
31 | atmosphere_density = 0.1
32 | shape_generator = SubResource("2")
33 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/planet_presets/test_planet_settings.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Resource" script_class="PlanetSettings" load_steps=6 format=3 uid="uid://kono1hjgsisy"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/planet_settings.gd" id="1"]
4 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/noise_generator.gd" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/shape_generator.gd" id="3"]
6 |
7 | [sub_resource type="Resource" id="1"]
8 | script = ExtResource("2")
9 | enabled = true
10 | use_first_as_mask = false
11 | seed_value = 2
12 | strength = 0.03
13 | fractal_octaves = 4
14 | period = 0.25
15 | frequency = 0.6
16 | center = Vector3(0, 0, 0)
17 |
18 | [sub_resource type="Resource" id="2"]
19 | script = ExtResource("3")
20 | noise_generators = [SubResource("1")]
21 |
22 | [resource]
23 | script = ExtResource("1")
24 | resolution = 10
25 | radius = 100.0
26 | has_water = false
27 | has_atmosphere = false
28 | has_collisions = false
29 | atmosphere_thickness = 1.15
30 | atmosphere_density = 0.1
31 | shape_generator = SubResource("2")
32 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Planet Generator"
4 | description="A plugin for procedurally generating planets with LOD terrain patches using only GDScript (and multithreading).
5 | Provides easy configurability and extensibility.
6 | A demo space sandbox is included."
7 | author="Hoimar"
8 | version="0.1.0"
9 | script="plugin.gd"
10 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 | # Plugin class for Planet Generator.
4 |
5 | const CUSTOM_TYPE_NAME := "Solar System"
6 | const PLUGIN_ICON := preload("resources/icons/solar_system.svg")
7 | const SOLAR_SYSTEM_SCRIPT := preload("scripts/celestial_bodies/solar_system.gd")
8 | const PG_GLOBALS_PATH = "res://addons/hoimar.planetgen/scripts/utils/pg_globals.gd"
9 |
10 |
11 | func _enter_tree():
12 | add_autoload_singleton("PGGlobals", PG_GLOBALS_PATH)
13 | add_custom_type(
14 | CUSTOM_TYPE_NAME,
15 | "Node3D",
16 | SOLAR_SYSTEM_SCRIPT,
17 | PLUGIN_ICON
18 | )
19 |
20 |
21 | func _exit_tree():
22 | remove_custom_type(CUSTOM_TYPE_NAME)
23 | remove_autoload_singleton("PGGlobals")
24 |
25 |
26 | func _get_plugin_icon() -> Texture2D:
27 | return PLUGIN_ICON
28 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/icons/globe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/icons/globe.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://qe5nwadsc2gp"
6 | path="res://.godot/imported/globe.svg-7a5df4a968e4f066c9513929629f909b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/hoimar.planetgen/resources/icons/globe.svg"
14 | dest_files=["res://.godot/imported/globe.svg-7a5df4a968e4f066c9513929629f909b.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/hoimar.planetgen/resources/icons/planet.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/icons/planet.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b7ln8bpi33ntm"
6 | path="res://.godot/imported/planet.svg-daaec8c8acdc9736b51f266d2823fcb0.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/hoimar.planetgen/resources/icons/planet.svg"
14 | dest_files=["res://.godot/imported/planet.svg-daaec8c8acdc9736b51f266d2823fcb0.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/hoimar.planetgen/resources/icons/solar_system.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/icons/solar_system.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bmywxfa1kgjau"
6 | path="res://.godot/imported/solar_system.svg-8c481e13a31098666c01bba83c55205b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/hoimar.planetgen/resources/icons/solar_system.svg"
14 | dest_files=["res://.godot/imported/solar_system.svg-8c481e13a31098666c01bba83c55205b.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/hoimar.planetgen/resources/icons/sun.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/icons/sun.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://b5shftr5vgekl"
6 | path="res://.godot/imported/sun.svg-4c192a061e6dac1f88263dd4bfeb6f42.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/hoimar.planetgen/resources/icons/sun.svg"
14 | dest_files=["res://.godot/imported/sun.svg-4c192a061e6dac1f88263dd4bfeb6f42.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/hoimar.planetgen/resources/materials/alien_planet_material.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://byxwrfsxs3aot"]
2 |
3 | [sub_resource type="Gradient" id="1"]
4 | offsets = PackedFloat32Array(0.353982, 0.371681, 0.480826, 0.622419, 0.781711, 0.882006)
5 | colors = PackedColorArray(1, 0.7245, 0.13, 1, 0.30127, 0.27375, 0.209476, 1, 0.300682, 0.254965, 0.250785, 1, 0.461426, 0.304613, 0.450972, 1, 0.3213, 0.51, 0.37162, 1, 0.4176, 0.72, 0.62928, 1)
6 |
7 | [sub_resource type="GradientTexture2D" id="2"]
8 | gradient = SubResource("1")
9 |
10 | [resource]
11 | albedo_texture = SubResource("2")
12 | metallic_specular = 0.08
13 | roughness = 0.75
14 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/atmosphere.gdshader:
--------------------------------------------------------------------------------
1 | shader_type spatial;
2 | render_mode unshaded;//, depth_draw_opaque;
3 |
4 | // Some refs:
5 | // https://www.youtube.com/watch?v=OCZTVpfMSys
6 |
7 | uniform float u_planet_radius = 1.0;
8 | uniform float u_atmosphere_height = 0.1;
9 | uniform bool u_clip_mode = false;
10 | uniform vec4 u_day_color0 : source_color = vec4(0.5, 0.8, 1.0, 1.0);
11 | uniform vec4 u_day_color1 : source_color = vec4(0.5, 0.8, 1.0, 1.0);
12 | uniform vec4 u_night_color0 : source_color = vec4(0.2, 0.4, 0.8, 1.0);
13 | uniform vec4 u_night_color1 : source_color = vec4(0.2, 0.4, 0.8, 1.0);
14 | uniform vec3 u_sun_position = vec3(0.0, 0.0, 0.0);
15 | uniform float u_density = 0.2;
16 | uniform float u_attenuation_distance = 0.0;
17 | uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, repeat_disable, filter_nearest;
18 |
19 | varying vec3 v_planet_center_viewspace;
20 | varying vec3 v_sun_center_viewspace;
21 |
22 | // x = first hit, y = second hit. Equal if not hit.
23 | vec2 ray_sphere(vec3 center, float radius, vec3 ray_origin, vec3 ray_dir) {
24 | float t = max(dot(center - ray_origin, ray_dir), 0.0);
25 | float y = length(center - (ray_origin + ray_dir * t));
26 | // TODO y * y means we can use a squared length
27 | float x = sqrt(max(radius * radius - y * y, 0.0));
28 | return vec2(t - x, t + x);
29 | }
30 |
31 | // < 0 or infinite: doesn't hit the plane
32 | // > 0: hits the plane
33 | float ray_plane(vec3 plane_pos, vec3 plane_dir, vec3 ray_origin, vec3 ray_dir) {
34 | float dp = dot(plane_dir, ray_dir);
35 | return dot(plane_pos - ray_origin, plane_dir) / (dp + 0.0001);
36 | }
37 |
38 | float get_atmo_factor(vec3 ray_origin, vec3 ray_dir, vec3 planet_center,
39 | float t_begin, float t_end, vec3 sun_dir, out float light_factor) {
40 |
41 | int steps = 16;
42 | float inv_steps = 1.0 / float(steps);
43 | float step_len = (t_end - t_begin) * inv_steps;
44 | vec3 stepv = step_len * ray_dir;
45 | vec3 pos = ray_origin + ray_dir * t_begin;
46 | float distance_from_ray_origin = t_begin;
47 | float attenuation_distance_inv = 1.0 / u_attenuation_distance;
48 |
49 | float factor = 1.0;
50 | float light_sum = 0.0;
51 |
52 | // TODO Some stuff can be optimized
53 | for (int i = 0; i < steps; ++i) {
54 | float d = distance(pos, planet_center);
55 | vec3 up = (pos - planet_center) / d;
56 | float sd = d - u_planet_radius;
57 | float h = clamp(sd / u_atmosphere_height, 0.0, 1.0);
58 | float y = 1.0 - h;
59 |
60 | float density = y * y * y * u_density;
61 |
62 | density *= min(1.0, attenuation_distance_inv * distance_from_ray_origin);
63 | distance_from_ray_origin += step_len;
64 |
65 | float light = clamp(1.2 * dot(sun_dir, up) + 0.5, 0.0, 1.0);
66 | light = light * light;
67 |
68 | light_sum += light * inv_steps;
69 | factor *= (1.0 - density * step_len);
70 | pos += stepv;
71 | }
72 |
73 | light_factor = light_sum;
74 | return 1.0 - factor;
75 | }
76 |
77 | void vertex() {
78 | // Note:
79 | // When the camera is far enough, we should actually move the quad to be on top of the planet,
80 | // and not in front of the near plane, because otherwise it's harder to layer two
81 | // atmospheres on screen and have them properly sorted. Besides, it could reduce pixel cost.
82 | // So this is an option.
83 | if (u_clip_mode) {
84 | POSITION = vec4(VERTEX, 1.0);
85 | } else {
86 | // Godot expects us to fill in `POSITION` if we mention it at all in `vertex()`,
87 | // so we have to set it in the `else` block too otherwise nothing will show up
88 | POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
89 | // Billboard doesn't actually work well
90 | //VERTEX.z += 1.0;
91 | //MODELVIEW_MATRIX = INV_CAMERA_MATRIX *
92 | // mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);
93 | }
94 |
95 | vec4 world_pos = MODEL_MATRIX * vec4(0, 0, 0, 1);
96 | v_planet_center_viewspace = (VIEW_MATRIX * world_pos).xyz;
97 | v_sun_center_viewspace = (VIEW_MATRIX * vec4(u_sun_position, 1.0)).xyz;
98 | }
99 |
100 | void fragment() {
101 | // TODO Is depth texture really needed in the end?
102 | float nonlinear_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
103 | vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, nonlinear_depth);
104 | vec4 view_coords = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
105 | //view_coords.xyz /= view_coords.w;
106 | //float linear_depth = -view_coords.z; // Not what I want because it changes when looking around
107 | vec4 world_coords = INV_VIEW_MATRIX * view_coords;
108 | vec3 pos_world = world_coords.xyz / world_coords.w;
109 | vec3 cam_pos_world = (INV_VIEW_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
110 | // I wonder if there is a faster way to get to that distance...
111 | float linear_depth = distance(cam_pos_world, pos_world);
112 |
113 | // We'll evaluate the atmosphere in view space
114 | vec3 ray_origin = vec3(0.0, 0.0, 0.0);
115 | vec3 ray_dir = normalize(view_coords.xyz - ray_origin);
116 |
117 | float atmosphere_radius = u_planet_radius + u_atmosphere_height;
118 | vec2 rs_atmo = ray_sphere(v_planet_center_viewspace, atmosphere_radius, ray_origin, ray_dir);
119 |
120 | // TODO if we run this shader in a double-clip scenario,
121 | // we have to account for the near and far clips properly, so they can be composed seamlessly
122 |
123 | if (rs_atmo.x != rs_atmo.y) {
124 | float t_begin = max(rs_atmo.x, 0.0);
125 | float t_end = max(rs_atmo.y, 0.0);
126 | t_end = min(t_end, linear_depth);
127 |
128 | vec3 sun_dir = normalize(v_sun_center_viewspace - v_planet_center_viewspace);
129 | float light_factor;
130 | float atmo_factor = get_atmo_factor(
131 | ray_origin, ray_dir, v_planet_center_viewspace, t_begin, t_end, sun_dir, light_factor);
132 |
133 | vec3 night_col = mix(u_night_color0.rgb, u_night_color1.rgb, atmo_factor);
134 | vec3 day_col = mix(u_day_color0.rgb, u_day_color1.rgb, atmo_factor);
135 |
136 | vec3 col = mix(night_col, day_col, clamp(light_factor * 2.0 + 0.0, 0.0, 1.0));
137 |
138 | ALBEDO = col;
139 | ALPHA = clamp(atmo_factor, 0.0, 1.0);
140 |
141 | } else {
142 | // DEBUG
143 | //ALPHA = 0.2;
144 | discard;
145 | }
146 | }
147 |
148 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/atmosphere.shader:
--------------------------------------------------------------------------------
1 | shader_type spatial;
2 | render_mode unshaded;//, depth_draw_alpha_prepass;
3 |
4 | // Some refs:
5 | // https://www.youtube.com/watch?v=OCZTVpfMSys
6 |
7 | uniform float u_planet_radius = 1.0;
8 | uniform float u_atmosphere_height = 0.1;
9 | uniform bool u_clip_mode = false;
10 | uniform vec4 u_day_color0 : hint_color = vec4(0.5, 0.8, 1.0, 1.0);
11 | uniform vec4 u_day_color1 : hint_color = vec4(0.5, 0.8, 1.0, 1.0);
12 | uniform vec4 u_night_color0 : hint_color = vec4(0.2, 0.4, 0.8, 1.0);
13 | uniform vec4 u_night_color1 : hint_color = vec4(0.2, 0.4, 0.8, 1.0);
14 | uniform vec3 u_sun_position = vec3(0.0, 0.0, 0.0);
15 | uniform float u_density = 0.2;
16 | uniform float u_attenuation_distance = 0.0;
17 |
18 | varying vec3 v_planet_center_viewspace;
19 | varying vec3 v_sun_center_viewspace;
20 |
21 | // x = first hit, y = second hit. Equal if not hit.
22 | vec2 ray_sphere(vec3 center, float radius, vec3 ray_origin, vec3 ray_dir) {
23 | float t = max(dot(center - ray_origin, ray_dir), 0.0);
24 | float y = length(center - (ray_origin + ray_dir * t));
25 | // TODO y * y means we can use a squared length
26 | float x = sqrt(max(radius * radius - y * y, 0.0));
27 | return vec2(t - x, t + x);
28 | }
29 |
30 | // < 0 or infinite: doesn't hit the plane
31 | // > 0: hits the plane
32 | float ray_plane(vec3 plane_pos, vec3 plane_dir, vec3 ray_origin, vec3 ray_dir) {
33 | float dp = dot(plane_dir, ray_dir);
34 | return dot(plane_pos - ray_origin, plane_dir) / (dp + 0.0001);
35 | }
36 |
37 | float get_atmo_factor(vec3 ray_origin, vec3 ray_dir, vec3 planet_center,
38 | float t_begin, float t_end, vec3 sun_dir, out float light_factor) {
39 |
40 | int steps = 16;
41 | float inv_steps = 1.0 / float(steps);
42 | float step_len = (t_end - t_begin) * inv_steps;
43 | vec3 stepv = step_len * ray_dir;
44 | vec3 pos = ray_origin + ray_dir * t_begin;
45 | float distance_from_ray_origin = t_begin;
46 | float attenuation_distance_inv = 1.0 / u_attenuation_distance;
47 |
48 | float factor = 1.0;
49 | float light_sum = 0.0;
50 |
51 | // TODO Some stuff can be optimized
52 | for (int i = 0; i < steps; ++i) {
53 | float d = distance(pos, planet_center);
54 | vec3 up = (pos - planet_center) / d;
55 | float sd = d - u_planet_radius;
56 | float h = clamp(sd / u_atmosphere_height, 0.0, 1.0);
57 | float y = 1.0 - h;
58 |
59 | float density = y * y * y * u_density;
60 |
61 | density *= min(1.0, attenuation_distance_inv * distance_from_ray_origin);
62 | distance_from_ray_origin += step_len;
63 |
64 | float light = clamp(1.2 * dot(sun_dir, up) + 0.5, 0.0, 1.0);
65 | light = light * light;
66 |
67 | light_sum += light * inv_steps;
68 | factor *= (1.0 - density * step_len);
69 | pos += stepv;
70 | }
71 |
72 | light_factor = light_sum;
73 | return 1.0 - factor;
74 | }
75 |
76 | void vertex() {
77 | // Note:
78 | // When the camera is far enough, we should actually move the quad to be on top of the planet,
79 | // and not in front of the near plane, because otherwise it's harder to layer two
80 | // atmospheres on screen and have them properly sorted. Besides, it could reduce pixel cost.
81 | // So this is an option.
82 | if (u_clip_mode) {
83 | POSITION = vec4(VERTEX, 1.0);
84 | } else {
85 | // Godot expects us to fill in `POSITION` if we mention it at all in `vertex()`,
86 | // so we have to set it in the `else` block too otherwise nothing will show up
87 | POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
88 | // Billboard doesn't actually work well
89 | //VERTEX.z += 1.0;
90 | //MODELVIEW_MATRIX = INV_CAMERA_MATRIX *
91 | // mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);
92 | }
93 |
94 | vec4 world_pos = WORLD_MATRIX * vec4(0, 0, 0, 1);
95 | v_planet_center_viewspace = (INV_CAMERA_MATRIX * world_pos).xyz;
96 | v_sun_center_viewspace = (INV_CAMERA_MATRIX * vec4(u_sun_position, 1.0)).xyz;
97 | }
98 |
99 | void fragment() {
100 | // TODO Is depth texture really needed in the end?
101 | float nonlinear_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
102 | vec3 ndc = vec3(SCREEN_UV, nonlinear_depth) * 2.0 - 1.0;
103 | vec4 view_coords = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
104 | //view_coords.xyz /= view_coords.w;
105 | //float linear_depth = -view_coords.z; // Not what I want because it changes when looking around
106 | vec4 world_coords = CAMERA_MATRIX * view_coords;
107 | vec3 pos_world = world_coords.xyz / world_coords.w;
108 | vec3 cam_pos_world = (CAMERA_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
109 | // I wonder if there is a faster way to get to that distance...
110 | float linear_depth = distance(cam_pos_world, pos_world);
111 |
112 | // We'll evaluate the atmosphere in view space
113 | vec3 ray_origin = vec3(0.0, 0.0, 0.0);
114 | vec3 ray_dir = normalize(view_coords.xyz - ray_origin);
115 |
116 | float atmosphere_radius = u_planet_radius + u_atmosphere_height;
117 | vec2 rs_atmo = ray_sphere(v_planet_center_viewspace, atmosphere_radius, ray_origin, ray_dir);
118 |
119 | // TODO if we run this shader in a double-clip scenario,
120 | // we have to account for the near and far clips properly, so they can be composed seamlessly
121 |
122 | if (rs_atmo.x != rs_atmo.y) {
123 | float t_begin = max(rs_atmo.x, 0.0);
124 | float t_end = max(rs_atmo.y, 0.0);
125 | t_end = min(t_end, linear_depth);
126 |
127 | vec3 sun_dir = normalize(v_sun_center_viewspace - v_planet_center_viewspace);
128 | float light_factor;
129 | float atmo_factor = get_atmo_factor(
130 | ray_origin, ray_dir, v_planet_center_viewspace, t_begin, t_end, sun_dir, light_factor);
131 |
132 | vec3 night_col = mix(u_night_color0.rgb, u_night_color1.rgb, atmo_factor);
133 | vec3 day_col = mix(u_day_color0.rgb, u_day_color1.rgb, atmo_factor);
134 |
135 | vec3 col = mix(night_col, day_col, clamp(light_factor * 2.0 + 0.0, 0.0, 1.0));
136 |
137 | ALBEDO = col;
138 | ALPHA = clamp(atmo_factor, 0.0, 1.0);
139 |
140 | } else {
141 | // DEBUG
142 | //ALPHA = 0.2;
143 | discard;
144 | }
145 | }
146 |
147 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/atmosphere.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="ShaderMaterial" load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/hoimar.planetgen/resources/materials/atmosphere.gdshader" type="Shader" id=1]
4 |
5 | [resource]
6 | render_priority = 1
7 | shader = ExtResource( 1 )
8 | shader_param/u_planet_radius = 1.0
9 | shader_param/u_atmosphere_height = 0.1
10 | shader_param/u_clip_mode = false
11 | shader_param/u_day_color0 = Color( 0.5, 0.8, 1, 1 )
12 | shader_param/u_day_color1 = Color( 0.5, 0.8, 1, 1 )
13 | shader_param/u_night_color0 = Color( 0.2, 0.4, 0.8, 1 )
14 | shader_param/u_night_color1 = Color( 0.2, 0.4, 0.8, 1 )
15 | shader_param/u_sun_position = Vector3( 0, 0, 0 )
16 | shader_param/u_density = 0.2
17 | shader_param/u_attenuation_distance = 0.0
18 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/earthlike_planet_material.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://b1jwk81h16hlg"]
2 |
3 | [sub_resource type="Gradient" id="1"]
4 | offsets = PackedFloat32Array(0, 0.408269, 0.496, 0.5, 0.504, 0.569322, 0.687316, 0.778761, 0.867257)
5 | colors = PackedColorArray(0.160784, 0.180392, 0.192157, 1, 0.180392, 0.301961, 0.411765, 1, 0.203922, 0.388235, 0.45098, 1, 0.835938, 0.76165, 0.538788, 1, 0.625797, 0.756863, 0.392157, 1, 0.441538, 0.575195, 0.276363, 1, 0.317647, 0.388235, 0.25098, 1, 0.412109, 0.385611, 0.254349, 1, 0.887207, 0.878932, 0.835222, 1)
6 |
7 | [sub_resource type="GradientTexture2D" id="2"]
8 | gradient = SubResource("1")
9 |
10 | [resource]
11 | albedo_texture = SubResource("2")
12 | roughness = 0.9
13 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/moon_material.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://8wwbbtllcisy"]
2 |
3 | [sub_resource type="Gradient" id="1"]
4 | offsets = PackedFloat32Array(0.439528, 1)
5 | colors = PackedColorArray(0, 0, 0, 1, 0.714844, 0.696955, 0.658997, 1)
6 |
7 | [sub_resource type="GradientTexture2D" id="2"]
8 | gradient = SubResource("1")
9 |
10 | [resource]
11 | albedo_texture = SubResource("2")
12 | metallic_specular = 0.06
13 | roughness = 0.75
14 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/sun_bloom_material.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="ShaderMaterial" load_steps=9 format=3 uid="uid://5rm3b3klqa6f"]
2 |
3 | [sub_resource type="VisualShaderNodeVectorOp" id="1"]
4 | output_port_for_preview = 0
5 | operator = 2
6 |
7 | [sub_resource type="VisualShaderNodeExpression" id="2"]
8 | size = Vector2(250, 150)
9 | expression = "output = 1.0 - pow(cos(3.142 * x / 2.0), 3.5);"
10 |
11 | [sub_resource type="VisualShaderNodeColorParameter" id="3"]
12 | parameter_name = "sun_color"
13 |
14 | [sub_resource type="VisualShaderNodeInput" id="4"]
15 | input_name = "uv"
16 |
17 | [sub_resource type="VisualShaderNodeVectorDistance" id="5"]
18 | default_input_values = [0, Vector3(0, 0, 0), 1, Vector3(0.5, 0.5, 0)]
19 |
20 | [sub_resource type="VisualShaderNodeFloatOp" id="6"]
21 | output_port_for_preview = 0
22 | default_input_values = [0, 1.0, 1, 0.0]
23 | operator = 1
24 |
25 | [sub_resource type="VisualShaderNodeFloatOp" id="7"]
26 | output_port_for_preview = 0
27 | default_input_values = [0, 0.0, 1, 4.7]
28 | operator = 5
29 |
30 | [sub_resource type="VisualShader" id="8"]
31 | code = "shader_type spatial;
32 | render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx, unshaded;
33 |
34 | uniform vec4 sun_color : source_color;
35 |
36 |
37 |
38 | void fragment() {
39 | // ColorParameter:15
40 | vec4 n_out15p0 = sun_color;
41 |
42 |
43 | // Input:2
44 | vec2 n_out2p0 = UV;
45 |
46 |
47 | // Distance:3
48 | vec3 n_in3p1 = vec3(0.50000, 0.50000, 0.00000);
49 | float n_out3p0 = distance(vec3(n_out2p0, 0.0), n_in3p1);
50 |
51 |
52 | // FloatOp:7
53 | float n_in7p0 = 1.00000;
54 | float n_out7p0 = n_in7p0 - n_out3p0;
55 |
56 |
57 | // FloatOp:8
58 | float n_in8p1 = 4.70000;
59 | float n_out8p0 = pow(n_out7p0, n_in8p1);
60 |
61 |
62 | float n_out14p0;
63 | // Expression:14
64 | n_out14p0 = 0.0;
65 | {
66 | n_out14p0 = 1.0 - pow(cos(3.142 * n_out8p0 / 2.0), 3.5);
67 | }
68 |
69 |
70 | // VectorOp:10
71 | vec3 n_out10p0 = vec3(n_out15p0.xyz) * vec3(n_out14p0);
72 |
73 |
74 | // Output:0
75 | ALBEDO = n_out10p0;
76 | ALPHA = n_out14p0;
77 |
78 |
79 | }
80 | "
81 | graph_offset = Vector2(-61, 7.25)
82 | flags/unshaded = true
83 | nodes/fragment/0/position = Vector2(780, 340)
84 | nodes/fragment/2/node = SubResource("4")
85 | nodes/fragment/2/position = Vector2(-660, 320)
86 | nodes/fragment/3/node = SubResource("5")
87 | nodes/fragment/3/position = Vector2(-500, 320)
88 | nodes/fragment/7/node = SubResource("6")
89 | nodes/fragment/7/position = Vector2(-320, 320)
90 | nodes/fragment/8/node = SubResource("7")
91 | nodes/fragment/8/position = Vector2(-140, 320)
92 | nodes/fragment/10/node = SubResource("1")
93 | nodes/fragment/10/position = Vector2(580, 160)
94 | nodes/fragment/14/node = SubResource("2")
95 | nodes/fragment/14/position = Vector2(40, 320)
96 | nodes/fragment/14/size = Vector2(250, 150)
97 | nodes/fragment/14/input_ports = "0,0,x;"
98 | nodes/fragment/14/output_ports = "0,0,output;"
99 | nodes/fragment/14/expression = "output = 1.0 - pow(cos(3.142 * x / 2.0), 3.5);"
100 | nodes/fragment/15/node = SubResource("3")
101 | nodes/fragment/15/position = Vector2(340, 160)
102 | nodes/fragment/connections = PackedInt32Array(2, 0, 3, 0, 3, 0, 7, 1, 7, 0, 8, 0, 10, 0, 0, 0, 14, 0, 10, 1, 8, 0, 14, 0, 14, 0, 0, 1, 15, 0, 10, 0)
103 |
104 | [resource]
105 | render_priority = 0
106 | shader = SubResource("8")
107 | shader_parameter/sun_color = Color(1, 1, 0.94902, 1)
108 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/sun_material.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://cbrhatww1bo6y"]
2 |
3 | [sub_resource type="Gradient" id="1"]
4 | offsets = PackedFloat32Array(0.2334, 0.830986)
5 | colors = PackedColorArray(2, 1.14, 0.76, 1, 1.08, 1.12, 0.99, 1)
6 |
7 | [sub_resource type="GradientTexture2D" id="2"]
8 | gradient = SubResource("1")
9 |
10 | [resource]
11 | transparency = 2
12 | alpha_scissor_threshold = 0.98
13 | alpha_antialiasing_mode = 0
14 | shading_mode = 0
15 | albedo_texture = SubResource("2")
16 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/test_planet_material.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" load_steps=3 format=2]
2 |
3 | [sub_resource type="Gradient" id=1]
4 | offsets = PackedFloat32Array( 0.19174, 0.525074, 0.542773, 0.566372, 0.811209, 0.973451 )
5 | colors = PackedColorArray( 0.252136, 0.373553, 0.448242, 1, 0.25098, 0.34902, 0.447059, 1, 0.515625, 0.427694, 0.259827, 1, 0.265922, 0.31077, 0.0453105, 1, 0.398926, 0.384965, 0.296078, 1, 0.842773, 0.765133, 0.595867, 1 )
6 |
7 | [sub_resource type="GradientTexture2D" id=2]
8 | gradient = SubResource( 1 )
9 |
10 | [resource]
11 | albedo_texture = SubResource( 2 )
12 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/water.gdshader:
--------------------------------------------------------------------------------
1 | shader_type spatial;
2 |
3 | render_mode specular_schlick_ggx, cull_disabled;
4 |
5 | uniform vec4 albedo : source_color;
6 | uniform float proximity_fade_distance;
7 | uniform float planet_radius;
8 | uniform sampler2D texture_refraction;
9 | uniform float refraction : hint_range(-16,16);
10 | uniform vec4 refraction_texture_channel;
11 | uniform sampler2D texture_normal : hint_normal;
12 | uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable, filter_nearest;
13 | uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, repeat_disable, filter_nearest;
14 |
15 | varying vec3 cam_position;
16 |
17 | void vertex() {
18 | UV = UV * 750.0 + vec2(TIME + sin(TIME * 3.0) * 0.07) * 0.1;
19 | cam_position = MODELVIEW_MATRIX[3].xyz;
20 | }
21 |
22 | void fragment() {
23 | vec2 base_uv = UV;
24 | ALBEDO = albedo.rgb;
25 | ROUGHNESS = 0.1;
26 | SPECULAR = 0.7;
27 | NORMAL_MAP = texture(texture_normal, base_uv).rgb;
28 | NORMAL_MAP_DEPTH = 0.15;
29 | // Refraction.
30 | vec3 ref_normal = normalize(mix(
31 | NORMAL,
32 | TANGENT * NORMAL_MAP.x + BINORMAL * NORMAL_MAP.y + NORMAL * NORMAL_MAP.z,
33 | NORMAL_MAP_DEPTH));
34 | vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction, base_uv), vec4(1.0, 0.0, 0.0, 0.0)) * refraction;
35 | float ref_amount = 1.0 - albedo.a;
36 | EMISSION += textureLod(SCREEN_TEXTURE, ref_ofs, ROUGHNESS * 8.0).rgb * ref_amount;
37 | ALBEDO *= 1.0 - ref_amount;
38 |
39 | // Proximity fade.
40 | float depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;
41 | vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth_tex * 2.0 - 1.0, 1.0);
42 | world_pos.xyz /= world_pos.w;
43 | ALPHA *= clamp(1.0 - smoothstep(world_pos.z + proximity_fade_distance, world_pos.z, VERTEX.z), 0.0, 1.0);
44 |
45 | // Fade out in the distance.
46 | ALPHA *= clamp(smoothstep(planet_radius*3.3, planet_radius*1.7, length(cam_position)), 0.0, 1.0);
47 | }
48 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/water.shader:
--------------------------------------------------------------------------------
1 | shader_type spatial;
2 |
3 | render_mode specular_schlick_ggx, cull_disabled;
4 |
5 | uniform vec4 albedo : hint_color;
6 | uniform float proximity_fade_distance;
7 | uniform float planet_radius;
8 | uniform sampler2D texture_refraction;
9 | uniform float refraction : hint_range(-16,16);
10 | uniform vec4 refraction_texture_channel;
11 | uniform sampler2D texture_normal : hint_normal;
12 |
13 | varying vec3 cam_position;
14 |
15 | void vertex() {
16 | UV = UV * 750.0 + vec2(TIME + sin(TIME * 3.0) * 0.07) * 0.1;
17 | cam_position = MODELVIEW_MATRIX[3].xyz;
18 | }
19 |
20 | void fragment() {
21 | vec2 base_uv = UV;
22 | ALBEDO = albedo.rgb;
23 | ROUGHNESS = 0.1;
24 | SPECULAR = 0.7;
25 | NORMALMAP = texture(texture_normal, base_uv).rgb;
26 | NORMALMAP_DEPTH = 0.15;
27 | // Refraction.
28 | vec3 ref_normal = normalize(mix(
29 | NORMAL,
30 | TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,
31 | NORMALMAP_DEPTH));
32 | vec2 ref_ofs = SCREEN_UV - ref_normal.xy *
33 | dot(texture(texture_refraction, base_uv), vec4(1.0, 0.0, 0.0, 0.0)) * refraction;
34 | float ref_amount = 1.0 - albedo.a;
35 | EMISSION += textureLod(SCREEN_TEXTURE, ref_ofs, ROUGHNESS * 8.0).rgb * ref_amount;
36 | ALBEDO *= 1.0 - ref_amount;
37 |
38 | // Proximity fade.
39 | float depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;
40 | vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth_tex * 2.0 - 1.0, 1.0);
41 | world_pos.xyz /= world_pos.w;
42 | ALPHA *= clamp(1.0 - smoothstep(world_pos.z + proximity_fade_distance, world_pos.z, VERTEX.z), 0.0, 1.0);
43 |
44 | // Fade out in the distance.
45 | ALPHA *= clamp(smoothstep(planet_radius*3.3, planet_radius*1.7, length(cam_position)), 0.0, 1.0);
46 | }
47 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/materials/water.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://d082qpq5nmg6j"]
2 |
3 | [ext_resource type="Shader" path="res://addons/hoimar.planetgen/resources/materials/water.gdshader" id="1"]
4 | [ext_resource type="Texture2D" uid="uid://ch1xsvnhwyfk3" path="res://addons/hoimar.planetgen/resources/textures/water_normal_2.png" id="2"]
5 |
6 | [resource]
7 | render_priority = 0
8 | shader = ExtResource("1")
9 | shader_parameter/albedo = Color(0.168627, 0.286275, 0.415686, 1)
10 | shader_parameter/proximity_fade_distance = 0.003
11 | shader_parameter/planet_radius = null
12 | shader_parameter/refraction = 0.06
13 | shader_parameter/refraction_texture_channel = Plane(1, 0, 0, 0)
14 | shader_parameter/texture_refraction = ExtResource("2")
15 | shader_parameter/texture_normal = ExtResource("2")
16 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/models/Hull.material:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/models/Hull.material
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/models/Ship.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/models/Ship.blend
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/models/Ship.blend1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/models/Ship.blend1
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/models/ship_model.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/models/ship_model.glb
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/models/ship_model.glb.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="scene"
4 | importer_version=1
5 | type="PackedScene"
6 | uid="uid://3blrgv064fyc"
7 | path="res://.godot/imported/ship_model.glb-f3fb023aa4fa1bc271754f3af7ddc41f.scn"
8 |
9 | [deps]
10 |
11 | source_file="res://addons/hoimar.planetgen/resources/models/ship_model.glb"
12 | dest_files=["res://.godot/imported/ship_model.glb-f3fb023aa4fa1bc271754f3af7ddc41f.scn"]
13 |
14 | [params]
15 |
16 | nodes/root_type="Node3D"
17 | nodes/root_name="Scene Root"
18 | nodes/apply_root_scale=true
19 | nodes/root_scale=1.0
20 | meshes/ensure_tangents=true
21 | meshes/generate_lods=true
22 | meshes/create_shadow_meshes=true
23 | meshes/light_baking=0
24 | meshes/lightmap_texel_size=0.1
25 | skins/use_named_skins=true
26 | animation/import=true
27 | animation/fps=15
28 | animation/trimming=false
29 | animation/remove_immutable_tracks=true
30 | import_script/path=""
31 | _subresources={}
32 | gltf/embedded_image_handling=1
33 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/models/thruster_particle_mesh.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="QuadMesh" load_steps=3 format=3 uid="uid://d050u03qakshw"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://ca61u24mwicg6" path="res://addons/hoimar.planetgen/resources/textures/thruster_particle.png" id="1"]
4 |
5 | [sub_resource type="StandardMaterial3D" id="1"]
6 | transparency = 1
7 | blend_mode = 1
8 | shading_mode = 0
9 | albedo_texture = ExtResource("1")
10 | disable_receive_shadows = true
11 | billboard_mode = 3
12 | particles_anim_h_frames = 1
13 | particles_anim_v_frames = 1
14 | particles_anim_loop = false
15 |
16 | [resource]
17 | material = SubResource("1")
18 | size = Vector2(0.025, 0.025)
19 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/screenshots/.gdignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/screenshots/.gdignore
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/screenshots/in_editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/screenshots/in_editor.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/screenshots/rising_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/screenshots/rising_moon.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/screenshots/terrain_from_orbit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/screenshots/terrain_from_orbit.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/space_environment.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=4 format=3 uid="uid://b0aokqtycy50o"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://dpshug5d3dous" path="res://addons/hoimar.planetgen/resources/textures/stars_hdri.png" id="1_6qafq"]
4 |
5 | [sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_2hwgy"]
6 | panorama = ExtResource("1_6qafq")
7 |
8 | [sub_resource type="Sky" id="1"]
9 | sky_material = SubResource("PanoramaSkyMaterial_2hwgy")
10 |
11 | [resource]
12 | background_mode = 2
13 | sky = SubResource("1")
14 | ambient_light_color = Color(0.992157, 0.988235, 0.988235, 1)
15 | tonemap_mode = 2
16 | glow_enabled = true
17 | glow_intensity = 0.2
18 | glow_bloom = 0.2
19 | glow_blend_mode = 1
20 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/space_hdri.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/textures/space_hdri.jpg
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/space_hdri.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dg44tifwmc1cc"
6 | path="res://.godot/imported/space_hdri.jpg-ac57c6a5a8a00c518869059531016af5.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/hoimar.planetgen/resources/textures/space_hdri.jpg"
14 | dest_files=["res://.godot/imported/space_hdri.jpg-ac57c6a5a8a00c518869059531016af5.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 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/stars_hdri.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/textures/stars_hdri.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/stars_hdri.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dpshug5d3dous"
6 | path.s3tc="res://.godot/imported/stars_hdri.png-6886a509eea4f12bfe959c3bd7ccd2bc.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/hoimar.planetgen/resources/textures/stars_hdri.png"
15 | dest_files=["res://.godot/imported/stars_hdri.png-6886a509eea4f12bfe959c3bd7ccd2bc.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/thruster_particle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/textures/thruster_particle.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/thruster_particle.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://ca61u24mwicg6"
6 | path.s3tc="res://.godot/imported/thruster_particle.png-4d020054a10a0d1c44a76722fe8836c0.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/hoimar.planetgen/resources/textures/thruster_particle.png"
15 | dest_files=["res://.godot/imported/thruster_particle.png-4d020054a10a0d1c44a76722fe8836c0.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=0
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/water_normal_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/textures/water_normal_1.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/water_normal_1.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://ctt36gugoaomr"
6 | path.s3tc="res://.godot/imported/water_normal_1.png-82c587b0b581d496acf34c005850f8d5.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/hoimar.planetgen/resources/textures/water_normal_1.png"
15 | dest_files=["res://.godot/imported/water_normal_1.png-82c587b0b581d496acf34c005850f8d5.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=1
24 | compress/channel_pack=0
25 | mipmaps/generate=false
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=1
36 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/water_normal_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hoimar/Planet-Generator/a6626b9d600eebcba909183395e34c319e49369e/addons/hoimar.planetgen/resources/textures/water_normal_2.png
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/textures/water_normal_2.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://ch1xsvnhwyfk3"
6 | path.s3tc="res://.godot/imported/water_normal_2.png-754ba5994b9d492eb67a86045b142914.s3tc.ctex"
7 | metadata={
8 | "imported_formats": ["s3tc_bptc"],
9 | "vram_texture": true
10 | }
11 |
12 | [deps]
13 |
14 | source_file="res://addons/hoimar.planetgen/resources/textures/water_normal_2.png"
15 | dest_files=["res://.godot/imported/water_normal_2.png-754ba5994b9d492eb67a86045b142914.s3tc.ctex"]
16 |
17 | [params]
18 |
19 | compress/mode=2
20 | compress/high_quality=false
21 | compress/lossy_quality=0.7
22 | compress/hdr_compression=1
23 | compress/normal_map=1
24 | compress/channel_pack=0
25 | mipmaps/generate=true
26 | mipmaps/limit=-1
27 | roughness/mode=0
28 | roughness/src_normal=""
29 | process/fix_alpha_border=true
30 | process/premult_alpha=false
31 | process/normal_map_invert_y=false
32 | process/hdr_as_srgb=false
33 | process/hdr_clamp_exposure=false
34 | process/size_limit=0
35 | detect_3d/compress_to=0
36 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/resources/thruster_particles.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="ParticleProcessMaterial" load_steps=3 format=3 uid="uid://dmsj4jjqp6mt0"]
2 |
3 | [sub_resource type="Curve" id="1"]
4 | _data = [Vector2(0, 0.522727), 0.0, 3.77273, 0, 0, Vector2(1, 0.177273), 0.0, 0.0, 0, 0]
5 | point_count = 2
6 |
7 | [sub_resource type="CurveTexture" id="2"]
8 | curve = SubResource("1")
9 |
10 | [resource]
11 | emission_shape = 2
12 | emission_sphere_radius = 1.0
13 | direction = Vector3(0, 0, 1)
14 | spread = 1.0
15 | gravity = Vector3(0, 0, 0)
16 | scale_curve = SubResource("2")
17 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/celestial_bodies/atmosphere.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://ckkxbem2k2tmx"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/atmosphere/planet_atmosphere.gd" id="1"]
4 |
5 | [node name="Atmosphere" type="Node3D"]
6 | script = ExtResource("1")
7 | shader_params/u_day_color0 = Color(0.290196, 0.388235, 0.921569, 1)
8 | shader_params/u_day_color1 = Color(0.760784, 0.901961, 1, 1)
9 | shader_params/u_night_color0 = Color(0.15, 0.1, 0.33, 1)
10 | shader_params/u_night_color1 = Color(0, 0, 0, 1)
11 | shader_params/u_density = 0.2
12 | shader_params/u_attenuation_distance = null
13 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/celestial_bodies/planet.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://dtmgyl1uf7auy"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/planet.gd" id="1"]
4 | [ext_resource type="Material" uid="uid://d082qpq5nmg6j" path="res://addons/hoimar.planetgen/resources/materials/water.tres" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/terrain_manager.gd" id="3"]
6 | [ext_resource type="PackedScene" uid="uid://ckkxbem2k2tmx" path="res://addons/hoimar.planetgen/scenes/celestial_bodies/atmosphere.tscn" id="4"]
7 |
8 | [sub_resource type="SphereMesh" id="1"]
9 | material = ExtResource("2")
10 | radius = 26.0
11 | height = 52.0
12 | radial_segments = 256
13 | rings = 128
14 |
15 | [node name="Planet" type="Node3D" groups=["planets"]]
16 | script = ExtResource("1")
17 |
18 | [node name="TerrainManager" type="Node3D" parent="."]
19 | script = ExtResource("3")
20 |
21 | [node name="Atmosphere" parent="." instance=ExtResource("4")]
22 | shader_params/u_day_color0 = Color(0.286275, 0.454902, 0.811765, 1)
23 | shader_params/u_day_color1 = Color(0.72549, 0.854902, 0.945098, 1)
24 |
25 | [node name="WaterSphere" type="MeshInstance3D" parent="."]
26 | gi_mode = 0
27 | mesh = SubResource("1")
28 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/celestial_bodies/sun.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=3 uid="uid://fqjq3odx4ugm"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/sun.gd" id="1"]
4 | [ext_resource type="PackedScene" uid="uid://dtmgyl1uf7auy" path="res://addons/hoimar.planetgen/scenes/celestial_bodies/planet.tscn" id="3"]
5 | [ext_resource type="Material" uid="uid://5rm3b3klqa6f" path="res://addons/hoimar.planetgen/resources/materials/sun_bloom_material.tres" id="5"]
6 |
7 | [sub_resource type="QuadMesh" id="1"]
8 | material = ExtResource("5")
9 | size = Vector2(3000, 2800)
10 |
11 | [node name="Sun" instance=ExtResource("3")]
12 | script = ExtResource("1")
13 |
14 | [node name="Atmosphere" parent="." index="1"]
15 | visible = false
16 |
17 | [node name="WaterSphere" parent="." index="2"]
18 | visible = false
19 |
20 | [node name="Corona" type="MeshInstance3D" parent="." index="3"]
21 | transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
22 | mesh = SubResource("1")
23 |
24 | [node name="Sunlight" type="DirectionalLight3D" parent="." index="4"]
25 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -202)
26 | shadow_enabled = true
27 | shadow_bias = 2.0
28 | directional_shadow_mode = 1
29 | directional_shadow_split_1 = 0.2
30 | directional_shadow_split_2 = 0.4
31 | directional_shadow_split_3 = 0.8
32 | directional_shadow_blend_splits = true
33 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/gui/gui.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://btubuuiux53j4"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/gui/gui.gd" id="1"]
4 |
5 | [node name="Gui" type="CanvasLayer"]
6 | script = ExtResource("1")
7 |
8 | [node name="Root" type="Control" parent="."]
9 | layout_mode = 3
10 | anchors_preset = 15
11 | anchor_right = 1.0
12 | anchor_bottom = 1.0
13 | grow_horizontal = 2
14 | grow_vertical = 2
15 |
16 | [node name="MarginContainer" type="MarginContainer" parent="Root"]
17 | layout_mode = 0
18 | anchor_right = 1.0
19 | anchor_bottom = 1.0
20 | offset_left = 0.943848
21 | offset_top = -0.943878
22 | offset_right = 0.943848
23 | offset_bottom = -0.943848
24 | theme_override_constants/margin_left = 10
25 | theme_override_constants/margin_top = 10
26 | theme_override_constants/margin_right = 10
27 | theme_override_constants/margin_bottom = 10
28 |
29 | [node name="HBoxContainer" type="HBoxContainer" parent="Root/MarginContainer"]
30 | layout_mode = 2
31 | size_flags_vertical = 0
32 | theme_override_constants/separation = 20
33 |
34 | [node name="LabelStatus" type="Label" parent="Root/MarginContainer/HBoxContainer"]
35 | custom_minimum_size = Vector2(250, 0)
36 | layout_mode = 2
37 | theme_override_constants/line_spacing = 5
38 | text = "some
39 | status
40 | lines"
41 |
42 | [node name="Control" type="HBoxContainer" parent="Root/MarginContainer/HBoxContainer"]
43 | layout_mode = 2
44 | theme_override_constants/separation = 5
45 |
46 | [node name="Label" type="Label" parent="Root/MarginContainer/HBoxContainer/Control"]
47 | layout_mode = 2
48 | size_flags_vertical = 0
49 | text = "Speed scale:"
50 |
51 | [node name="HSlider" type="HSlider" parent="Root/MarginContainer/HBoxContainer/Control"]
52 | custom_minimum_size = Vector2(200, 0)
53 | layout_mode = 2
54 | size_flags_horizontal = 3
55 | min_value = 0.0005
56 | max_value = 0.2
57 | step = 0.0005
58 | value = 0.0005
59 |
60 | [node name="LabelSpeedScale" type="Label" parent="Root/MarginContainer/HBoxContainer/Control"]
61 | layout_mode = 2
62 | size_flags_vertical = 0
63 | text = "0.0005"
64 |
65 | [connection signal="value_changed" from="Root/MarginContainer/HBoxContainer/Control/HSlider" to="." method="_on_HSlider_value_changed"]
66 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/spacecraft/player_ship.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=3 uid="uid://bqwkjkg2uk3n7"]
2 |
3 | [ext_resource type="PackedScene" uid="uid://tqasauwlfh3i" path="res://addons/hoimar.planetgen/scenes/utils/third_person_camera.tscn" id="1"]
4 | [ext_resource type="PackedScene" uid="uid://glfu5mcu6h45" path="res://addons/hoimar.planetgen/scenes/spacecraft/ship.tscn" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/spacecraft/player_controller.gd" id="3"]
6 | [ext_resource type="PackedScene" uid="uid://dc0akkwm3ke1f" path="res://addons/hoimar.planetgen/scenes/utils/origin_shifter.tscn" id="5"]
7 |
8 | [node name="Ship" groups=["player"] instance=ExtResource("2")]
9 |
10 | [node name="OriginShifter" parent="." index="2" instance=ExtResource("5")]
11 |
12 | [node name="ThirdPersonCamera" parent="." index="3" instance=ExtResource("1")]
13 |
14 | [node name="PlayerController" type="Node" parent="." index="4"]
15 | script = ExtResource("3")
16 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/terrain/terrain_patch.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://drhwm0ctf0x6t"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/terrain/terrain_patch.gd" id="1"]
4 |
5 | [node name="TerrainPatch" type="MeshInstance3D"]
6 | script = ExtResource("1")
7 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/utils/benchmark.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=7 format=3 uid="uid://djo1i5q58baeu"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/utils/benchmark.gd" id="1"]
4 | [ext_resource type="PackedScene" uid="uid://dtmgyl1uf7auy" path="res://addons/hoimar.planetgen/scenes/celestial_bodies/planet.tscn" id="2"]
5 | [ext_resource type="Resource" uid="uid://kono1hjgsisy" path="res://addons/hoimar.planetgen/planet_presets/test_planet_settings.tres" id="3"]
6 |
7 | [sub_resource type="Gradient" id="1"]
8 | colors = PackedColorArray(0, 0, 0, 1, 0.79941, 0.79941, 0.79941, 1)
9 |
10 | [sub_resource type="GradientTexture2D" id="2"]
11 | gradient = SubResource("1")
12 |
13 | [sub_resource type="StandardMaterial3D" id="3"]
14 | albedo_texture = SubResource("2")
15 |
16 | [node name="Node3D" type="Node3D"]
17 | script = ExtResource("1")
18 |
19 | [node name="Planet" parent="." instance=ExtResource("2")]
20 | settings = ExtResource("3")
21 | material = SubResource("3")
22 |
23 | [node name="Camera3D" type="Camera3D" parent="."]
24 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 600)
25 | near = 1.0
26 | far = 1000.0
27 |
28 | [node name="CanvasLayer" type="CanvasLayer" parent="."]
29 |
30 | [node name="Control" type="Control" parent="CanvasLayer"]
31 | layout_mode = 3
32 | anchors_preset = 15
33 | anchor_right = 1.0
34 | anchor_bottom = 1.0
35 |
36 | [node name="Panel" type="Panel" parent="CanvasLayer/Control"]
37 | layout_mode = 0
38 | anchor_right = 0.2
39 | anchor_bottom = 1.0
40 | size_flags_horizontal = 3
41 | size_flags_vertical = 3
42 |
43 | [node name="MarginContainer" type="MarginContainer" parent="CanvasLayer/Control/Panel"]
44 | layout_mode = 0
45 | anchor_right = 1.0
46 | anchor_bottom = 1.0
47 | theme_override_constants/margin_left = 20
48 | theme_override_constants/margin_top = 30
49 | theme_override_constants/margin_right = 20
50 | theme_override_constants/margin_bottom = 30
51 |
52 | [node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/Control/Panel/MarginContainer"]
53 | layout_mode = 2
54 | size_flags_horizontal = 3
55 | size_flags_vertical = 3
56 | theme_override_constants/separation = 20
57 |
58 | [node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/Control/Panel/MarginContainer/VBoxContainer"]
59 | layout_mode = 2
60 | theme_override_constants/separation = 20
61 |
62 | [node name="Label" type="Label" parent="CanvasLayer/Control/Panel/MarginContainer/VBoxContainer/HBoxContainer"]
63 | layout_mode = 2
64 | text = "Iterations:"
65 |
66 | [node name="SpinBox" type="SpinBox" parent="CanvasLayer/Control/Panel/MarginContainer/VBoxContainer/HBoxContainer"]
67 | layout_mode = 2
68 | size_flags_horizontal = 3
69 | min_value = 1.0
70 | max_value = 10000.0
71 | value = 10.0
72 |
73 | [node name="Button" type="Button" parent="CanvasLayer/Control/Panel/MarginContainer/VBoxContainer"]
74 | layout_mode = 2
75 | size_flags_horizontal = 3
76 | text = "Generate"
77 |
78 | [node name="Label" type="Label" parent="CanvasLayer/Control/Panel/MarginContainer/VBoxContainer"]
79 | layout_mode = 2
80 | size_flags_horizontal = 3
81 | size_flags_vertical = 0
82 |
83 | [connection signal="pressed" from="CanvasLayer/Control/Panel/MarginContainer/VBoxContainer/Button" to="." method="_on_Button_pressed"]
84 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/utils/orbiting_camera.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://c1g8kv42lnifl"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/utils/orbiting_camera.gd" id="1"]
4 |
5 | [node name="OrbitingCamera" type="Node3D"]
6 | transform = Transform3D(0.943485, 0, 0.330286, 0, 1, 0, -0.330286, 0, 0.943485, 0, 0, 0)
7 | script = ExtResource("1")
8 |
9 | [node name="Camera3D" type="Camera3D" parent="."]
10 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 50)
11 | current = true
12 | near = 2.0
13 | far = 15000.0
14 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/utils/origin_shifter.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://dc0akkwm3ke1f"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/utils/origin_shifter.gd" id="1"]
4 |
5 | [node name="OriginShifter" type="Node3D"]
6 | script = ExtResource("1")
7 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scenes/utils/third_person_camera.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://tqasauwlfh3i"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/utils/third_person_camera.gd" id="1"]
4 |
5 | [node name="ThirdPersonCamera" type="Node3D"]
6 | script = ExtResource("1")
7 |
8 | [node name="Camera3D" type="Camera3D" parent="."]
9 | transform = Transform3D(1, 0, 0, 0, 0.984808, 0.173648, 0, -0.173648, 0.984808, 0, 0.104189, 0.590885)
10 | current = true
11 | near = 0.3
12 | far = 10000.0
13 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/atmosphere/planet_atmosphere.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | # Wraps an atmosphere rendering shader.
3 | # When the camera is far, it uses a cube bounding the planet.
4 | # When the camera is close, it uses a fullscreen quad (does not work in editor).
5 | # Common parameters are exposed as properties.
6 |
7 | extends Node3D
8 |
9 | const MODE_NEAR = 0
10 | const MODE_FAR = 1
11 | const SWITCH_MARGIN_RATIO = 1.1
12 |
13 | const AtmosphereShader = preload("../../resources/materials/atmosphere.gdshader")
14 |
15 | @export var planet_radius := 1.0: set = set_planet_radius
16 | @export var atmosphere_height := 0.1: set = set_atmosphere_height
17 | @export var atmosphere_density := 0.1: set = set_atmosphere_density
18 | @export var sun_path: NodePath: set = set_sun_path
19 |
20 | var _far_mesh : BoxMesh
21 | var _near_mesh : QuadMesh
22 | var _mode := MODE_FAR
23 | var _mesh_instance : MeshInstance3D
24 |
25 | # These parameters are assigned internally,
26 | # they don't need to be shown in the list of shader params
27 | const _api_shader_params = {
28 | "u_planet_radius": true,
29 | "u_atmosphere_height": true,
30 | "u_clip_mode": false,
31 | "u_sun_position": true
32 | }
33 |
34 | func _init():
35 | var material = ShaderMaterial.new()
36 | material.shader = AtmosphereShader
37 | material.render_priority = 1
38 | _mesh_instance = MeshInstance3D.new()
39 | _mesh_instance.material_override = material
40 | _mesh_instance.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
41 | add_child(_mesh_instance)
42 |
43 | _near_mesh = QuadMesh.new()
44 | _near_mesh.size = Vector2(2.0, 2.0)
45 | _near_mesh.flip_faces = true
46 |
47 | #_far_mesh = _create_far_mesh()
48 | _far_mesh = BoxMesh.new()
49 | _far_mesh.size = Vector3(1.0, 1.0, 1.0)
50 |
51 | _mesh_instance.mesh = _far_mesh
52 |
53 | _update_cull_margin()
54 |
55 | # Setup defaults for the builtin shader
56 | # This is a workaround for https://github.com/godotengine/godot/issues/24488
57 | material.set_shader_parameter("u_day_color0", Color(0.29, 0.39, 0.92))
58 | material.set_shader_parameter("u_day_color1", Color(0.76, 0.90, 1.0))
59 | material.set_shader_parameter("u_night_color0", Color(0.15, 0.10, 0.33))
60 | material.set_shader_parameter("u_night_color1", Color(0.0, 0.0, 0.0))
61 | material.set_shader_parameter("u_density", 0.2)
62 | material.set_shader_parameter("u_sun_position", Vector3(5000, 0, 0))
63 |
64 | func _ready():
65 | var mat = _mesh_instance.material_override
66 | mat.set_shader_parameter("u_planet_radius", planet_radius)
67 | mat.set_shader_parameter("u_atmosphere_height", atmosphere_height)
68 | mat.set_shader_parameter("u_clip_mode", false)
69 |
70 | func set_shader_parameter(param_name: String, value):
71 | _mesh_instance.material_override.set_shader_parameter(param_name, value)
72 |
73 | func get_shader_parameter(param_name: String):
74 | return _mesh_instance.material_override.get_shader_parameter(param_name)
75 |
76 | # Shader parameters are exposed like this so we can have more custom shaders in the future,
77 | # without forcing to change the node/script entirely
78 | func _get_property_list():
79 | var props = []
80 | var mat = _mesh_instance.material_override
81 | var shader_params := RenderingServer.get_shader_parameter_list(mat.shader.get_rid())
82 | for p in shader_params:
83 | if _api_shader_params.has(p.name):
84 | continue
85 | var cp := {}
86 | for k in p:
87 | cp[k] = p[k]
88 | cp.name = str("shader_params/", p.name)
89 | props.append(cp)
90 | return props
91 |
92 | func _get(property):
93 | if property.begins_with("shader_params/"):
94 | var param_name = property.right(len("shader_params/"))
95 | var mat = _mesh_instance.material_override
96 | return mat.get_shader_parameter(param_name)
97 |
98 | func _set(property, value):
99 | if property.begins_with("shader_params/"):
100 | var param_name = property.right(len("shader_params/"))
101 | var mat = _mesh_instance.material_override
102 | mat.set_shader_parameter(param_name, value)
103 | return true
104 |
105 | func _get_configuration_warnings() -> PackedStringArray:
106 | var strArr = PackedStringArray([])
107 | if sun_path == null or sun_path.is_empty():
108 | strArr.append("The path to the sun is not assigned.")
109 | var light = get_node(sun_path)
110 | if not (light is Node3D):
111 | strArr.append("The assigned sun node is not a Node3D.")
112 | return strArr
113 |
114 | func set_planet_radius(new_radius: float):
115 | if planet_radius == new_radius:
116 | return
117 | planet_radius = max(new_radius, 0.0)
118 | _mesh_instance.material_override.set_shader_parameter("u_planet_radius", planet_radius)
119 | _update_cull_margin()
120 |
121 | func _update_cull_margin():
122 | _mesh_instance.extra_cull_margin = planet_radius + atmosphere_height
123 |
124 | func set_atmosphere_height(new_height: float):
125 | if atmosphere_height == new_height:
126 | return
127 | atmosphere_height = max(new_height, 0.0)
128 | _mesh_instance.material_override.set_shader_parameter("u_atmosphere_height", atmosphere_height)
129 | _update_cull_margin()
130 |
131 | func set_atmosphere_density(new_density: float):
132 | if atmosphere_density == new_density:
133 | return
134 | atmosphere_density = max(new_density, 0.0)
135 | _mesh_instance.material_override.set_shader_parameter("u_density", atmosphere_density)
136 | _update_cull_margin()
137 |
138 | func set_sun_path(new_sun_path: NodePath):
139 | sun_path = new_sun_path
140 | update_configuration_warnings()
141 |
142 | func _set_mode(mode: int):
143 | if mode == _mode:
144 | return
145 | _mode = mode
146 |
147 | var mat = _mesh_instance.material_override
148 |
149 | if _mode == MODE_NEAR:
150 | if OS.is_stdout_verbose():
151 | print("Switching ", name, " to near mode")
152 | # If camera is close enough, switch shader to near clip mode
153 | # otherwise it will pass through the quad
154 | mat.set_shader_parameter("u_clip_mode", true)
155 | _mesh_instance.mesh = _near_mesh
156 | _mesh_instance.transform = Transform3D()
157 | # TODO Sometimes there is a short flicker, figure out why
158 |
159 | else:
160 | if OS.is_stdout_verbose():
161 | print("Switching ", name, " to far mode")
162 | mat.set_shader_parameter("u_clip_mode", false)
163 | _mesh_instance.mesh = _far_mesh
164 |
165 | func _process(_delta):
166 | var cam_pos := Vector3()
167 | var cam_near := 0.1
168 |
169 | var cam = get_viewport().get_camera_3d()
170 |
171 | if cam != null:
172 | cam_pos = cam.global_transform.origin
173 | cam_near = cam.near
174 | elif Engine.is_editor_hint():
175 | # Getting the camera in editor is freaking awkward so let's hardcode it...
176 | cam_pos = global_transform.origin + Vector3(10.0 * (planet_radius + atmosphere_height + cam_near), 0, 0)
177 |
178 | # 1.75 is an approximation of sqrt(3), because the far mesh is a cube and we have to take
179 | # the largest distance from the center into account
180 | var atmo_clip_distance : float = 1.75 * (planet_radius + atmosphere_height + cam_near) * SWITCH_MARGIN_RATIO
181 |
182 | # Detect when to switch modes.
183 | # we always switch modes while already being slightly away from the quad, to avoid flickering
184 | var d := global_transform.origin.distance_to(cam_pos)
185 | var is_near := d < atmo_clip_distance
186 | if is_near:
187 | _set_mode(MODE_NEAR)
188 | else:
189 | _set_mode(MODE_FAR)
190 |
191 | if _mode == MODE_FAR:
192 | _mesh_instance.scale = Vector3(atmo_clip_distance, atmo_clip_distance, atmo_clip_distance)
193 |
194 | # Lazily avoiding the node referencing can of worms.
195 | # Not very efficient but I assume there won't be many atmospheres in the game.
196 | # In Godot 4 it could be replaced by caching the object ID in some way
197 | if has_node(sun_path):
198 | var sun = get_node(sun_path)
199 | if sun is Node3D:
200 | _mesh_instance.material_override.set_shader_parameter("u_sun_position", sun.global_transform.origin)
201 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/celestial_bodies/planet.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../resources/icons/planet.svg")
3 | class_name Planet
4 | extends Node3D
5 | # Class for a planet taking care of terrain, atmosphere, water etc.
6 |
7 | @export var do_generate: bool = false: set = set_do_generate
8 | @export var settings: Resource
9 | @export var material: Material
10 | @export var solar_system_path: NodePath
11 | @export var sun_path: NodePath
12 | var _org_water_mesh: Mesh
13 | var _solar_system: Node
14 | var _logger := Logger.get_for(self)
15 | var mass: float = pow(10.0, 10) # TODO: Make this configurable through settings.
16 | @onready var _terrain: TerrainManager = $TerrainManager
17 | @onready var _atmosphere = $Atmosphere
18 | @onready var _water_sphere: MeshInstance3D = $WaterSphere
19 |
20 |
21 | func _ready():
22 | if not _org_water_mesh:
23 | _org_water_mesh = _water_sphere.mesh
24 | generate()
25 |
26 |
27 | # Generate whole planet.
28 | func generate():
29 | if not are_conditions_met():
30 | return
31 | var time_before = Time.get_ticks_msec()
32 | settings.init(self)
33 | _terrain.generate(settings, material)
34 |
35 | # Adjust water.
36 | _water_sphere.visible = settings.has_water
37 | if settings.has_water:
38 | var material :Material = _org_water_mesh.surface_get_material(0).duplicate()
39 | var mesh : SphereMesh = _org_water_mesh.duplicate()
40 | mesh.radius = settings.radius
41 | mesh.height = settings.radius*2
42 | mesh.surface_set_material(0, material)
43 | _water_sphere.mesh = mesh
44 | material.set_shader_parameter("planet_radius", settings.radius)
45 |
46 | # Adjust atmosphere.
47 | _atmosphere.visible = settings.has_atmosphere
48 | if settings.has_atmosphere:
49 | _atmosphere.planet_radius = settings.radius
50 | _atmosphere.atmosphere_height = settings.atmosphere_thickness
51 | _atmosphere.atmosphere_density = settings.atmosphere_density
52 | _atmosphere.set_sun_path("../" + str(sun_path))
53 |
54 | _logger.debug("%s%s started generating after %sms." % [name, str(self), str(Time.get_ticks_msec() - time_before)])
55 |
56 | func are_conditions_met() -> bool:
57 | if not settings or not material:
58 | _logger.warn("Settings or material not set, can't generate %s%s." %
59 | [name, str(self)])
60 | return false
61 | if not _terrain:
62 | _logger.warn("Terrain %s%s for not yet initialized." % [name, str(self)])
63 | return false
64 | var jobs: Array = PGGlobals.job_queue.get_jobs_for(self)
65 | if !jobs.is_empty() and not PGGlobals.benchmark_mode:
66 | _logger.warn("Waiting for %d jobs to finish before generating \"%s%s\"." % [jobs.size(), name, str(self)])
67 | return false
68 | return true
69 |
70 | func set_do_generate(_new):
71 | generate()
72 |
73 | func _enter_tree():
74 | if solar_system_path:
75 | _solar_system = get_node(solar_system_path)
76 | elif get_parent().has_method("register_planet"): # TODO: Properly find if parent is _solar_system.
77 | solar_system_path = ".."
78 | _solar_system = get_parent()
79 | if _solar_system:
80 | _solar_system.register_planet(self)
81 |
82 | func _exit_tree():
83 | if _solar_system:
84 | _solar_system.unregister_planet(self)
85 |
86 | func _get_configuration_warnings() -> PackedStringArray:
87 | var strArr = PackedStringArray([])
88 | if settings and settings.has_atmosphere and sun_path.is_empty():
89 | strArr.append("Node path to sun node is not set in 'Sun Path3D'.")
90 | if solar_system_path.is_empty():
91 | strArr.append("Node path to the solar system node is not set in 'Solar System Path3D'.")
92 | return strArr
93 |
94 | # Shared configuration warnings between this class and subclasses.
95 | func _get_common_config_warning() -> String:
96 | if not settings:
97 | return "Missing a 'PlanetSettings' resource in 'Settings'."
98 | if not material:
99 | return "Missing a 'Material' resource in 'Material'."
100 | return ""
101 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/celestial_bodies/planet_settings.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name PlanetSettings
3 | extends Resource
4 |
5 | @export_range(3, 9999) var resolution: int = 20: set = set_resolution
6 | @export var radius: float = 100: set = set_radius
7 | @export var has_water: bool = false: set = set_has_water
8 | @export var has_atmosphere: bool = true: set = set_has_atmosphere
9 | @export var has_collisions: bool = true: set = set_has_collisions
10 | @export_range(1.0, 10000.0) var atmosphere_thickness: float = 1.15: set = set_atmosphere_thickness
11 | @export_range(0.0, 1.0) var atmosphere_density: float = 0.1: set = set_atmosphere_density
12 | @export var shape_generator: Resource
13 |
14 | var _planet: Node3D: get = get_planet
15 | var shared_mutex := Mutex.new() # Used for threads creating physics shapes.
16 |
17 |
18 | func init(_planet):
19 | self._planet = _planet
20 | shape_generator.init(_planet)
21 |
22 |
23 | func on_settings_changed():
24 | if not _planet:
25 | return
26 | _planet.generate()
27 |
28 |
29 | func set_resolution(new: int):
30 | resolution = new
31 | on_settings_changed()
32 |
33 |
34 | func set_radius(new: float):
35 | radius = new
36 | on_settings_changed()
37 |
38 |
39 | func set_has_water(new: bool):
40 | has_water = new
41 | on_settings_changed()
42 |
43 |
44 | func set_has_atmosphere(new: bool):
45 | has_atmosphere = new
46 | on_settings_changed()
47 |
48 |
49 | func set_atmosphere_thickness(new: float):
50 | atmosphere_thickness = new
51 | on_settings_changed()
52 |
53 |
54 | func set_atmosphere_density(new: float):
55 | atmosphere_density = new
56 | on_settings_changed()
57 |
58 |
59 | func set_has_collisions(new: bool):
60 | has_collisions = new
61 | on_settings_changed()
62 |
63 |
64 | func get_planet() -> Node3D:
65 | return _planet
66 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/celestial_bodies/solar_system.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../resources/icons/solar_system.svg")
3 | class_name SolarSystem
4 | extends Node3D
5 |
6 | var _all_planets: Array
7 | var _logger := Logger.get_for(self)
8 |
9 |
10 | func register_planet(planet: Planet):
11 | _all_planets.append(planet)
12 |
13 |
14 | func unregister_planet(planet: Planet):
15 | _all_planets.erase(planet)
16 |
17 |
18 | func _enter_tree():
19 | PGGlobals.register_solar_system(self)
20 |
21 |
22 | func _exit_tree():
23 | PGGlobals.unregister_solar_system(self)
24 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/celestial_bodies/sun.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | @icon("../../resources/icons/sun.svg")
3 | class_name Sun
4 | extends Planet
5 |
6 | const CORONA_SIZE := Vector2(15, 14)
7 | const LIGHT_OFFSET := 1.01 * Vector3.FORWARD
8 |
9 | @onready var _corona: MeshInstance3D = $Corona
10 | @onready var _sunlight := $Sunlight
11 |
12 |
13 | # Called every frame. 'delta' is the elapsed time since the previous frame.
14 | func _process(_delta):
15 | var cam = get_viewport().get_camera_3d()
16 | if cam:
17 | look_at(cam.global_transform.origin, Vector3.UP)
18 |
19 |
20 | func generate():
21 | await self.ready
22 | if settings:
23 | _corona.mesh.size = CORONA_SIZE * settings.radius
24 | _sunlight.position = LIGHT_OFFSET * settings.radius
25 | super.generate()
26 |
27 |
28 | func _get_configuration_warnings():
29 | return _get_common_config_warning()
30 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/constants.gd:
--------------------------------------------------------------------------------
1 | # Defines some constants for the quadtree and terrain patches.
2 |
3 | const COLLISIONS_ENABLED := false # Whether planets generate collision shapes.
4 | const GRAVITY_ENABLED := true # TODO: Implement gravity.
5 | const THREADS_ENABLED := true
6 |
7 | const GRAVITY := 0.000000981 # Increase this to make gravity fade faster than reality.
8 | const MOUSE_SENSITIVITY := 1.5
9 |
10 | ### Quad tree and terrain LOD constants.
11 | # Quad tree depth, also number of LOD levels.
12 | const MAX_TREE_DEPTH := 9
13 | # How long the feeder thread sleeps if idle in µs.
14 | const THREAD_DELAY := 5000
15 | # Vertex border around terrain patches.
16 | const BORDER_SIZE := 1
17 | # How much border vertices will be dipped in relation to patch _size.
18 | const BORDER_DIP := 0.8
19 | # Minimal size of quad nodes, 1/2^MAX_TREE_DEPTH
20 | const MIN_SIZE := 1.0/pow(2, MAX_TREE_DEPTH)
21 | # Define when LODs will be switched: min_distance * _size * radius
22 | const MIN_DISTANCE := 4.0
23 | # This is multiplied with theoretical noise strength to get a sane value.
24 | const MIN_MAX_APPROXIMATION := 0.6
25 | # The four quadrants of a quadtree leaf:
26 | const MAX_LEAVES := 4
27 | # Offset vector for the leaf nodes:
28 | const LEAF_OFFSETS := [
29 | Vector2(-1, -1),
30 | Vector2(-1, 1),
31 | Vector2(1, -1),
32 | Vector2(1, 1),
33 | ]
34 | # Normals of the six cube faces that are mapped to the planet sphere.
35 | const DIRECTIONS: Array = [
36 | Vector3.FORWARD,
37 | Vector3.BACK,
38 | Vector3.UP,
39 | Vector3.DOWN,
40 | Vector3.LEFT,
41 | Vector3.RIGHT,
42 | ]
43 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/gui/gui.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 | # Experimental GUI to display some debug information, uses ugly private member access for now.
3 |
4 | @onready var lbl_status := $Root/MarginContainer/HBoxContainer/LabelStatus
5 | @onready var lbl_speedscale := $Root/MarginContainer/HBoxContainer/Control/LabelSpeedScale
6 | @onready var slider_speedscale := $Root/MarginContainer/HBoxContainer/Control/HSlider
7 | var ship : Node3D
8 |
9 |
10 | func _ready():
11 | var player_nodes = get_tree().get_nodes_in_group("player")
12 | if player_nodes.size() > 0:
13 | ship = player_nodes[0]
14 | ship.connect("speed_scale_changed", Callable(self, "update_speed_scale"))
15 |
16 |
17 | func _process(_delta):
18 | lbl_status.text = "FPS: %d" % Engine.get_frames_per_second()
19 | lbl_status.text += "\nwireframe: %s\ncolored_patches: %s" \
20 | % [PGGlobals.wireframe, PGGlobals.colored_patches]
21 | if ship:
22 | if ship.get("_current_speed"):
23 | lbl_status.text += "\nspeed: %f km/s" % (round(ship._current_speed*3500)/100)
24 | if ship.get("linear_velocity"):
25 | lbl_status.text += "\nvelocity: %s" % ship.linear_velocity
26 | show_planet_info()
27 | check_input()
28 |
29 |
30 | func show_planet_info():
31 | if PGGlobals.solar_systems.is_empty():
32 | return
33 | var num_jobs: int = PGGlobals.job_queue.get_number_of_jobs()
34 | lbl_status.text += "\nTerrain patch queue size: %d" % num_jobs
35 | for planet in PGGlobals.solar_systems[0]._all_planets:
36 | lbl_status.text += "\n%s%s | %d patches" % \
37 | [planet.name, str(planet), planet._terrain.get_children().size()]
38 |
39 |
40 | func check_input():
41 | if Input.is_action_just_pressed("toggle_colored_patches"):
42 | PGGlobals.colored_patches = !PGGlobals.colored_patches
43 | if Input.is_action_just_pressed("toggle_wireframe"):
44 | PGGlobals.wireframe = !PGGlobals.wireframe
45 |
46 |
47 | func _on_HSlider_value_changed(value):
48 | update_speed_scale(value)
49 | if ship:
50 | ship.speed_scale = value
51 |
52 |
53 | func update_speed_scale(value):
54 | lbl_speedscale.text = str(value)
55 | slider_speedscale.value = value
56 | PGGlobals.speed_scale = value
57 |
58 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/quadtree/cube_quadtree.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name CubeQuadTree
3 |
4 | # Represents six quadtrees on a cube with one for each side.
5 |
6 | const Const := preload("../constants.gd")
7 |
8 | var _face_quadtrees: Dictionary # Maps a cube face normal to a quadtree instance.
9 |
10 |
11 | func _init(terrain_manager):
12 | for dir in Const.DIRECTIONS:
13 | _face_quadtrees[dir] = QuadNode.new(null, dir, terrain_manager)
14 |
15 |
16 | func set_viewer(viewer: Node3D):
17 | for qt in _face_quadtrees.values():
18 | qt.set_viewer(viewer)
19 |
20 |
21 | func get_num_children() -> int:
22 | var result: int
23 | for qt in _face_quadtrees:
24 | result += qt.get_num_children()
25 | return result
26 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/quadtree/quadnode.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name QuadNode
3 |
4 | # One quadrant in a quadtree.
5 | # Lifecycle looks like one of these:
6 | # 1. PREPARING → WAITING → ACTIVE → SPLITTING → SPLIT → ACTIVE → MAY_MERGE.
7 | # 2. PREPARING → WAITING → ACTIVE → MAY_MERGE.
8 | # 3. PREPARING → MAY_MERGE.
9 | # 4. PREPARING → WAITING → MAY_MERGE.
10 |
11 | const Const := preload("../constants.gd")
12 |
13 | enum STATE {PREPARING, WAITING, ACTIVE, SPLITTING, SPLIT, MAY_MERGE}
14 |
15 | var parent: QuadNode
16 | var depth: int
17 | var leaves: Array
18 | var terrain: TerrainPatch # Terrain patch of this quadtree node.
19 | var terrain_job: TerrainJob
20 | var _state: int = STATE.PREPARING
21 | var _size: float # Size of this quad, 1/depth
22 | var _terrain_manager: Node3D
23 | var _center: Vector3 # Global position of the center.
24 | var _min_distance: float # Distance to viewer at which this node subdivides.
25 | var _viewer_node: Node3D: set = set_viewer
26 |
27 |
28 | func _init(parent: QuadNode, direction: Vector3, terrain_manager: Node3D, leaf_index := -1):
29 | var offset: Vector2
30 | if not parent:
31 | # We're the top level quadtree node.
32 | depth = 1
33 | _size = 1.0
34 | offset = Vector2(0, 0)
35 | else:
36 | # Spawning as a leaf node, so use an offset.
37 | self.parent = parent
38 | depth = parent.depth + 1
39 | _size = parent._size / 2
40 | _viewer_node = parent._viewer_node
41 | offset = Const.LEAF_OFFSETS[leaf_index]
42 | var data := PatchData.new(terrain_manager, self, direction, offset)
43 | _terrain_manager = terrain_manager
44 | _center = data.center
45 | _min_distance = Const.MIN_DISTANCE * _size * data.settings.radius
46 | terrain_job = PGGlobals.queue_terrain_patch(data)
47 | terrain_job.connect("job_finished", Callable(self, "on_patch_finished").bind(), CONNECT_DEFERRED)
48 |
49 |
50 | # Update this node in the quadtree.
51 | func visit():
52 | var distance: float = _viewer_node.global_transform.origin.distance_to(_terrain_manager.global_transform.origin + _center)
53 | var viewer_in_range: bool = distance < _min_distance
54 |
55 | if _state == STATE.ACTIVE or _state == STATE.MAY_MERGE:
56 | if viewer_in_range:
57 | split_start()
58 | elif _state != STATE.MAY_MERGE:
59 | mark_redundant()
60 | elif _state == STATE.SPLIT:
61 | if not viewer_in_range:
62 | var can_merge: bool = true
63 | for leaf in leaves:
64 | if leaf._state != STATE.MAY_MERGE:
65 | can_merge = false
66 | if can_merge:
67 | merge()
68 | elif _state == STATE.SPLITTING:
69 | if viewer_in_range:
70 | var split_finished: bool = true
71 | for leaf in leaves:
72 | if leaf._state == STATE.PREPARING:
73 | split_finished = false
74 | if split_finished:
75 | split_finish()
76 | else:
77 | merge() # Viewer has left range while in the process of splitting.
78 |
79 |
80 | # Begin splitting this node up into leaf nodes.
81 | func split_start():
82 | if depth == Const.MAX_TREE_DEPTH:
83 | return # Don't split any further.
84 | for i in Const.MAX_LEAVES:
85 | # Workaround for cyclic reference issues.
86 | leaves.append(get_script().new(
87 | self, terrain.data.axis_up, _terrain_manager, i
88 | ))
89 | _state = STATE.SPLITTING
90 |
91 |
92 | # Leaf nodes are done generating and ready to go.
93 | func split_finish():
94 | for leaf in leaves:
95 | leaf.on_ready_to_show()
96 | terrain.set_visible(false)
97 | _state = STATE.SPLIT
98 |
99 |
100 | func merge():
101 | for leaf in leaves:
102 | leaf.destroy()
103 | leaves.clear()
104 | terrain.set_visible(true)
105 | _state = STATE.ACTIVE
106 |
107 |
108 | func mark_redundant():
109 | if not parent:
110 | return
111 | _state = STATE.MAY_MERGE
112 |
113 |
114 | # Destroys this node, also handles being destroyed while job is running.
115 | func destroy():
116 | if terrain_job:
117 | terrain_job.abort()
118 | if terrain:
119 | terrain.queue_free()
120 |
121 |
122 | # TerrainPatch for this node is done.
123 | func on_patch_finished(job: TerrainJob, patch: TerrainPatch):
124 | terrain = patch
125 | terrain_job = null
126 | if parent:
127 | # Signal to parent that we're wait for sibling nodes to finish.
128 | _state = STATE.WAITING
129 | else:
130 | # Top level node, don't wait for siblings.
131 | on_ready_to_show()
132 |
133 |
134 | func on_ready_to_show():
135 | assert(terrain_job == null) #,"Terrain job for %s is not done!" % str(self))
136 | terrain.set_visible(true)
137 | _terrain_manager.add_child(terrain)
138 | _state = STATE.ACTIVE
139 | if not _viewer_node:
140 | set_viewer(terrain.get_viewport().get_camera_3d())
141 |
142 |
143 | func get_num_children() -> int:
144 | var result: int
145 | for leaf in leaves:
146 | result += leaf.get_num_children()
147 | return result
148 |
149 |
150 | func set_viewer(viewer: Node3D):
151 | _viewer_node = viewer
152 | for leaf in leaves:
153 | leaf.set_viewer(viewer)
154 |
155 |
156 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/spacecraft/camera.gd:
--------------------------------------------------------------------------------
1 | extends Camera3D
2 |
3 | const MIN_WEIGHT: float = 0.05
4 | const MAX_WEIGHT: float = 0.6
5 |
6 | @onready
7 | @export var target: NodePath
8 | @export var weight: float = 0.6
9 |
10 |
11 | func _ready():
12 | set_as_top_level(true)
13 |
14 |
15 | func _physics_process(delta):
16 | var targetTransform: Transform3D = get_node(target).global_transform
17 | var distance = targetTransform.origin.distance_to(transform.origin)
18 | # Calculate dynamic weight.
19 | var dynamicWeight = max(MIN_WEIGHT, min(MAX_WEIGHT,
20 | remap(distance, 0.1, 2.0, MIN_WEIGHT, MAX_WEIGHT)))
21 | transform = transform.interpolate_with(targetTransform, dynamicWeight)
22 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/spacecraft/player_controller.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | const Ship := preload("ship.gd")
4 | const Constants := preload("../constants.gd")
5 |
6 | var _mouse_speed := Vector2.ZERO
7 | @onready var ship = get_parent()
8 |
9 |
10 | func _ready():
11 | if not Engine.is_editor_hint():
12 | Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
13 | else:
14 | Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
15 |
16 |
17 | # Called every frame. 'delta' is the elapsed time since the previous frame.
18 | func _physics_process(delta):
19 | var input := Vector3()
20 | var rotation_z := 0.0
21 | # Ship movement input.
22 | if Input.is_key_pressed(KEY_W):
23 | input.z = -1
24 | if Input.is_key_pressed(KEY_S):
25 | input.z = 1
26 | if Input.is_key_pressed(KEY_A):
27 | input.x = -1
28 | if Input.is_key_pressed(KEY_D):
29 | input.x = 1
30 | # Rotation along local Z axis.
31 | if Input.is_key_pressed(KEY_Q):
32 | rotation_z = Ship.ROTATIONSPEED
33 | if Input.is_key_pressed(KEY_E):
34 | rotation_z = -Ship.ROTATIONSPEED
35 | if rotation_z:
36 | ship.rotate(ship.transform.basis.z, rotation_z)
37 |
38 | if input:
39 | ship.apply_thrust(input)
40 |
41 |
42 | func _input(event):
43 | if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED and not Input.is_action_pressed("toggle_camera_mode"):
44 | _mouse_speed = event.relative * Constants.MOUSE_SENSITIVITY
45 | ship.rotate(ship.transform.basis.y.normalized(), deg_to_rad(-_mouse_speed.x))
46 | ship.rotate(ship.transform.basis.x.normalized(), deg_to_rad(-_mouse_speed.y))
47 | elif event is InputEventMouseButton:
48 | if event.button_index == MOUSE_BUTTON_WHEEL_UP:
49 | ship.speed_scale += Ship.SPEED_INCREMENT
50 | elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
51 | ship.speed_scale -= Ship.SPEED_INCREMENT
52 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/spacecraft/player_ship_kinematic.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody3D
2 | # Ship controller. Also handles the camera.
3 |
4 | const Constants := preload("../constants.gd")
5 | const SHAKE_MAX_DEGREES := Vector3(0.005, 0.005, 0.015)
6 | const MAXSPEED = 20.0
7 | const ROTATIONSPEED = 0.01
8 | const MAXPARTICLETIME = 0.1
9 |
10 | enum CAMERASTATE {FOLLOW, ROTATE}
11 |
12 | var _mouse_speed := Vector2()
13 | var _current_speed: float
14 | var _camera_noise := FastNoiseLite.new()
15 | var speed_scale := 0.0005
16 |
17 | @onready var _camera_pivot := $CameraPivot
18 | @onready var _camera := $CameraPivot/RotatingCamera
19 | @onready var _camera_tween := $CameraPivot/Tween
20 | @onready var _thrust_particles_left := $ThrustParticlesLeft
21 | @onready var _thrust_particles_right := $ThrustParticlesRight
22 | @onready var _org_transform := self.get_transform()
23 | @onready var _org_pivot_transform: Transform3D = _camera_pivot.get_transform()
24 | @onready var _org_camera_rotation: Vector3 = _camera.rotation
25 |
26 | func _ready():
27 | _camera_noise.seed = randi()
28 | _camera_noise.period = 0.4
29 | if not Engine.is_editor_hint():
30 | Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
31 | else:
32 | Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
33 | set_process_input(true)
34 |
35 | func _physics_process(_delta):
36 | var input: Vector2 = Vector2()
37 | var rotation_z = 0
38 | # Ship movement input.
39 | if Input.is_key_pressed(KEY_W):
40 | input.x = 1
41 | if Input.is_key_pressed(KEY_S):
42 | input.x = -1
43 | if Input.is_key_pressed(KEY_A):
44 | input.y = 1
45 | if Input.is_key_pressed(KEY_D):
46 | input.y = -1
47 | if Input.is_key_pressed(KEY_SHIFT):
48 | input *= 10
49 | if Input.is_key_pressed(KEY_Q):
50 | rotation_z += ROTATIONSPEED
51 | if Input.is_key_pressed(KEY_E):
52 | rotation_z -= ROTATIONSPEED
53 | if Input.is_action_just_pressed("toggle_camera_mode"):
54 | _camera_tween.stop_all()
55 | if Input.is_action_just_released("toggle_camera_mode") and not _camera_tween.is_active():
56 | _camera_tween.interpolate_property(_camera_pivot, "transform:basis", null, _org_pivot_transform.basis, 1.2, Tween.TRANS_CUBIC, Tween.EASE_IN_OUT)
57 | _camera_tween.start()
58 |
59 | if rotation_z:
60 | rotate(transform.basis.z, rotation_z)
61 | _current_speed += speed_scale * input.x
62 | _current_speed = clamp(_current_speed, -MAXSPEED, MAXSPEED)
63 | if abs(_current_speed) < 1 / 1000:
64 | _current_speed = 0
65 |
66 | # Move the ship.
67 | move_and_collide(-transform.basis.z * _current_speed) # Forward movement.
68 |
69 | shake_camera()
70 | adjust_thrusters()
71 |
72 | func _input(event):
73 | if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
74 | _mouse_speed = event.relative * PGGlobals.MOUSE_SENSITIVITY
75 | if Input.is_action_pressed("toggle_camera_mode"):
76 | _camera_pivot.rotate(_camera_pivot.transform.basis.y.normalized(), deg_to_rad(-_mouse_speed.x))
77 | _camera_pivot.rotate(_camera_pivot.transform.basis.x.normalized(), deg_to_rad(-_mouse_speed.y))
78 | else:
79 | rotate(transform.basis.y.normalized(), deg_to_rad(-_mouse_speed.x))
80 | rotate(transform.basis.x.normalized(), deg_to_rad(-_mouse_speed.y))
81 | elif event is InputEventMouseButton:
82 | if event.button_index == MOUSE_BUTTON_WHEEL_UP:
83 | _current_speed += speed_scale
84 | elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
85 | _current_speed -= speed_scale
86 |
87 | func shake_camera():
88 | # Normalize the speed factor.
89 | var speed_factor: float = remap(abs(_current_speed), 0, MAXSPEED, 0, 1)
90 | # Apply an exponential easing function.
91 | speed_factor = 1.0 if speed_factor == 1 else 1 - pow(2, -10 * speed_factor)
92 | # Constant change in noise.
93 | var time = wrapf(Engine.get_frames_drawn() / float(Engine.physics_ticks_per_second), 0, 1000)
94 | _camera.rotation = _org_camera_rotation
95 | _camera.rotation.x = SHAKE_MAX_DEGREES.x * _camera_noise.get_noise_1d(time) * speed_factor
96 | _camera.rotation.y = SHAKE_MAX_DEGREES.y * _camera_noise.get_noise_1d(time*2) * speed_factor
97 | _camera.rotation.z = SHAKE_MAX_DEGREES.z * _camera_noise.get_noise_1d(time*3) * speed_factor
98 |
99 | func adjust_thrusters():
100 | var lifetime = remap(abs(_current_speed), 0, MAXSPEED, 0, MAXPARTICLETIME)
101 | _thrust_particles_left.visible = lifetime > 0.0
102 | _thrust_particles_right.visible = lifetime > 0.0
103 | _thrust_particles_left.lifetime = max(0.001, lifetime)
104 | _thrust_particles_right.lifetime = max(0.001, lifetime)
105 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/spacecraft/ship.gd:
--------------------------------------------------------------------------------
1 | extends RigidBody3D
2 |
3 | const Constants := preload("../constants.gd")
4 | const MAXVELOCITY := 50.0
5 | const ROTATIONSPEED := 0.5
6 | const SPEED_INCREMENT := 0.0005
7 | const SPEED_SCALE_MAX := 0.2
8 |
9 | signal speed_scale_changed(value)
10 |
11 | var impulse := Vector3.ZERO
12 | var rotation_basis := transform.basis
13 | var apply_rotation := false
14 | var speed_scale := 0.0005: get = get_speed_scale, set = set_speed_scale
15 |
16 | # Called when the node enters the scene tree for the first time.
17 | func _ready():
18 | pass # Replace with function body.
19 |
20 | func _physics_process(delta: float):
21 | calculate_gravity(delta)
22 | apply_central_impulse(impulse)
23 | impulse = Vector3.ZERO
24 |
25 | func _integrate_forces(state: PhysicsDirectBodyState3D):
26 | state.transform.basis = rotation_basis
27 |
28 | func apply_thrust(v: Vector3) -> bool:
29 | if linear_velocity.length() > MAXVELOCITY:
30 | return false
31 | impulse += transform.origin * v * speed_scale
32 | return true
33 |
34 | func rotate(axis: Vector3, degrees: float):
35 | rotation_basis = rotation_basis.rotated(axis, deg_to_rad(degrees))
36 |
37 | func calculate_gravity(delta: float):
38 | var bodies = get_tree().get_nodes_in_group("planets")
39 | for body in bodies:
40 | var radius : float = body.global_transform.origin.distance_to(global_transform.origin)
41 | var direction : Vector3 = (body.global_transform.origin - global_transform.origin).normalized()
42 | var accel = direction * Constants.GRAVITY * body.mass / (radius * radius) * delta
43 | impulse += accel
44 |
45 | func set_speed_scale(new: float):
46 | speed_scale = new
47 | clamp(speed_scale, SPEED_INCREMENT, SPEED_SCALE_MAX)
48 | emit_signal("speed_scale_changed", new)
49 |
50 | func get_speed_scale():
51 | return speed_scale
52 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/job_queue.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name JobQueue
3 |
4 | # Handles queueing terrain jobs and feeding them to a defined amount of
5 | # worker threads, balancing the load.
6 |
7 | const Const := preload("../constants.gd")
8 | enum STATE {WORKING, IDLE, CLEANING_UP, CLEANED_UP}
9 |
10 | signal all_finished
11 |
12 | # Make sure to have at least one worker thread:
13 | var _num_workers := max(1, OS.get_processor_count())
14 | var _state: int = STATE.IDLE
15 | var _state_mutex := Mutex.new()
16 | var _queued_jobs := [] # Jobs that have been queued for processing.
17 | var _queue_mutex := Mutex.new()
18 | var processing_jobs := [] # Jobs that are currently being processed.
19 | var _worker_pool := []
20 | var _logger := Logger.get_for(self)
21 | var semaphore := Semaphore.new()
22 |
23 |
24 | func _init():
25 | if Const.THREADS_ENABLED:
26 | for i in _num_workers:
27 | _worker_pool.append(WorkerThread.new(self))
28 |
29 |
30 | func is_working() -> bool:
31 | if _state == STATE.WORKING or _state == STATE.CLEANING_UP:
32 | return true
33 | else:
34 | return false
35 |
36 |
37 | # Return total number of currently queued and processed jobs.
38 | func get_number_of_jobs() -> int:
39 | return _queued_jobs.size() + processing_jobs.size()
40 |
41 |
42 | func get_jobs_for(planet: Planet) -> Array:
43 | var result := []
44 | _queue_mutex.lock() # We don't want any surprises while reading.
45 | for job in _queued_jobs:
46 | if job.get_data().settings.get_planet() == planet:
47 | result.append(job)
48 | for job in processing_jobs:
49 | if job.get_data().settings.get_planet() == planet:
50 | result.append(job)
51 | _queue_mutex.unlock()
52 | return result
53 |
54 |
55 | func update_state():
56 | if _state == STATE.CLEANING_UP or _state == STATE.CLEANED_UP:
57 | return
58 | _state_mutex.lock()
59 | if _queued_jobs.is_empty() and processing_jobs.is_empty():
60 | _state = STATE.IDLE
61 | call_deferred("emit_signal", "all_finished") # Thread-safe.
62 | else:
63 | _state = STATE.WORKING
64 | _state_mutex.unlock()
65 |
66 |
67 | # Add a new job to the queue.
68 | func queue(job: TerrainJob):
69 | if _state == STATE.CLEANING_UP:
70 | return
71 | _queue_mutex.lock()
72 | _queued_jobs.append(job)
73 | _queue_mutex.unlock()
74 | job.connect("job_finished", Callable(self, "on_job_finished"))
75 | semaphore.post() # The next free worker thread will pick it up.
76 | update_state()
77 |
78 |
79 | # Pop and return next job from the queue.
80 | func fetch_job() -> TerrainJob:
81 | if _queued_jobs.is_empty():
82 | return null # May happen while cleaning up.
83 | var job: TerrainJob
84 | _queue_mutex.lock()
85 | job = _queued_jobs.pop_front()
86 | processing_jobs.append(job)
87 | _queue_mutex.unlock()
88 | update_state()
89 | return job
90 |
91 |
92 | func on_job_finished(job: TerrainJob, patch: TerrainPatch):
93 | _queue_mutex.lock()
94 | processing_jobs.erase(job)
95 | _queue_mutex.unlock()
96 | update_state()
97 |
98 |
99 | # Clean up jobs and worker threads.
100 | func clean_up():
101 | if _state == STATE.CLEANING_UP or _state == STATE.CLEANED_UP:
102 | return
103 | _clean_jobs_and_workers()
104 |
105 |
106 | func _clean_jobs_and_workers():
107 | # Update state.
108 | _state_mutex.lock()
109 | _state = STATE.CLEANING_UP
110 | _state_mutex.unlock()
111 | _queue_mutex.lock()
112 | _queued_jobs.clear() # Simply free all jobs, we won't need their results.
113 | _queue_mutex.unlock()
114 |
115 | await self.all_finished
116 | for worker in _num_workers:
117 | semaphore.post() # One last cycle to let worker finish.
118 | while !_worker_pool.is_empty():
119 | var worker: WorkerThread = _worker_pool.pop_front()
120 | if worker.is_active():
121 | worker.wait_to_finish()
122 | _state = STATE.CLEANED_UP
123 |
124 |
125 | # Only used when multithreading is not enabled.
126 | func process_queue_without_threads():
127 | if Const.THREADS_ENABLED:
128 | _logger.warn("process_queue() was called although multithreading is enabled!")
129 | else:
130 | var job: TerrainJob = fetch_job()
131 | if job:
132 | job.run()
133 |
134 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/min_max.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name MinMax
3 |
4 |
5 | var min_value: float
6 | var max_value: float
7 |
8 |
9 | func _init():
10 | min_value = INF
11 | max_value = -INF
12 |
13 |
14 | func add_value(new: float):
15 | if new < min_value:
16 | min_value = new
17 | elif new > max_value:
18 | max_value = new
19 |
20 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/noise_generator.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name NoiseGenerator
3 | extends Resource
4 |
5 | @export var enabled: bool = true: set = set_enabled
6 | @export var use_first_as_mask: bool: set = set_use_first_as_mask
7 | @export var seed_value: int: set = set_seed_value
8 | @export var strength: float: set = set_strength
9 | @export var fractal_octaves: int = 4: set = set_octaves
10 | @export var period: float = 0.03: set = set_period
11 | @export var frequency: float = 0.6: set = set_frequency
12 | @export var center: Vector3: set = set_center
13 |
14 | # Micro-optimization to make generator functions branchless (no ifs).
15 | var enabled_int: int
16 | var use_first_as_mask_int: int
17 |
18 | var _simplex: FastNoiseLite
19 | var _planet: Node3D
20 |
21 |
22 | func init(_planet):
23 | self._planet = _planet
24 | enabled_int = enabled
25 | use_first_as_mask_int = use_first_as_mask
26 |
27 |
28 | func update_settings():
29 | _simplex = FastNoiseLite.new()
30 | _simplex.noise_type = FastNoiseLite.TYPE_SIMPLEX
31 | _simplex.seed = seed_value
32 | _simplex.fractal_octaves = fractal_octaves
33 | _simplex.fractal_type = FastNoiseLite.FRACTAL_RIDGED
34 | _simplex.frequency = frequency
35 | if _planet:
36 | _planet.generate()
37 |
38 |
39 | func evaluate(v: Vector3) -> float:
40 | return _simplex.get_noise_3dv(center + v) * strength
41 |
42 |
43 | func set_enabled(new):
44 | enabled = new
45 | update_settings()
46 |
47 |
48 | func set_seed_value(new):
49 | seed_value = new
50 | update_settings()
51 |
52 |
53 | func set_strength(new):
54 | strength = new
55 | update_settings()
56 |
57 |
58 | func set_octaves(new):
59 | fractal_octaves = new
60 | update_settings()
61 |
62 |
63 | func set_period(new):
64 | period = new
65 | update_settings()
66 |
67 |
68 | func set_frequency(new):
69 | frequency = new
70 | update_settings()
71 |
72 |
73 | func set_use_first_as_mask(new):
74 | use_first_as_mask = new
75 | update_settings()
76 |
77 |
78 | func set_center(new):
79 | center = new
80 | update_settings()
81 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/patch_data.gd:
--------------------------------------------------------------------------------
1 | class_name PatchData
2 |
3 | # Data class which holds information for one patch of terrain.
4 |
5 | const Const := preload("../constants.gd")
6 |
7 | var parent_patch: Node3D # Parent patch in the quad tree.
8 | var quadnode: RefCounted
9 | var settings: PlanetSettings
10 | var axis_up: Vector3 # Normal of flat cube patch.
11 | var axis_a: Vector3 # Axis perpendicular to the normal.
12 | var axis_b: Vector3 # Axis perpendicular to both above.
13 | var verts_per_edge: int # Amount of vertices with border (so resolution + BORDER_SIZE * 2).
14 | var offset_a: Vector3 # Offsets this patch to it's quadtree cell along axis a.
15 | var offset_b: Vector3 # Offsets this patch to it's quadtree cell along axis b.
16 | var size: float # Size of this quad. 1 is a full cube patch, 0.5 a quarter etc.
17 | var center: Vector3
18 | var material: Material
19 |
20 |
21 | func _init(manager: Node3D, quadnode: RefCounted,
22 | axis_up: Vector3, offset: Vector2):
23 | self.quadnode = quadnode
24 | settings = manager.planet_settings
25 | material = manager.planet_material
26 | size = quadnode._size
27 | axis_up = axis_up.normalized()
28 | self.axis_up = axis_up
29 | axis_a = Vector3(axis_up.y, axis_up.z, axis_up.x) * size
30 | axis_b = axis_up.cross(axis_a).normalized() * size
31 | offset_a = Vector3(axis_a * offset.x)
32 | offset_b = Vector3(axis_b * offset.y)
33 |
34 | if quadnode.parent:
35 | parent_patch = quadnode.parent.terrain
36 | if parent_patch:
37 | offset_a += parent_patch.data.offset_a
38 | offset_b += parent_patch.data.offset_b
39 | verts_per_edge = settings.resolution + Const.BORDER_SIZE * 2
40 | center = settings.radius * (axis_up + offset_a + offset_b).normalized()
41 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/ridged_noise_generator.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name RidgedNoiseGenerator
3 | extends NoiseGenerator
4 |
5 |
6 | func evaluate(v: Vector3) -> float:
7 | var elevation: float = 1.0 - abs(_simplex.get_noise_3dv(center + v))
8 | return elevation * elevation * strength
9 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/shape_generator.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name ShapeGenerator
3 | extends Resource
4 |
5 | const Const := preload("../constants.gd")
6 |
7 | @export var noise_generators: Array
8 | var _planet
9 | var mask: float
10 | var ng_array: Array # May help a tiny bit by preallocating instead of allocating for every call.
11 | var min_max: MinMax
12 | var min_max_mutex := Mutex.new()
13 | var planet_radius: float # Shorthand for faster access.
14 |
15 | func init(_planet):
16 | self._planet = _planet
17 | self.min_max = MinMax.new()
18 | for ng in noise_generators:
19 | ng.init(_planet)
20 | ng_array = range(1, noise_generators.size())
21 | planet_radius = _planet.settings.radius
22 | calculate_min_max()
23 |
24 |
25 | # Get elevation of point on unit sphere from all noise generators.
26 | # Contains a few micro-optimizations like branchless calculations.
27 | func get_unscaled_elevation(point_on_unit_sphere: Vector3) -> float:
28 | var first_ng: NoiseGenerator = noise_generators[0]
29 | var first_layer_value: float = first_ng.evaluate(point_on_unit_sphere)
30 | var elevation: float = first_layer_value * first_ng.enabled_int
31 |
32 | for i in ng_array:
33 | # Get elevation when ng is enabled and use first layer as mask if needed.
34 | var ng: NoiseGenerator = noise_generators[i]
35 | var use_first_as_mask := ng.use_first_as_mask_int
36 | elevation += ng.evaluate(point_on_unit_sphere) * ng.enabled_int \
37 | * (first_layer_value * use_first_as_mask + 1 - use_first_as_mask)
38 | return elevation
39 |
40 |
41 | # Return previously retrieved elevation in proportion to the planet.
42 | func get_scaled_elevationa(elevation: float) -> float:
43 | return _planet.settings.radius * (1.0 + elevation)
44 |
45 |
46 | # Return previously retrieved elevation in proportion to the planet.
47 | func get_scaled_elevation(elevation: float) -> float:
48 | return planet_radius * (1.0 + elevation)
49 |
50 |
51 | # Approximates the theoretical minimal and maximal unscaled elevation.
52 | func calculate_min_max():
53 | var elevation: float
54 | var first_layer_value: float = noise_generators[0].strength * Const.MIN_MAX_APPROXIMATION
55 | if noise_generators[0].enabled:
56 | elevation = first_layer_value
57 |
58 | for i in ng_array:
59 | var ng: NoiseGenerator = noise_generators[i]
60 | if ng.enabled:
61 | var mask: float = first_layer_value if ng.use_first_as_mask else 1.0
62 | elevation += ng.strength * mask * Const.MIN_MAX_APPROXIMATION
63 | min_max.min_value = -elevation
64 | min_max.max_value = elevation
65 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/terrain_job.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name TerrainJob
3 |
4 | # Class that takes care of building one patch of terrain from PatchData object.
5 |
6 | const TERRAIN_PATCH_SCENE = preload("../../scenes/terrain/terrain_patch.tscn")
7 |
8 | signal job_finished(job, result)
9 |
10 | var _data: PatchData: get = get_data
11 | var _is_aborted: bool: get = is_aborted, set = abort
12 |
13 |
14 | func _init(data: PatchData):
15 | _data = data
16 |
17 |
18 | func run():
19 | if _is_aborted: # Check before running job.
20 | emit_signal("job_finished", self, null)
21 | return
22 | # Build the patch of terrain.
23 | var patch: TerrainPatch = TERRAIN_PATCH_SCENE.instantiate()
24 | patch.build(_data)
25 | if _is_aborted: # Check after running job.
26 | emit_signal("job_finished", self, null)
27 | else:
28 | emit_signal("job_finished", self, patch) # Return results.
29 |
30 |
31 | # "Setter" function used only to abort the job.
32 | func abort(b := true):
33 | _is_aborted = true
34 |
35 |
36 | func is_aborted() -> bool:
37 | return _is_aborted
38 |
39 |
40 | func get_data() -> PatchData:
41 | return _data
42 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/terrain_manager.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name TerrainManager
3 | extends Node3D
4 |
5 | const Const := preload("../constants.gd")
6 |
7 | var _cube_quadtree: CubeQuadTree
8 | var planet_settings: PlanetSettings
9 | var planet_material: Material
10 | var _logger := Logger.get_for(self)
11 |
12 |
13 | # Remove old patches, initialize quadtrees to build terrain patches.
14 | func generate(settings: PlanetSettings, material: Material):
15 | planet_settings = settings
16 | planet_material = material
17 | # Free all existing terrain patches.
18 | for child in get_children():
19 | child.queue_free()
20 | # Create the quadtree with new terrain patches.
21 | _cube_quadtree = CubeQuadTree.new(self)
22 |
23 |
24 | func set_viewer(viewer: Node3D):
25 | if _cube_quadtree:
26 | _cube_quadtree.set_viewer(viewer)
27 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/terrain_patch.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name TerrainPatch
3 | # Represents a patch of terrain tied to a quad tree node.
4 | extends MeshInstance3D
5 |
6 | const Const := preload("../constants.gd")
7 |
8 | var data: PatchData
9 | var quadnode: RefCounted
10 | var vertices: PackedVector3Array
11 | var triangles: PackedInt32Array
12 | var uvs: PackedVector2Array
13 | var normals: PackedVector3Array
14 | var faces: PackedVector3Array # Vertices in a format that physics can use.
15 |
16 | var _body_rid: RID # Godot's internal resource ID for the physics body.
17 | var _shape_rid: RID # As above, but for the bodies' shape.
18 |
19 |
20 | # Node enters scene tree. Finish configuring physics.
21 | func _ready():
22 | if _body_rid:
23 | PhysicsServer3D.body_set_space(_body_rid, get_world_3d().space)
24 |
25 |
26 | func _process(_delta):
27 | if quadnode:
28 | quadnode.visit()
29 |
30 |
31 | func _notification(what):
32 | if Const.COLLISIONS_ENABLED and what == NOTIFICATION_TRANSFORM_CHANGED:
33 | update_transform() # Manually update physics shape position.
34 |
35 |
36 | # Builds the terrain mesh from generator data.
37 | func build(data: PatchData):
38 | self.data = data
39 | self.quadnode = data.quadnode
40 | var verts_per_edge = data.verts_per_edge
41 | var num_verts = verts_per_edge * verts_per_edge
42 | var border_offset := 1.0 + Const.BORDER_SIZE * 2.0 / (data.settings.resolution - 1)
43 | var base_offset := data.axis_up + data.offset_a + data.offset_b
44 | var axis_a_scaled := data.axis_a * border_offset * 2.0
45 | var axis_b_scaled := data.axis_b * border_offset * 2.0
46 | var tri_idx := 0 # Mapping of vertex index to triangle
47 | var min_max := MinMax.new() # Store local min and max elevation.
48 | var shape_gen: ShapeGenerator = data.settings.shape_generator
49 | # Number of triangles: (verts_per_edge - 1)² * 3 vertices * 2 triangles
50 | triangles.resize((verts_per_edge - 1) * (verts_per_edge - 1) * 3 * 2)
51 | vertices.resize(num_verts)
52 | uvs.resize(num_verts)
53 | normals.resize(num_verts)
54 |
55 | # Build the mesh.
56 | for vertex_idx in num_verts:
57 | var x: int = vertex_idx / verts_per_edge
58 | var y: int = vertex_idx % verts_per_edge
59 | # Calculate position of this vertex.
60 | var percent: Vector2 = Vector2(x, y) / (verts_per_edge - 1)
61 | var point_on_unit_cube := base_offset + (percent.x - 0.5) * axis_a_scaled + (percent.y - 0.5) * axis_b_scaled
62 | var point_on_unit_sphere: Vector3 = point_on_unit_cube.normalized()
63 | var elevation: float = shape_gen.get_unscaled_elevation(point_on_unit_sphere)
64 | vertices[vertex_idx] = point_on_unit_sphere * shape_gen.get_scaled_elevation(elevation)
65 | uvs[vertex_idx].x = elevation
66 | min_max.add_value(elevation)
67 | # Build two triangles that form one quad like so:
68 | # 0--2 0 2
69 | # \ | | \
70 | # 1 3 1--3
71 | if x < verts_per_edge - 1 and y < verts_per_edge - 1:
72 | triangles[tri_idx] = vertex_idx
73 | triangles[tri_idx + 1] = vertex_idx + verts_per_edge + 1
74 | triangles[tri_idx + 2] = vertex_idx + verts_per_edge
75 | triangles[tri_idx + 3] = vertex_idx
76 | triangles[tri_idx + 4] = vertex_idx + 1
77 | triangles[tri_idx + 5] = vertex_idx + verts_per_edge + 1
78 | tri_idx += 6
79 |
80 | # Adjust global min_max.
81 | shape_gen.min_max_mutex.lock()
82 | shape_gen.min_max.add_value(min_max.min_value)
83 | shape_gen.min_max.add_value(min_max.max_value)
84 | shape_gen.min_max_mutex.unlock()
85 | # Manipulate vertices.
86 | calc_normals() # Calculate normals before dipping border vertices,
87 | calc_terrain_border() # resulting in smoother terrain patch edges.
88 | calc_uvs()
89 |
90 | if Const.COLLISIONS_ENABLED and data.settings.has_collisions:
91 | init_physics()
92 |
93 | # Prepare mesh arrays and create mesh.
94 | var mesh_arrays := []
95 | mesh_arrays.resize(Mesh.ARRAY_MAX)
96 | mesh_arrays[Mesh.ARRAY_VERTEX] = vertices
97 | mesh_arrays[Mesh.ARRAY_NORMAL] = normals
98 | mesh_arrays[Mesh.ARRAY_TEX_UV] = uvs
99 | mesh_arrays[Mesh.ARRAY_INDEX] = triangles
100 | mesh = ArrayMesh.new()
101 | mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, mesh_arrays)
102 |
103 | # Special material needed?
104 | if not Engine.is_editor_hint() \
105 | and PGGlobals.colored_patches \
106 | and data.material is StandardMaterial3D:
107 | data.material = data.material.duplicate()
108 | data.material.albedo_color = Color(randi())
109 | mesh.surface_set_material(0, data.material)
110 | set_visible(false)
111 |
112 |
113 | # Create physics body & shape.
114 | # TODO: PhysicsServer is not multi-threading safe here, should be fixed in 4.0.
115 | func init_physics():
116 | data.settings.shared_mutex.lock()
117 | _shape_rid = PhysicsServer3D.concave_polygon_shape_create()
118 | _body_rid = PhysicsServer3D.body_create()
119 | data.settings.shared_mutex.unlock()
120 | calc_face_vertices() # Prepare array with ordered face vertices.
121 | update_transform()
122 | PhysicsServer3D.shape_set_data(_shape_rid, faces)
123 | PhysicsServer3D.body_add_shape(_body_rid, _shape_rid)
124 | PhysicsServer3D.body_set_shape_disabled(_body_rid, 0, true)
125 | PhysicsServer3D.body_set_collision_layer(_body_rid, 1)
126 | PhysicsServer3D.body_set_collision_mask(_body_rid, 1)
127 |
128 |
129 | func update_transform():
130 | print(_body_rid)
131 | var transform: Transform3D = data.settings._planet.global_transform
132 | PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM,
133 | transform)
134 |
135 |
136 | # Prevents jagged LOD borders by lowering border vertices.
137 | func calc_terrain_border():
138 | var verts_per_edge = data.verts_per_edge
139 | var dip: float = pow(Const.BORDER_DIP, data.size)
140 | # Top and bottom border.
141 | for i in range(0, verts_per_edge * verts_per_edge, verts_per_edge):
142 | var idx: = i
143 | vertices[idx] *= dip
144 | idx = i + verts_per_edge - 1
145 | vertices[idx] *= dip
146 | # Left and right border.
147 | for i in range(1, verts_per_edge - 1):
148 | var idx: = i
149 | vertices[idx] *= dip
150 | idx = i + verts_per_edge * (verts_per_edge - 1)
151 | vertices[idx] *= dip
152 |
153 |
154 | # Calculates smooth normals for all vertices by averaging (normalizing) mesh
155 | # normals. This is done by accumulating the normals calculated from triangles
156 | # and normalizing the resulting vector, thus building an average.
157 | func calc_normals():
158 | for i in range(0, triangles.size(), 3):
159 | var vi_a := triangles[i]
160 | var vi_b := triangles[i+1]
161 | var vi_c := triangles[i+2]
162 | var a := vertices[vi_a]
163 | var b := vertices[vi_b]
164 | var c := vertices[vi_c]
165 | var norm: Vector3 = -(b - a).cross(c - a)
166 | normals[vi_a] += norm
167 | normals[vi_b] += norm
168 | normals[vi_c] += norm
169 | for i in normals.size():
170 | normals[i] = normals[i].normalized()
171 |
172 |
173 | # Get UV coordinates into the appropriate range.
174 | func calc_uvs():
175 | var min_max: MinMax = data.settings.shape_generator.min_max
176 | var min_value := min_max.min_value
177 | var max_value := min_max.max_value
178 | for i in uvs.size():
179 | uvs[i].x = remap(uvs[i].x, min_value, max_value, 0.0, 1.0)
180 |
181 |
182 | # Returns the meshes vertices, ordered as triangle points (a, b, c, a, b, c, …).
183 | func calc_face_vertices():
184 | faces.resize(triangles.size())
185 | for i in triangles.size():
186 | # face vertex = vertices at index of current triangle point.
187 | faces[i] = vertices[triangles[i]]
188 | return faces
189 |
190 |
191 | func set_visible(visible: bool):
192 | # Enable/disable shape when visibility of this patch changes.
193 | if _body_rid:
194 | PhysicsServer3D.body_set_shape_disabled(_body_rid, 0, !visible)
195 | super.set_visible(visible)
196 |
197 |
198 | func _exit_tree():
199 | if _body_rid:
200 | PhysicsServer3D.free_rid(_body_rid)
201 | if _shape_rid:
202 | PhysicsServer3D.free_rid(_shape_rid)
203 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/terrain/worker_thread.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | class_name WorkerThread
3 | extends Thread
4 | # Represents a single worker thread that processes terrain jobs that are set by
5 | # the job queue.
6 |
7 | const Const := preload("../constants.gd")
8 |
9 | var semaphore: Semaphore
10 | var queue: RefCounted
11 |
12 |
13 | func _init(job_queue: RefCounted):
14 | self.queue = job_queue
15 | self.semaphore = job_queue.semaphore
16 | start(Callable(self, "work"))
17 |
18 |
19 | # Thread function.
20 | func work(userdata = null):
21 | while true:
22 | semaphore.wait() # Wait until we posted by queue.
23 | var job: TerrainJob = queue.fetch_job()
24 | if job:
25 | job.run()
26 | else:
27 | break # Semaphore posted but no jobs queued: Worker should stop.
28 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/utils/benchmark.gd:
--------------------------------------------------------------------------------
1 | extends Node3D
2 | # Simple benchmark.
3 |
4 | const Const := preload("../constants.gd")
5 |
6 | @onready var _label := $CanvasLayer/Control/Panel/MarginContainer/VBoxContainer/Label
7 | @onready var _spin_box := $CanvasLayer/Control/Panel/MarginContainer/VBoxContainer/HBoxContainer/SpinBox
8 | @onready var _button_benchmark := $CanvasLayer/Control/Panel/MarginContainer/VBoxContainer/Button
9 | @onready var _planet := $Planet
10 | var _duration: int
11 |
12 |
13 | func _enter_tree():
14 | PGGlobals.benchmark_mode = true
15 |
16 |
17 | func _exit_tree():
18 | PGGlobals.benchmark_mode = false
19 |
20 |
21 | func _ready():
22 | start()
23 |
24 |
25 | func _on_Button_pressed():
26 | start()
27 |
28 |
29 | func start():
30 | _button_benchmark.disabled = true
31 | # Finish running jobs.
32 | _label.text = "Waiting for current jobs to finish..."
33 | if PGGlobals.job_queue.is_working():
34 | await PGGlobals.job_queue.all_finished
35 | # Run the actual benchmark.
36 | _label.text = "Benchmarking..."
37 | _duration = 0
38 | for i in _spin_box.value:
39 | var _tstart := Time.get_ticks_usec()
40 | $Planet.generate()
41 | await PGGlobals.job_queue.all_finished
42 | var _deltat = Time.get_ticks_usec() - _tstart
43 | _duration += _deltat
44 | print("Iteration %d finished in %.3fms." \
45 | % [i + 1, (_deltat) / 1000.0])
46 | await get_tree().idle_frame
47 | stop()
48 | _button_benchmark.disabled = false
49 |
50 |
51 | func stop():
52 | var text = "Generated %d times in %.3fms." \
53 | % [_spin_box.value, _duration / 1000.0]
54 | _label.text = text
55 | print(text)
56 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/utils/logger.gd:
--------------------------------------------------------------------------------
1 | class_name Logger
2 |
3 | class Standard:
4 | var _context := ""
5 |
6 |
7 | func _init(context):
8 | _context = context
9 |
10 |
11 | func debug(msg: String):
12 | pass
13 |
14 |
15 | func warn(msg: String):
16 | push_warning("[WARNING] %s: %s" % [_context, msg])
17 |
18 |
19 | func error(msg: String):
20 | push_error("[ERROR] %s: %s" % [_context, msg])
21 |
22 |
23 | class Verbose extends Standard:
24 | func _init(context: String):
25 | super(context)
26 | pass
27 |
28 |
29 | func debug(msg: String):
30 | print("[DEBUG] %s: %s" % [_context , msg])
31 |
32 |
33 | static func get_for(owner: Object) -> Standard:
34 | var context = owner.get_script().resource_path.get_file()
35 | if OS.is_stdout_verbose():
36 | return Verbose.new(context)
37 | return Standard.new(context)
38 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/utils/orbiting_camera.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node3D
3 |
4 | @export var radius: float = 50.0: set = setRadius
5 | @export var speed: float = 0.1
6 | @export var _play_in_editor: bool = true
7 |
8 | @onready var _camera = $Camera3D
9 |
10 |
11 | func _ready():
12 | rotation_degrees.y = 0
13 | setRadius(radius)
14 |
15 |
16 | func _process(delta):
17 | if Engine.is_editor_hint() and not _play_in_editor:
18 | return
19 | rotate(transform.basis.y.normalized(), speed * delta)
20 |
21 |
22 | func setRadius(new):
23 | radius = new
24 | if _camera:
25 | _camera.position.z = radius
26 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/utils/origin_shifter.gd:
--------------------------------------------------------------------------------
1 | # Shift all nodes so the parent node always stays close to the center.
2 | extends Node
3 |
4 | const MAX_DISTANCE := 2000.0
5 |
6 | @export var world_node_path: NodePath
7 | @onready var world_node: Node3D = get_node_or_null(world_node_path)
8 | @onready var parent := get_parent()
9 |
10 | func _ready():
11 | if !world_node:
12 | world_node = get_node("../..")
13 |
14 | func _process(delta):
15 | if parent.global_transform.origin.length() > MAX_DISTANCE:
16 | shift_origin()
17 |
18 | func shift_origin():
19 | var offset: Vector3 = parent.global_transform.origin
20 | for child in world_node.get_children():
21 | if child is Node3D:
22 | child.global_translate(-offset)
23 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/utils/pg_globals.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | # Global settings for Planet Generator.
3 | extends Node
4 |
5 | const Const := preload("../constants.gd")
6 |
7 | var wireframe: bool = false: set = set_wireframe
8 | var colored_patches: bool # Colors patches of terrain randomly.
9 | var benchmark_mode: bool # re-generates planets even if there are still active threads.
10 | var solar_systems: Array = []
11 | var job_queue := JobQueue.new() # Global queue for TerrainJobs.
12 | var speed_scale: float = 0.001
13 |
14 |
15 | func _ready():
16 | if Const.THREADS_ENABLED:
17 | set_process(false) # Otherwise, process queue in single thread.
18 |
19 |
20 | func _exit_tree():
21 | job_queue.clean_up()
22 |
23 |
24 | func queue_terrain_patch(data: PatchData) -> TerrainJob:
25 | var job := TerrainJob.new(data)
26 | job_queue.queue(job)
27 | return job
28 |
29 |
30 | func register_solar_system(sys: Node):
31 | solar_systems.append(sys)
32 |
33 |
34 | func unregister_solar_system(sys: Node):
35 | solar_systems.erase(sys)
36 |
37 |
38 | func set_wireframe(value: bool):
39 | wireframe = value
40 | RenderingServer.set_debug_generate_wireframes(value)
41 | if value:
42 | get_viewport().set_debug_draw(SubViewport.DEBUG_DRAW_WIREFRAME)
43 | else:
44 | get_viewport().set_debug_draw(SubViewport.DEBUG_DRAW_DISABLED);
45 |
46 |
47 | func _process(delta):
48 | job_queue.process_queue_without_threads()
49 |
50 |
51 | func _input(event):
52 | if Engine.is_editor_hint():
53 | return
54 | if Input.is_action_just_pressed("toggle_mouse_capture"):
55 | if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
56 | Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
57 | else:
58 | Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
59 |
--------------------------------------------------------------------------------
/addons/hoimar.planetgen/scripts/utils/third_person_camera.gd:
--------------------------------------------------------------------------------
1 | extends Node3D
2 |
3 | const Constants := preload("../constants.gd")
4 |
5 | @export var _radius: float = 0.6: get = get_radius, set = set_radius
6 |
7 | @onready var _camera := $Camera3D
8 | @onready var _org_rotation := transform.basis.get_euler()
9 |
10 | #tween camera back to original pos
11 | func _process(delta):
12 | if Input.is_action_just_released("toggle_camera_mode"):
13 | var _tween = create_tween()
14 | _tween.tween_property(self, "rotation", _org_rotation, 1.2).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT)
15 | _tween.play()
16 |
17 | #Use mouse to rotate camera
18 | func _input(event):
19 | if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED and Input.is_action_pressed("toggle_camera_mode"):
20 | var _mouse_speed = event.relative * Constants.MOUSE_SENSITIVITY * 0.05
21 | rotate(transform.basis.y.normalized(), deg_to_rad(-_mouse_speed.x))
22 | rotate(transform.basis.x.normalized(), deg_to_rad(-_mouse_speed.y))
23 |
24 | func set_radius(new: float):
25 | _radius = new
26 | _camera.transform.origin = Vector3.ZERO
27 | _camera.translate_object_local(Vector3(0, 0, _radius))
28 |
29 | func get_radius():
30 | return _radius
31 |
--------------------------------------------------------------------------------
/default_env.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=2 format=3 uid="uid://cjhhw6kysaswd"]
2 |
3 | [sub_resource type="Sky" id="1"]
4 |
5 | [resource]
6 | background_mode = 2
7 | sky = SubResource("1")
8 | ambient_light_color = Color(0.137255, 0.156863, 0.184314, 1)
9 |
--------------------------------------------------------------------------------
/demos/quadtree_terrain_demo.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node3D
3 |
4 |
5 | @export var _play_in_editor: bool = true: set = set_play_in_editor
6 | @export var _rotation_speed: float = 200
7 | @onready var _view_position_rig := $ViewPositionRig
8 | @onready var _view_position := $ViewPositionRig/ViewPosition
9 | @onready var _planet := $SolarSystem/TestPlanet
10 |
11 |
12 | func _ready():
13 | PGGlobals.wireframe = true
14 | #PGGlobals.colored_patches = true
15 | _planet._terrain.set_viewer(_view_position)
16 |
17 |
18 | func _process(delta):
19 | if Engine.is_editor_hint() and not _play_in_editor:
20 | return
21 | _view_position_rig.rotate_y(_rotation_speed * PGGlobals.speed_scale * delta)
22 |
23 |
24 | func set_play_in_editor(new: bool):
25 | _play_in_editor = new
26 | if _planet:
27 | _planet._terrain.set_viewer(_view_position)
28 |
--------------------------------------------------------------------------------
/demos/quadtree_terrain_demo.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=12 format=3 uid="uid://cv3jth7u5rno3"]
2 |
3 | [ext_resource type="Script" path="res://demos/quadtree_terrain_demo.gd" id="1"]
4 | [ext_resource type="PackedScene" uid="uid://btubuuiux53j4" path="res://addons/hoimar.planetgen/scenes/gui/gui.tscn" id="2"]
5 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/solar_system.gd" id="3_hi6yo"]
6 | [ext_resource type="PackedScene" uid="uid://dtmgyl1uf7auy" path="res://addons/hoimar.planetgen/scenes/celestial_bodies/planet.tscn" id="4"]
7 | [ext_resource type="Resource" uid="uid://kono1hjgsisy" path="res://addons/hoimar.planetgen/planet_presets/test_planet_settings.tres" id="6"]
8 |
9 | [sub_resource type="Gradient" id="1"]
10 | offsets = PackedFloat32Array(0, 0.5, 0.533923, 0.557522, 0.864307, 1)
11 | colors = PackedColorArray(0.05476, 0.177625, 0.311523, 1, 0.0473442, 0.462289, 0.577148, 1, 0.666992, 0.557391, 0.0364761, 1, 0.224285, 0.416992, 0.118908, 1, 0.409842, 0.366813, 0.233597, 1, 1, 0.981964, 0.953125, 1)
12 |
13 | [sub_resource type="GradientTexture2D" id="2"]
14 | gradient = SubResource("1")
15 |
16 | [sub_resource type="StandardMaterial3D" id="3"]
17 | albedo_texture = SubResource("2")
18 |
19 | [sub_resource type="SphereMesh" id="4"]
20 |
21 | [sub_resource type="Sky" id="5"]
22 |
23 | [sub_resource type="Environment" id="6"]
24 | background_mode = 2
25 | sky = SubResource("5")
26 | ambient_light_color = Color(0.992157, 0.988235, 0.988235, 1)
27 | ambient_light_sky_contribution = 0.0
28 | tonemap_mode = 2
29 | glow_strength = 0.75
30 | glow_bloom = 1.0
31 | glow_blend_mode = 1
32 |
33 | [node name="QuadTreeTerrainDemo" type="Node3D"]
34 | script = ExtResource("1")
35 | _play_in_editor = false
36 |
37 | [node name="Gui" parent="." instance=ExtResource("2")]
38 |
39 | [node name="SolarSystem" type="Node3D" parent="."]
40 | script = ExtResource("3_hi6yo")
41 |
42 | [node name="TestPlanet" parent="SolarSystem" instance=ExtResource("4")]
43 | settings = ExtResource("6")
44 | material = SubResource("3")
45 | solar_system_path = NodePath("..")
46 |
47 | [node name="ViewPositionRig" type="Node3D" parent="."]
48 | transform = Transform3D(-0.786847, 0, -0.6176, 0, 1, 0, 0.6176, 0, -0.786847, 0, 0, 0)
49 |
50 | [node name="ViewPosition" type="MeshInstance3D" parent="ViewPositionRig"]
51 | transform = Transform3D(1, 0, 0, 0, 1, 0, -1.42109e-14, 0, 1, -105, 0, 0)
52 | mesh = SubResource("4")
53 |
54 | [node name="Camera3D" type="Camera3D" parent="."]
55 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 200)
56 | current = true
57 | near = 0.5
58 | far = 1000.0
59 |
60 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
61 | environment = SubResource("6")
62 |
--------------------------------------------------------------------------------
/demos/solar_system_demo.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=13 format=3 uid="uid://xqufprx78lly"]
2 |
3 | [ext_resource type="Script" path="res://addons/hoimar.planetgen/scripts/celestial_bodies/solar_system.gd" id="1"]
4 | [ext_resource type="PackedScene" uid="uid://dtmgyl1uf7auy" path="res://addons/hoimar.planetgen/scenes/celestial_bodies/planet.tscn" id="2"]
5 | [ext_resource type="Resource" uid="uid://dd88lsn35g60e" path="res://addons/hoimar.planetgen/planet_presets/earthlike_planet_settings.tres" id="3"]
6 | [ext_resource type="Environment" uid="uid://b0aokqtycy50o" path="res://addons/hoimar.planetgen/resources/space_environment.tres" id="4"]
7 | [ext_resource type="PackedScene" uid="uid://btubuuiux53j4" path="res://addons/hoimar.planetgen/scenes/gui/gui.tscn" id="5"]
8 | [ext_resource type="Resource" uid="uid://bfhq5kbvtn36a" path="res://addons/hoimar.planetgen/planet_presets/alien_planet_settings.tres" id="7"]
9 | [ext_resource type="Material" uid="uid://byxwrfsxs3aot" path="res://addons/hoimar.planetgen/resources/materials/alien_planet_material.tres" id="9"]
10 | [ext_resource type="PackedScene" uid="uid://fqjq3odx4ugm" path="res://addons/hoimar.planetgen/scenes/celestial_bodies/sun.tscn" id="10"]
11 | [ext_resource type="Material" uid="uid://8wwbbtllcisy" path="res://addons/hoimar.planetgen/resources/materials/moon_material.tres" id="11"]
12 | [ext_resource type="Material" uid="uid://b1jwk81h16hlg" path="res://addons/hoimar.planetgen/resources/materials/earthlike_planet_material.tres" id="12"]
13 | [ext_resource type="PackedScene" uid="uid://bqwkjkg2uk3n7" path="res://addons/hoimar.planetgen/scenes/spacecraft/player_ship.tscn" id="12_pcwfe"]
14 | [ext_resource type="Resource" uid="uid://c15gyg7nxeyuj" path="res://addons/hoimar.planetgen/planet_presets/moon_settings.tres" id="13"]
15 |
16 | [node name="SolarSystemDemo" type="Node3D"]
17 | script = ExtResource("1")
18 |
19 | [node name="Gui" parent="." instance=ExtResource("5")]
20 |
21 | [node name="Sun" parent="." instance=ExtResource("10")]
22 | transform = Transform3D(0.68603, 1.10307e-05, 0.727569, 0, 1, -1.51609e-05, -0.727569, 1.04009e-05, 0.68603, 5000, 0, 5000)
23 | solar_system_path = NodePath("..")
24 |
25 | [node name="EarthlikePlanet" parent="." instance=ExtResource("2")]
26 | settings = ExtResource("3")
27 | material = ExtResource("12")
28 | solar_system_path = NodePath("..")
29 | sun_path = NodePath("../Sun")
30 |
31 | [node name="AlienPlanet" parent="." instance=ExtResource("2")]
32 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3064.12, 811.559, 936.359)
33 | settings = ExtResource("7")
34 | material = ExtResource("9")
35 | solar_system_path = NodePath("..")
36 | sun_path = NodePath("../Sun")
37 |
38 | [node name="Moon" parent="." instance=ExtResource("2")]
39 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1482, 347, 276)
40 | settings = ExtResource("13")
41 | material = ExtResource("11")
42 | solar_system_path = NodePath("..")
43 | sun_path = NodePath("../Sun")
44 |
45 | [node name="SpaceEnvironment" type="WorldEnvironment" parent="."]
46 | environment = ExtResource("4")
47 |
48 | [node name="Ship" parent="." instance=ExtResource("12_pcwfe")]
49 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 284.871)
50 |
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="Planet Generator"
14 | run/main_scene="res://demos/solar_system_demo.tscn"
15 | config/features=PackedStringArray("4.1")
16 | config/icon="res://addons/hoimar.planetgen/resources/icons/globe.svg"
17 |
18 | [autoload]
19 |
20 | PGGlobals="*res://addons/hoimar.planetgen/scripts/utils/pg_globals.gd"
21 |
22 | [display]
23 |
24 | window/size/viewport_width=1600
25 | window/size/viewport_height=900
26 |
27 | [editor_plugins]
28 |
29 | enabled=PackedStringArray()
30 |
31 | [input]
32 |
33 | ui_left={
34 | "deadzone": 0.5,
35 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
36 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
37 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
38 | ]
39 | }
40 | ui_right={
41 | "deadzone": 0.5,
42 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
43 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null)
44 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
45 | ]
46 | }
47 | ui_up={
48 | "deadzone": 0.5,
49 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
50 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
51 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
52 | ]
53 | }
54 | ui_down={
55 | "deadzone": 0.5,
56 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
57 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
58 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
59 | ]
60 | }
61 | toggle_colored_patches={
62 | "deadzone": 0.5,
63 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194333,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
64 | ]
65 | }
66 | speedup={
67 | "deadzone": 0.5,
68 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194325,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
69 | ]
70 | }
71 | toggle_wireframe={
72 | "deadzone": 0.5,
73 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194332,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
74 | ]
75 | }
76 | toggle_camera_mode={
77 | "deadzone": 0.5,
78 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194326,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
79 | ]
80 | }
81 | toggle_mouse_capture={
82 | "deadzone": 0.5,
83 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
84 | ]
85 | }
86 |
87 | [physics]
88 |
89 | 3d/default_gravity_vector=Vector3(0, 0, 0)
90 | 3d/active_soft_world=false
91 |
92 | [rendering]
93 |
94 | environment/defaults/default_environment="res://default_env.tres"
95 | threads/thread_model=2
96 | quality/shadows/filter_mode=2
97 | quality/filters/anisotropic_filter_level=16
98 | limits/buffers/blend_shape_max_buffer_size_kb=8192
99 | limits/buffers/immediate_buffer_size_kb=4096
100 | quality/filters/msaa=2
101 |
--------------------------------------------------------------------------------