├── .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 Planet-Generator icon 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 | flight towards earthlike planet a procedural moon appears behind the procedural horizon 114 | typical scene the in Godot editor 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 | --------------------------------------------------------------------------------