Compare commits

..

4 Commits

Author SHA1 Message Date
Nikolai Fesenko
a45fc71a6d changed position of cart 2025-08-13 21:20:24 +02:00
Nikolai Fesenko
f80de943ec terrain ressources 2025-08-13 21:19:30 +02:00
Nikolai Fesenko
85d50d3bd4 new terrain plugin 2025-08-13 21:08:35 +02:00
Nikolai Fesenko
43fb8410c3 new build mechanic 2025-08-13 21:00:22 +02:00
236 changed files with 11929 additions and 43 deletions

View File

@@ -5,3 +5,4 @@
[node name="DoubleBeds" type="Node3D"] [node name="DoubleBeds" type="Node3D"]
[node name="DoubleBeds" parent="." instance=ExtResource("1_kkvf5")] [node name="DoubleBeds" parent="." instance=ExtResource("1_kkvf5")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.83435, 0, 0)

View File

@@ -1,15 +1,16 @@
[gd_scene load_steps=7 format=3 uid="uid://dim2geqhn6d35"] [gd_scene load_steps=8 format=3 uid="uid://dim2geqhn6d35"]
[ext_resource type="Script" uid="uid://dhls6unflalvd" path="res://Scripts/cart.gd" id="1_esjgi"] [ext_resource type="Script" uid="uid://dhls6unflalvd" path="res://Scripts/cart.gd" id="1_esjgi"]
[ext_resource type="ArrayMesh" uid="uid://p3d7iitismhf" path="res://Blends/Cart/cart-bottom.obj" id="1_ux2tx"] [ext_resource type="ArrayMesh" uid="uid://p3d7iitismhf" path="res://Blends/Cart/cart-bottom.obj" id="1_ux2tx"]
[ext_resource type="ArrayMesh" uid="uid://docto7iocves6" path="res://Blends/Cart/wheels.obj" id="2_2wj72"] [ext_resource type="ArrayMesh" uid="uid://docto7iocves6" path="res://Blends/Cart/wheels.obj" id="2_2wj72"]
[ext_resource type="ArrayMesh" uid="uid://cayqoyyq7nbij" path="res://Blends/Cart/cart-top.obj" id="3_2wj72"] [ext_resource type="ArrayMesh" uid="uid://cayqoyyq7nbij" path="res://Blends/Cart/cart-top.obj" id="3_2wj72"]
[ext_resource type="Script" uid="uid://bcmd74mxocn7e" path="res://Scripts/building_area.gd" id="5_eosii"]
[sub_resource type="BoxShape3D" id="BoxShape3D_esjgi"] [sub_resource type="BoxShape3D" id="BoxShape3D_esjgi"]
size = Vector3(22.2341, 4.23804, 0.494629) size = Vector3(22.2341, 4.23804, 0.494629)
[sub_resource type="BoxShape3D" id="BoxShape3D_eosii"] [sub_resource type="BoxShape3D" id="BoxShape3D_eosii"]
size = Vector3(17.5376, 0.0286865, 2.28394) size = Vector3(5.40002, 4.29805, 2.28394)
[node name="Cart" type="Node3D" node_paths=PackedStringArray("cartTop")] [node name="Cart" type="Node3D" node_paths=PackedStringArray("cartTop")]
script = ExtResource("1_esjgi") script = ExtResource("1_esjgi")
@@ -60,15 +61,21 @@ shape = SubResource("BoxShape3D_esjgi")
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.282789, 1.61902, -2.6054) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.282789, 1.61902, -2.6054)
shape = SubResource("BoxShape3D_esjgi") shape = SubResource("BoxShape3D_esjgi")
[node name="BuildingArea2" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.23003, 0, 0)
script = ExtResource("5_eosii")
metadata/is_building_area = true
[node name="smallBuildingArea2" type="CollisionShape3D" parent="BuildingArea2"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.69414, 1.02766, -1.22106)
shape = SubResource("BoxShape3D_eosii")
metadata/is_building_area = true
[node name="BuildingArea" type="StaticBody3D" parent="."] [node name="BuildingArea" type="StaticBody3D" parent="."]
script = ExtResource("5_eosii")
metadata/is_building_area = true metadata/is_building_area = true
[node name="CollisionShape3D" type="CollisionShape3D" parent="BuildingArea"] [node name="smallBuildingArea2" type="CollisionShape3D" parent="BuildingArea"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.374649, -0.275452, 2.38014) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.69414, 1.02766, -1.22106)
shape = SubResource("BoxShape3D_eosii")
metadata/is_building_area = true
[node name="CollisionShape3D2" type="CollisionShape3D" parent="BuildingArea"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.374649, -0.275452, -1.22106)
shape = SubResource("BoxShape3D_eosii") shape = SubResource("BoxShape3D_eosii")
metadata/is_building_area = true metadata/is_building_area = true

View File

@@ -1,10 +1,28 @@
[gd_scene load_steps=8 format=3 uid="uid://bj7y7q2qkpnci"] [gd_scene load_steps=11 format=3 uid="uid://bj7y7q2qkpnci"]
[ext_resource type="ArrayMesh" uid="uid://622ethh2pdfa" path="res://Blends/road/road.obj" id="4_jjvhh"] [ext_resource type="ArrayMesh" uid="uid://622ethh2pdfa" path="res://Blends/road/road.obj" id="4_jjvhh"]
[ext_resource type="PackedScene" uid="uid://dim2geqhn6d35" path="res://Scenes/Prefabs/cart.tscn" id="6_21xkr"] [ext_resource type="PackedScene" uid="uid://dim2geqhn6d35" path="res://Scenes/Prefabs/cart.tscn" id="6_21xkr"]
[ext_resource type="PackedScene" uid="uid://dy03tqug33fep" path="res://Blends/ground.blend" id="6_344ge"] [ext_resource type="PackedScene" uid="uid://dy03tqug33fep" path="res://Blends/ground.blend" id="6_344ge"]
[ext_resource type="Script" uid="uid://drrp1k2q71hq2" path="res://Scripts/camera_3d.gd" id="7_6bp64"] [ext_resource type="Script" uid="uid://drrp1k2q71hq2" path="res://Scripts/camera_3d.gd" id="7_6bp64"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_jjvhh"]
sky_top_color = Color(0.654771, 0.60129, 0.578102, 1)
sky_horizon_color = Color(0.866942, 0.845822, 0.831025, 1)
ground_horizon_color = Color(0.866942, 0.845822, 0.831025, 1)
[sub_resource type="Sky" id="Sky_kry3j"]
sky_material = SubResource("ProceduralSkyMaterial_jjvhh")
[sub_resource type="Environment" id="Environment_21xkr"]
background_mode = 2
sky = SubResource("Sky_kry3j")
tonemap_mode = 2
ssao_enabled = true
glow_enabled = true
fog_mode = 1
fog_density = 1.0
fog_depth_curve = 4.75681
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_21xkr"] [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_21xkr"]
lifetime_randomness = 0.55 lifetime_randomness = 0.55
emission_shape = 3 emission_shape = 3
@@ -18,25 +36,28 @@ size = Vector2(0.5, 0.5)
[sub_resource type="BoxShape3D" id="BoxShape3D_21xkr"] [sub_resource type="BoxShape3D" id="BoxShape3D_21xkr"]
[node name="Node3D" type="Node3D"] [node name="Main" type="Node3D"]
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_21xkr")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866025, -0.5, -2.18557e-08, 0, -4.37114e-08, 1, -0.5, 0.866025, 3.78552e-08, 0, 0, 0) transform = Transform3D(-0.866025, -0.5, -2.18557e-08, 0, -4.37114e-08, 1, -0.5, 0.866025, 3.78552e-08, 0, 0, 0)
shadow_enabled = true shadow_enabled = true
[node name="Road2" type="MeshInstance3D" parent="."] [node name="Road2" type="MeshInstance3D" parent="."]
transform = Transform3D(10.951, 0, 0, 0, 1, 0, 0, 0, 1, -54.1402, 37.1464, -56.7411) transform = Transform3D(10.951, 0, 0, 0, 1, 0, 0, 0, 1, -54.1402, 0.738562, -56.7411)
mesh = ExtResource("4_jjvhh") mesh = ExtResource("4_jjvhh")
skeleton = NodePath("../Road") skeleton = NodePath("../Road")
[node name="Road" type="MeshInstance3D" parent="."] [node name="Road" type="MeshInstance3D" parent="."]
transform = Transform3D(10.9512, 0, 0, 0, 1, 0, 0, 0, 1, -53.9758, 37.1737, -62.1734) transform = Transform3D(10.9512, 0, 0, 0, 1, 0, 0, 0, 1, -54.4288, 0.584906, -61.8752)
mesh = ExtResource("4_jjvhh") mesh = ExtResource("4_jjvhh")
[node name="GPUParticles3D" type="GPUParticles3D" parent="."] [node name="GPUParticles3D" type="GPUParticles3D" parent="."]
transform = Transform3D(3.70763, 0, 0, 0, 2.24982, 0, 0, 0, 3.71542, -7.77808, 47.2887, -60.0289) transform = Transform3D(3.70763, 0, 0, 0, 2.24982, 0, 0, 0, 3.71542, -7.77808, 10.8809, -60.0289)
emitting = false emitting = false
amount = 500 amount = 1006
speed_scale = 5.17 speed_scale = 5.17
randomness = 1.0 randomness = 1.0
trail_lifetime = 1.01 trail_lifetime = 1.01
@@ -44,17 +65,17 @@ process_material = SubResource("ParticleProcessMaterial_21xkr")
draw_pass_1 = SubResource("QuadMesh_21xkr") draw_pass_1 = SubResource("QuadMesh_21xkr")
[node name="SpotLight3D" type="SpotLight3D" parent="."] [node name="SpotLight3D" type="SpotLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.64431, 0.764764, 0, -0.764764, 0.64431, -15.9548, 43.2767, -60.5361) transform = Transform3D(1, 0, 0, 0, 0.64431, 0.764764, 0, -0.764764, 0.64431, -15.9548, 6.86886, -60.5361)
light_energy = 1.162 light_energy = 1.162
spot_range = 23.417 spot_range = 23.417
spot_angle = 89.99 spot_angle = 89.99
[node name="Cart" parent="." node_paths=PackedStringArray("mainCamera") instance=ExtResource("6_21xkr")] [node name="Cart" parent="." node_paths=PackedStringArray("mainCamera") instance=ExtResource("6_21xkr")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.31428, 39.9268, -60.2323) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.31428, 3.18503, -60.2323)
mainCamera = NodePath("../RigidBody3D/Camera3D") mainCamera = NodePath("../RigidBody3D/Camera3D")
[node name="RigidBody3D" type="RigidBody3D" parent="."] [node name="RigidBody3D" type="RigidBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.05618, 41.42, -58.2918) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.05618, 5.01216, -58.2918)
collision_layer = 128 collision_layer = 128
collision_mask = 128 collision_mask = 128
axis_lock_angular_x = true axis_lock_angular_x = true
@@ -62,7 +83,7 @@ axis_lock_angular_z = true
mass = 0.001 mass = 0.001
gravity_scale = 0.0 gravity_scale = 0.0
[node name="Camera3D" type="Camera3D" parent="RigidBody3D" node_paths=PackedStringArray("ownRigidBody", "endZoom")] [node name="Camera3D" type="Camera3D" parent="RigidBody3D" node_paths=PackedStringArray("ownRigidBody", "endZoom", "particlesSystem", "worldEnvironmentSystem")]
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 17.894, 14) transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 17.894, 14)
current = true current = true
script = ExtResource("7_6bp64") script = ExtResource("7_6bp64")
@@ -70,6 +91,8 @@ rayLength = 1000.0
camera_speed = 2.0 camera_speed = 2.0
ownRigidBody = NodePath("..") ownRigidBody = NodePath("..")
endZoom = NodePath("../endZoom") endZoom = NodePath("../endZoom")
particlesSystem = NodePath("../../GPUParticles3D")
worldEnvironmentSystem = NodePath("../../WorldEnvironment")
[node name="DebugLabel1" type="Label" parent="RigidBody3D/Camera3D"] [node name="DebugLabel1" type="Label" parent="RigidBody3D/Camera3D"]
offset_right = 40.0 offset_right = 40.0
@@ -84,7 +107,7 @@ shape = SubResource("BoxShape3D_21xkr")
debug_color = Color(0.895552, 0, 0.381247, 1) debug_color = Color(0.895552, 0, 0.381247, 1)
[node name="ground" parent="." instance=ExtResource("6_344ge")] [node name="ground" parent="." instance=ExtResource("6_344ge")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 20.3213, 36.9694, -59.4263) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 20.321, 0.384693, -59.426)
[node name="ground2" parent="." instance=ExtResource("6_344ge")] [node name="ground2" parent="." instance=ExtResource("6_344ge")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 180.354, 36.969, -59.426) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 180.354, 0.385, -59.426)

41
Scripts/building_area.gd Normal file
View File

@@ -0,0 +1,41 @@
extends StaticBody3D
@onready var beds = preload("res://Scenes/Prefabs/DoubleBeds.tscn")
var areas
var previewObject: Node3D
var is_placed = false
func _ready() -> void:
areas = get_children()
Global.exit_build_mode.connect(_on_exit_build_mode)
func _input_event(camera: Camera3D, event: InputEvent, event_position: Vector3, normal: Vector3, shape_idx: int) -> void:
if event.is_action_pressed("mouse_click") and Global.build_mode:
place_object()
func _mouse_enter() -> void:
if !is_placed and Global.build_mode:
show_preview()
func _mouse_exit() -> void:
if !is_placed and Global.build_mode:
hide_preview()
func show_preview():
previewObject = beds.instantiate()
areas[0].add_child(previewObject)
func hide_preview():
if is_placed != true:
if previewObject != null:
previewObject.queue_free()
func place_object():
is_placed = true
func _on_exit_build_mode():
hide_preview()

View File

@@ -0,0 +1 @@
uid://bcmd74mxocn7e

View File

@@ -4,6 +4,8 @@ extends Camera3D
@export var camera_speed: float @export var camera_speed: float
@export var ownRigidBody: RigidBody3D @export var ownRigidBody: RigidBody3D
@export var endZoom: Node3D @export var endZoom: Node3D
@export var particlesSystem: GPUParticles3D
@export var worldEnvironmentSystem: WorldEnvironment
var debugLabel var debugLabel
var global_delta var global_delta
var default_pos var default_pos
@@ -11,9 +13,13 @@ var default_pos
func _ready() -> void: func _ready() -> void:
default_pos = self.position default_pos = self.position
debugLabel = $DebugLabel1 debugLabel = $DebugLabel1
particlesSystem.emitting = true
var environment = worldEnvironmentSystem.environment
environment.fog_enabled = true
func _process(delta: float) -> void: func _process(delta: float) -> void:
debugLabel.text = "Mode: " + str(Global.build_mode)
global_delta = delta global_delta = delta
look_at(ownRigidBody.position) look_at(ownRigidBody.position)
self.position.y = -0.1 * pow(self.position.z,2) + 40 self.position.y = -0.1 * pow(self.position.z,2) + 40

View File

@@ -5,31 +5,10 @@ extends Node3D
@export var cartTop: MeshInstance3D @export var cartTop: MeshInstance3D
@export var mainCamera: Camera3D @export var mainCamera: Camera3D
var build_mode = false
var previewObject var previewObject
var targetPos var targetPos
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
if event.is_action_pressed("hide_top"): if event.is_action_pressed("hide_top"):
cartTop.visible = !cartTop.visible cartTop.visible = !cartTop.visible
if event.is_action_pressed("enter_build_mode"): #add_preview()
build_mode = !build_mode
add_preview()
func _process(_delta: float) -> void:
if build_mode:
targetPos = mainCamera.getGlobalRayTargetObject()
#mainCamera.debugLabel.text = targetPos.collider.name
if is_instance_valid(targetPos):
if targetPos.collider.has_meta("is_building_area"):
#if targetPos.collider.is_building_area == true:
previewObject.visible = true
previewObject.global_position = targetPos.position
else:
previewObject.visible = false
func add_preview():
previewObject = beds.instantiate()
get_tree().root.get_child(0).add_child(previewObject)

17
Scripts/global_script.gd Normal file
View File

@@ -0,0 +1,17 @@
extends Node3D
@export var debugLabel1: Label
signal exit_build_mode
var build_mode: bool = false
func _input(event: InputEvent) -> void:
if event.is_action_released("enter_build_mode"):
if build_mode:
exit_build_mode.emit()
build_mode = false
else:
build_mode = true

View File

@@ -0,0 +1 @@
uid://be4romsmai6jd

View File

@@ -0,0 +1 @@
extends CollisionShape3D

View File

@@ -0,0 +1 @@
uid://c3sewowdqkd83

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,52 @@
![Terrain3D Logo](/doc/docs/images/terrain3d.jpg)
# Terrain3D
A high performance, editable terrain system for Godot 4.
## Features
* Written in C++ as a GDExtension addon, which works with official builds of Godot Engine
* [Can be accessed](https://terrain3d.readthedocs.io/en/stable/docs/programming_languages.html) by GDScript, C#, and any language Godot supports
* Terrains as small as 64x64m up to 65.5x65.5km (4295km^2) in non-contiguous and variable sized regions
* Up to 32 textures
* Up to 10 levels of detail for the terrain mesh
* Foliage instancing, with up to 10 levels of detail, and a shadow impostor
* Sculpting, holes, texture painting, texture detiling, painting colors and wetness
* Imports heightmaps from [HTerrain](https://github.com/Zylann/godot_heightmap_plugin/), Gaea, World Creator, World Machine, Unity, Unreal and any tool that can export a heightmap. See [heightmaps](https://terrain3d.readthedocs.io/en/stable/docs/heightmaps.html)
## Games Using Terrain3D
Please see the [featured games using Terrain3D](https://terrain3d.readthedocs.io/en/latest/docs/games.html) for examples of what it can do.
## Getting Started
1. Read the [Introduction](https://terrain3d.readthedocs.io/en/stable/docs/introduction.html) to understand how this terrain system works.
2. Read the [Installation & Upgrade](https://terrain3d.readthedocs.io/en/stable/docs/installation.html) instructions.
3. Watch the [tutorial videos](https://terrain3d.readthedocs.io/en/stable/docs/tutorial_videos.html) and read through the documentation.
4. For support, read [Getting Help](https://terrain3d.readthedocs.io/en/stable/docs/getting_help.html) and join our [Discord server](https://tokisan.com/discord).
## Credit
Developed for the Godot community by:
|||
|--|--|
| **Cory Petkovsek, Tokisan Games** | [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/twitter.png?raw=true" width="24"/>](https://twitter.com/TokisanGames) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/github.png?raw=true" width="24"/>](https://github.com/TokisanGames) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/www.png?raw=true" width="24"/>](https://tokisan.com/) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/discord.png?raw=true" width="24"/>](https://tokisan.com/discord) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/youtube.png?raw=true" width="24"/>](https://www.youtube.com/@TokisanGames)|
| **Roope Palmroos, Outobugi Games** | [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/twitter.png?raw=true" width="24"/>](https://twitter.com/outobugi) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/github.png?raw=true" width="24"/>](https://github.com/outobugi) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/www.png?raw=true" width="24"/>](https://outobugi.com/) [<img src="https://github.com/dmhendricks/signature-social-icons/blob/master/icons/round-flat-filled/35px/youtube.png?raw=true" width="24"/>](https://www.youtube.com/@outobugi)|
And the contribution team in [AUTHORS.md](https://terrain3d.readthedocs.io/en/stable/docs/authors.html) and on the right of the github page.
## Contributing
Please see [CONTRIBUTING.md](https://github.com/TokisanGames/Terrain3D/blob/main/CONTRIBUTING.md) if you would like to help make Terrain3D the best terrain system for Godot.
## License
This addon has been released under the [MIT License](https://github.com/TokisanGames/Terrain3D/blob/main/LICENSE.txt).

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,42 @@
# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
# Import From SimpleGrassTextured
#
# This script demonstrates how to import transforms from SimpleGrassTextured. To use it:
#
# 1. Setup the mesh asset you wish to use in the asset dock.
# 1. Select your Terrain3D node.
# 1. In the inspector, click Script (very bottom) and Quick Load import_sgt.gd.
# 1. At the very top, assign your SimpleGrassTextured node.
# 1. Input the desired mesh asset ID.
# 1. Click import. The output window and console will report when finished.
# 1. Clear the script from your Terrain3D node, and save your scene.
#
# The instance transforms are now stored in your region files.
#
# Use clear_instances to erase all instances that match the assign_mesh_id.
#
# The add_transforms function (called by add_multimesh) applies the height_offset specified in the
# Terrain3DMeshAsset.
# Once the transforms are imported, you can reassign any mesh you like into this mesh slot.
@tool
extends Terrain3D
@export var simple_grass_textured: MultiMeshInstance3D
@export var assign_mesh_id: int
@export var import: bool = false : set = import_sgt
@export var clear_instances: bool = false : set = clear_multimeshes
func clear_multimeshes(value: bool) -> void:
get_instancer().clear_by_mesh(assign_mesh_id)
func import_sgt(value: bool) -> void:
var sgt_mm: MultiMesh = simple_grass_textured.multimesh
var global_xform: Transform3D = simple_grass_textured.global_transform
print("Starting to import %d instances from SimpleGrassTextured using mesh id %d" % [ sgt_mm.instance_count, assign_mesh_id])
var time: int = Time.get_ticks_msec()
get_instancer().add_multimesh(assign_mesh_id, sgt_mm, simple_grass_textured.global_transform)
print("Import complete in %.2f seconds" % [ float(Time.get_ticks_msec() - time)/1000. ])

View File

@@ -0,0 +1 @@
uid://bllcuwetve45k

View File

@@ -0,0 +1,137 @@
# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
# This script is an addon for HungryProton's Scatter https://github.com/HungryProton/scatter
# It provides a `Project on Terrain3D` modifier, which allows Scatter
# to detect the terrain height from Terrain3D without using collision.
#
# Copy this file into /addons/proton_scatter/src/modifiers
# Then uncomment everything below (select, press CTRL+K)
# In the editor, add this modifier to Scatter, then set your Terrain3D node
#@tool
#extends "base_modifier.gd"
#
#
#signal projection_completed
#
#
#@export var terrain_node : NodePath
#@export var align_with_collision_normal : bool = false
#@export_range(0.0, 90.0, 0.1) var max_slope : float = 90.0
#@export var enable_texture_filtering : bool = false
#@export_range(0, 31) var target_texture_id : int = 0
#@export var not_target_texture : bool = false
#@export_range(0.0, 1.0, 0.01) var texture_threshold : float = 0.8
#
#var _terrain: Terrain3D
#
#
#func _init() -> void:
#display_name = "Project On Terrain3D"
#category = "Edit"
#can_restrict_height = false
#global_reference_frame_available = true
#local_reference_frame_available = true
#individual_instances_reference_frame_available = true
#use_global_space_by_default()
#
#documentation.add_paragraph(
#"This is a modified version of `Project on Colliders` that queries Terrain3D
#for heights without using collision. It constrains placement by slope or texture.
#
#This modifier must have terrain_node set to a Terrain3D node.")
#
#var p := documentation.add_parameter("Terrain Node")
#p.set_type("NodePath")
#p.set_description("Set your Terrain3D node.")
#
#p = documentation.add_parameter("Align with collision normal")
#p.set_type("bool")
#p.set_description(
#"Rotate the transform to align it with the collision normal in case
#the ray cast hit a collider.")
#
#p = documentation.add_parameter("Enable Texture Filtering")
#p.set_type("bool")
#p.set_description(
#"If enabled, objects will only be placed based on the ground texture specified.")
#
#p = documentation.add_parameter("Target Texture ID")
#p.set_type("int")
#p.set_description(
#"The ID of the texture to place objects on (0-31). Objects will only be placed on this texture.")
#
#p = documentation.add_parameter("Not Target Texture")
#p.set_type("bool")
#p.set_description(
#"If true, objects will be placed on all textures EXCEPT the target texture.")
#
#p = documentation.add_parameter("Texture Threshold")
#p.set_type("float")
#p.set_description("The blend value required for placement on the texture.")
#
#
#func _process_transforms(transforms, domain, _seed) -> void:
#if transforms.is_empty():
#return
#
#if terrain_node:
#_terrain = domain.get_root().get_node_or_null(terrain_node)
#
#if not _terrain:
#warning += """No Terrain3D node found"""
#return
#
#if not _terrain.data:
#warning += """Terrain3DData is not initialized"""
#return
#
## Review transforms
#var gt: Transform3D = domain.get_global_transform()
#var gt_inverse := gt.affine_inverse()
#var new_transforms_array: Array[Transform3D] = []
#var remapped_max_slope: float = remap(max_slope, 0.0, 90.0, 0.0, 1.0)
#for i in transforms.list.size():
#var t: Transform3D = transforms.list[i]
#
#var location: Vector3 = (gt * t).origin
#var height: float = _terrain.data.get_height(location)
#if is_nan(height):
#continue
#
#var normal: Vector3 = _terrain.data.get_normal(location)
#if not abs(Vector3.UP.dot(normal)) >= (1.0 - remapped_max_slope):
#continue
#
#if enable_texture_filtering:
#var texture_info: Vector3 = _terrain.data.get_texture_id(location)
#var base_id: int = int(texture_info.x)
#var overlay_id: int = int(texture_info.y)
#var blend_value: float = texture_info.z
## Skip if overlay or blend != target texture, unless inverted
#if ((overlay_id != target_texture_id or blend_value < texture_threshold) and \
#(base_id != target_texture_id or blend_value >= texture_threshold)) != not_target_texture:
#continue
#
#if align_with_collision_normal and not is_nan(normal.x):
#t.basis.y = normal
#t.basis.x = -t.basis.z.cross(normal)
#t.basis = t.basis.orthonormalized()
#
#t.origin.y = height - gt.origin.y
#new_transforms_array.push_back(t)
#
#transforms.list.clear()
#transforms.list.append_array(new_transforms_array)
#
#if transforms.is_empty():
#warning += """All transforms have been removed. Possible reasons include: \n"""
#if enable_texture_filtering:
#warning += """+ No matching texture found at any position.
#+ Texture threshold may be too high.
#"""
#warning += """+ No collider is close enough to the shapes.
#+ Ray length is too short.
#+ Ray direction is incorrect.
#+ Collision mask is not set properly.
#+ Max slope is too low.
#"""

View File

@@ -0,0 +1 @@
uid://g3opjh3m3iww

View File

@@ -0,0 +1,25 @@
[gd_scene load_steps=5 format=3 uid="uid://d3sr0a7dxfkr8"]
[ext_resource type="Script" uid="uid://bp7r4ppgq1m0g" path="res://addons/terrain_3d/extras/particle_example/terrain_3D_particles.gd" id="1_gl3qg"]
[ext_resource type="Material" uid="uid://el5y10hnh13g" path="res://addons/terrain_3d/extras/particle_example/process_material.tres" id="2_2gon1"]
[ext_resource type="Material" uid="uid://ljo1wt61kbkq" path="res://addons/terrain_3d/extras/particle_example/grass_material.tres" id="3_qyjnw"]
[sub_resource type="RibbonTrailMesh" id="RibbonTrailMesh_fwrtk"]
shape = 0
section_length = 0.18
section_segments = 1
[node name="Terrain3DParticles" type="Node3D"]
script = ExtResource("1_gl3qg")
instance_spacing = 0.25
cell_width = 24.0
grid_width = 5
rows = 96
amount = 9216
process_material = ExtResource("2_2gon1")
mesh = SubResource("RibbonTrailMesh_fwrtk")
shadow_mode = 0
mesh_material_override = ExtResource("3_qyjnw")
min_draw_distance = 60.0
particle_count = 230400
metadata/_edit_lock_ = true

View File

@@ -0,0 +1,69 @@
// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
shader_type spatial;
render_mode skip_vertex_transform, cull_disabled, blend_mix;
uniform vec2 wind_direction = vec2(1.0, 1.0);
varying vec4 data;
// A lot of hard coded things here atm.
void vertex() {
// Wind effect from model data, in this case no vertex colors,
// so just use vertex Y component, including mesh offset
data[2] = (VERTEX.y + 0.55);
data[2] *= data[2]; // make non-linear
// Ribbon used as a grass mesh.. so pinch the top.
VERTEX.xz *= (1.0 - data[2]);
// Brighten tips
COLOR = mix(COLOR, vec4(1.0), smoothstep(0.9, 1.0, data[2]));
// Darken base, skip is scale is less than threshold, as this means "grow in" is occuring.
COLOR *= INSTANCE_CUSTOM[3] < 0.35 ? 1. : mix(1.0, 0.75, smoothstep(0.35, 0.0, data[2]));
// Save red/green shift for fragment
data.rg = INSTANCE_CUSTOM.rg;
// World space vertex
vec3 w_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
// Get wind force and scale from process()
float scale = pow(INSTANCE_CUSTOM[3] * INSTANCE_CUSTOM[3], 0.707);
float force = INSTANCE_CUSTOM[2] * data[2] * scale;
// Add some cheap jitter at high wind values
force -= fract(force * 256.0) * force * 0.05;
// Curve the result
force = pow(force, 0.707);
// These 2 combined result in a decent bend without resorting to matrices or pivot data.
// Lateral move and wobble
float lateral_wobble = sin(TIME * 2.0 * (1.0 + data.r + data.g)) * 0.25 * (1.0 - INSTANCE_CUSTOM[2]);
vec2 direction = normalize(wind_direction);
w_vertex.xz -= (vec2(-direction.y, direction.x) * lateral_wobble + direction) * force;
// Flatten
w_vertex.y -= INSTANCE_CUSTOM[2] * force * data[2];
// Save final wind force value for fragment.
data[3] = force;
VERTEX = (VIEW_MATRIX * vec4(w_vertex, 1.0)).xyz;
NORMAL = MODELVIEW_NORMAL_MATRIX * NORMAL;
BINORMAL = MODELVIEW_NORMAL_MATRIX * BINORMAL;
TANGENT = MODELVIEW_NORMAL_MATRIX * TANGENT;
}
void fragment() {
// Hard coded color.
ALBEDO = vec3(0.20, 0.22, 0.05) * (data[2] * 0.5 + 0.5);
ALBEDO.rg *= (data.rg * 0.3 + 0.9);
ALBEDO *= pow(COLOR.rgb, vec3(2.2));
// Modify roughness / specular based on wind force for added detail
float spec_rough = clamp(max(data[2], data[3]), 0., 1.);
ROUGHNESS = 1. - spec_rough;
SPECULAR = clamp(spec_rough * 0.25, 0., .15);
BACKLIGHT = vec3(0.33);
#if CURRENT_RENDERER == RENDERER_COMPATIBILITY
ALBEDO = pow(ALBEDO, vec3(0.4));
#endif
}

View File

@@ -0,0 +1 @@
uid://dq3lfyp3u5oxt

View File

@@ -0,0 +1,8 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://ljo1wt61kbkq"]
[ext_resource type="Shader" uid="uid://dq3lfyp3u5oxt" path="res://addons/terrain_3d/extras/particle_example/grass.gdshader" id="1_nkru0"]
[resource]
render_priority = 0
shader = ExtResource("1_nkru0")
shader_parameter/wind_direction = Vector2(1, 1)

View File

@@ -0,0 +1,275 @@
// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
// This is an example particle shader designed to procedurally place
// particles like grass, small rocks, and other ground effects, on the terrain
// surface by reading the Terrain3D data maps. It works in tandem with the
// provided GDScript.
shader_type particles;
render_mode disable_velocity, disable_force;
group_uniforms options;
uniform sampler2D main_noise;
uniform float main_noise_scale = 0.01;
uniform vec3 position_offset = vec3(0.);
uniform bool align_to_normal = true;
uniform float normal_strength : hint_range(0.01, 1.0, 0.01) = 0.3;
uniform bool random_rotation = true;
uniform float random_spacing : hint_range(0.0, 1.0, 0.01) = 0.5;
uniform vec3 min_scale = vec3(1.0);
uniform vec3 max_scale = vec3(1.0);
group_uniforms wind;
uniform float noise_scale = 0.0041;
uniform float wind_speed = 0.025;
uniform float wind_strength : hint_range(0.0, 1.0, 0.01) = 1.0;
uniform float wind_dithering = 4.0;
uniform vec2 wind_direction = vec2(1.0,1.0);
group_uniforms shapeing;
uniform float clod_scale_boost = 3.0;
uniform float clod_min_threshold : hint_range(0.0, 1.0, 0.001) = 0.2;
uniform float clod_max_threshold : hint_range(0.0, 1.0, 0.001) = 0.5;
uniform float patch_min_threshold : hint_range(0.0, 1.0, 0.001) = 0.025;
uniform float patch_max_threshold : hint_range(0.0, 1.0, 0.001) = 0.2;
group_uniforms filtering;
uniform float condition_dither_range : hint_range(0.0, 1.0, 0.01) = 0.15;
uniform float surface_slope_min : hint_range(0.0, 1.0, 0.01) = 0.87;
uniform float distance_fade_ammount : hint_range(0.0, 1.0, 0.01) = 0.5;
group_uniforms private;
uniform float max_dist = 1.;
uniform vec3 camera_position = vec3(0.);
uniform uint instance_rows = 1;
uniform float instance_spacing = 0.5;
uniform uint _background_mode = 0u;
uniform float _vertex_spacing = 1.0;
uniform float _vertex_density = 1.0; // = 1/_vertex_spacing
uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1/REGION_SIZE
uniform int _region_map_size = 32;
uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform highp sampler2DArray _height_maps : repeat_disable;
uniform highp sampler2DArray _control_maps : repeat_disable;
uniform highp sampler2DArray _color_maps : repeat_disable;
// Defined Constants
#define SKIP_PASS 0
#define VERTEX_PASS 1
#define FRAGMENT_PASS 2
// Takes in world space XZ (UV) coordinates & search depth (only applicable for background mode none)
// Returns ivec3 with:
// XY: (0 to _region_size - 1) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
ivec3 get_index_coord(const vec2 uv, const int search) {
vec2 r_uv = round(uv);
vec2 o_uv = mod(r_uv,_region_size);
ivec2 pos;
int bounds, layer_index = -1;
for (int i = -1; i < 0; i++) {
if ((layer_index == -1 && _background_mode == 0u) || i < 0) {
r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x));
pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2);
bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1);
}
}
return ivec3(ivec2(mod(r_uv,_region_size)), layer_index);
}
#if CURRENT_RENDERER == RENDERER_COMPATIBILITY
#define fma(a, b, c) ((a) * (b) + (c))
#endif
float random(vec2 v) {
return fract(1e4 * sin(fma(17.0, v.x, v.y * 0.1)) * (0.1 + abs(sin(fma(v.y, 13.0, v.x)))));
}
mat3 rotation_matrix(vec3 axis, float angle) {
float c = cos(angle);
float s = sin(angle);
float t = 1.0 - c;
vec3 n = normalize(axis);
float x = n.x;
float y = n.y;
float z = n.z;
return mat3(
vec3(t * x * x + c, t * x * y - z * s, t * x * z + y * s),
vec3(t * x * y + z * s, t * y * y + c, t * y * z - x * s),
vec3(t * x * z - y * s, t * y * z + x * s, t * z * z + c));
}
mat3 align_to_vector(vec3 normal) {
vec3 up = vec3(0.0, 1.0, 0.0);
if (abs(dot(normal, up)) > 0.9999) { // Avoid singularity
up = vec3(1.0, 0.0, 0.0);
}
vec3 tangent = normalize(cross(up, normal));
vec3 bitangent = normalize(cross(tangent, normal));
return mat3(tangent, normal, bitangent);
}
void start() {
// Create centered a grid
vec3 pos = vec3(float(INDEX % instance_rows), 0.0, float(INDEX / instance_rows)) - float(instance_rows >> 1u);
// Apply spcaing
pos *= instance_spacing;
// Move the grid to the emitter, snapping is handled CPU side
pos.xz += EMISSION_TRANSFORM[3].xz;
// Create random values per-instance, incorporating the seed, mask bits to avoid NAN/INF
float seed = fract(uintBitsToFloat(RANDOM_SEED & 0x7EFFFFFFu));
vec3 r = fract(vec3(random(pos.xz), random(pos.xz + vec2(0.5)), random(pos.xz - vec2(0.5))) + seed);
// Randomize instance spacing
pos.x += ((r.x * 2.0) - 1.0) * random_spacing * instance_spacing;
pos.z += ((r.z * 2.0) - 1.0) * random_spacing * instance_spacing;
// Lookup offsets, ID and blend weight
const vec3 offsets = vec3(0, 1, 2);
vec2 index_id = floor(pos.xz * _vertex_density);
vec2 weight = fract(pos.xz * _vertex_density);
vec2 invert = 1.0 - weight;
vec4 weights = vec4(
invert.x * weight.y, // 0
weight.x * weight.y, // 1
weight.x * invert.y, // 2
invert.x * invert.y // 3
);
ivec3 index[4];
// Map lookups
index[0] = get_index_coord(index_id + offsets.xy, VERTEX_PASS);
index[1] = get_index_coord(index_id + offsets.yy, VERTEX_PASS);
index[2] = get_index_coord(index_id + offsets.yx, VERTEX_PASS);
index[3] = get_index_coord(index_id + offsets.xx, VERTEX_PASS);
highp float h[8];
h[0] = texelFetch(_height_maps, index[0], 0).r; // 0 (0,1)
h[1] = texelFetch(_height_maps, index[1], 0).r; // 1 (1,1)
h[2] = texelFetch(_height_maps, index[2], 0).r; // 2 (1,0)
h[3] = texelFetch(_height_maps, index[3], 0).r; // 3 (0,0)
h[4] = texelFetch(_height_maps, get_index_coord(index_id + offsets.yz, VERTEX_PASS), 0).r; // 4 (1,2)
h[5] = texelFetch(_height_maps, get_index_coord(index_id + offsets.zy, VERTEX_PASS), 0).r; // 5 (2,1)
h[6] = texelFetch(_height_maps, get_index_coord(index_id + offsets.zx, VERTEX_PASS), 0).r; // 6 (2,0)
h[7] = texelFetch(_height_maps, get_index_coord(index_id + offsets.xz, VERTEX_PASS), 0).r; // 7 (0,2)
vec3 index_normal[4];
index_normal[0] = vec3(h[0] - h[1], _vertex_spacing, h[0] - h[7]);
index_normal[1] = vec3(h[1] - h[5], _vertex_spacing, h[1] - h[4]);
index_normal[2] = vec3(h[2] - h[6], _vertex_spacing, h[2] - h[1]);
index_normal[3] = vec3(h[3] - h[2], _vertex_spacing, h[3] - h[0]);
vec3 w_normal = normalize(
index_normal[0] * weights[0] +
index_normal[1] * weights[1] +
index_normal[2] * weights[2] +
index_normal[3] * weights[3]);
// Set the height according to the heightmap data
pos.y =
h[0] * weights[0] +
h[1] * weights[1] +
h[2] * weights[2] +
h[3] * weights[3] ;
// Offset, Rotation, Alignment.
TRANSFORM = mat4(1.0);
vec3 orientation = vec3(0., 1., 0.);
vec2 uv = (pos.xz) * main_noise_scale;
float noise = textureLod(main_noise, uv, 0.0).r;
float clods = smoothstep(clod_min_threshold, clod_max_threshold, noise) * clod_scale_boost;
float patch = smoothstep(patch_min_threshold, patch_max_threshold, noise);
float width_modifier = 1.0 + 3.0 * smoothstep(0., max_dist, length(camera_position - pos));
// Calculate scale
vec3 scale = vec3(
mix(min_scale.x, max_scale.x, r.x) * width_modifier,
mix(min_scale.y, max_scale.y, r.y) + clods,
mix(min_scale.z, max_scale.z, r.z) * width_modifier) * patch;
// Apply scale to offset
vec3 offset = position_offset * scale;
// Apply normal orientation
if (align_to_normal) {
orientation = mix(orientation, w_normal, normal_strength);
mat3 alignment = align_to_vector(orientation);
offset = alignment * offset;
TRANSFORM = mat4(alignment);
}
// Apply rotation around orientation
if (random_rotation) {
mat3 rotation = rotation_matrix(orientation, r.x * TAU);
TRANSFORM = mat4(rotation) * TRANSFORM;
}
// Filtering - Causes some particles to be rendered as degenerate triangles
// via 0./0. - Particles filtered this way are still processed by the GPU.
// For compatibility it seems we must shift as well.
// Surface slope filtering
if (surface_slope_min > w_normal.y + (r.y - 0.5) * condition_dither_range) {
pos.y = 0. / 0.;
pos.xz = vec2(100000.0);
}
// Read color map
highp vec4 c[4];
#define COLOR_MAP vec4(1., 1., 1., 0.5)
c[0] = index[0].z >= 0 ? texelFetch(_color_maps, index[0], 0) : COLOR_MAP; // 0 (0,1)
c[1] = index[1].z >= 0 ? texelFetch(_color_maps, index[1], 0) : COLOR_MAP; // 1 (1,1)
c[2] = index[2].z >= 0 ? texelFetch(_color_maps, index[2], 0) : COLOR_MAP; // 2 (1,0)
c[3] = index[3].z >= 0 ? texelFetch(_color_maps, index[3], 0) : COLOR_MAP; // 3 (0,0)
vec4 color_map =
c[0] * weights[0] +
c[1] * weights[1] +
c[2] * weights[2] +
c[3] * weights[3] ;
COLOR = color_map;
// Read control map
uint control = floatBitsToUint(texelFetch(_control_maps, index[3], 0).r);
bool auto = bool(control & 0x1u);
int base = int(control >>27u & 0x1Fu);
int over = int(control >> 22u & 0x1Fu);
float blend = float(control >> 14u & 0xFFu) * 0.003921568627450; // 1. / 255.
// Hardcoded example, hand painted texture id 0 is filtered out.
if (!auto && ((base == 0 && blend < 0.7) || (over == 0 && blend >= 0.3))) {
pos.y = 0. / 0.;
pos.xz = vec2(100000.0);
}
if (length(camera_position - pos) > max_dist) {
pos.y = 0. / 0.;
pos.xz = vec2(100000.0);
} else {
float fade_factor = 1.0 - smoothstep(max_dist * distance_fade_ammount, max_dist + 0.0001, length(camera_position - pos)) + 0.001;
scale.y *= fade_factor;
offset *= fade_factor;
}
// Apply scale
TRANSFORM[0] *= scale.x;
TRANSFORM[1] *= scale.y;
TRANSFORM[2] *= scale.z;
// Apply the position
TRANSFORM[3].xyz = pos.xyz + offset;
// Save Fixed 2 Random values for Reg/Green color randomness
CUSTOM.rg = r.rg;
// Save Y component scale pre-rotation
CUSTOM[3] = scale.y;
}
void process() {
// Extract world space UV from Transform Matrix
vec2 uv = (TRANSFORM[3].xz + CUSTOM.rg * wind_dithering) * noise_scale;
// Scaled wind noise, updated per instance, at process FPS. Passed to Vertex()
CUSTOM[2] = textureLod(main_noise, uv + TIME * wind_speed * normalize(wind_direction), 0.0).r * wind_strength;
}

View File

@@ -0,0 +1 @@
uid://dce675i014xcn

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,237 @@
# Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
#
# This is an example of using a particle shader with Terrain3D.
# To use it, add `Terrain3DParticles.tscn` to your scene and assign the terrain.
# Then customize the settings, materials and shader to extend it and make it your own.
@tool
extends Node3D
#region settings
## Auto set if attached as a child of a Terrain3D node
@export var terrain: Terrain3D:
set(value):
terrain = value
_create_grid()
## Distance between instances
@export_range(0.125, 2.0, 0.015625) var instance_spacing: float = 0.5:
set(value):
instance_spacing = clamp(round(value * 64.0) * 0.015625, 0.125, 2.0)
rows = maxi(int(cell_width / instance_spacing), 1)
amount = rows * rows
_set_offsets()
## Width of an individual cell of the grid
@export_range(8.0, 256.0, 1.0) var cell_width: float = 32.0:
set(value):
cell_width = clamp(value, 8.0, 256.0)
rows = maxi(int(cell_width / instance_spacing), 1)
amount = rows * rows
min_draw_distance = 1.0
# Have to update aabb
if terrain and terrain.data:
var height_range: Vector2 = terrain.data.get_height_range()
var height: float = height_range[0] - height_range[1]
var aabb: AABB = AABB()
aabb.size = Vector3(cell_width, height, cell_width)
aabb.position = aabb.size * -0.5
aabb.position.y = height_range[1]
for p in particle_nodes:
p.custom_aabb = aabb
_set_offsets()
## Grid width. Must be odd.
## Higher values cull slightly better, draw further out.
@export_range(1, 15, 2) var grid_width: int = 9:
set(value):
grid_width = value
particle_count = 1
min_draw_distance = 1.0
_create_grid()
@export_storage var rows: int = 1
@export_storage var amount: int = 1:
set(value):
amount = value
particle_count = value
last_pos = Vector3.ZERO
for p in particle_nodes:
p.amount = amount
@export_range(1, 256, 1) var process_fixed_fps: int = 30:
set(value):
process_fixed_fps = maxi(value, 1)
for p in particle_nodes:
p.fixed_fps = process_fixed_fps
p.preprocess = 1.0 / float(process_fixed_fps)
## Access to process material parameters
@export var process_material: ShaderMaterial
## The mesh that each particle will render
@export var mesh: Mesh
@export var shadow_mode: GeometryInstance3D.ShadowCastingSetting = (
GeometryInstance3D.ShadowCastingSetting.SHADOW_CASTING_SETTING_ON):
set(value):
shadow_mode = value
for p in particle_nodes:
p.cast_shadow = value
## Override material for the particle mesh
@export_custom(
PROPERTY_HINT_RESOURCE_TYPE,
"BaseMaterial3D,ShaderMaterial") var mesh_material_override: Material:
set(value):
mesh_material_override = value
for p in particle_nodes:
p.material_override = mesh_material_override
@export_group("Info")
## The minimum distance that particles will be drawn upto
## If using fade out effects like pixel alpha this is the limit to use.
@export var min_draw_distance: float = 1.0:
set(value):
min_draw_distance = float(cell_width * grid_width) * 0.5
## Displays current total particle count based on Cell Width and Instance Spacing
@export var particle_count: int = 1:
set(value):
particle_count = amount * grid_width * grid_width
#endregion
var offsets: Array[Vector3]
var last_pos: Vector3 = Vector3.ZERO
var particle_nodes: Array[GPUParticles3D]
func _ready() -> void:
if not terrain:
var parent: Node = get_parent()
if parent is Terrain3D:
terrain = parent
_create_grid()
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
_destroy_grid()
func _physics_process(delta: float) -> void:
if terrain:
var camera: Camera3D = terrain.get_camera()
if camera:
if last_pos.distance_squared_to(camera.global_position) > 1.0:
var pos: Vector3 = camera.global_position.snapped(Vector3.ONE)
_position_grid(pos)
RenderingServer.material_set_param(process_material.get_rid(), "camera_position", pos )
last_pos = camera.global_position
_update_process_parameters()
else:
set_physics_process(false)
func _create_grid() -> void:
_destroy_grid()
if not terrain:
return
set_physics_process(true)
_set_offsets()
var hr: Vector2 = terrain.data.get_height_range()
var height: float = hr.x - hr.y
var aabb: AABB = AABB()
aabb.size = Vector3(cell_width, height, cell_width)
aabb.position = aabb.size * -0.5
aabb.position.y = hr.y
var half_grid: int = grid_width / 2
# Iterating the array like this allows identifying grid position, in case setting
# different mesh or materials is desired for LODs etc.
for x in range(-half_grid, half_grid + 1):
for z in range(-half_grid, half_grid + 1):
#var ring: int = maxi(maxi(absi(x), absi(z)), 0)
var particle_node = GPUParticles3D.new()
particle_node.lifetime = 600.0
particle_node.amount = amount
particle_node.explosiveness = 1.0
particle_node.amount_ratio = 1.0
particle_node.process_material = process_material
particle_node.draw_pass_1 = mesh
particle_node.speed_scale = 1.0
particle_node.custom_aabb = aabb
particle_node.cast_shadow = shadow_mode
particle_node.fixed_fps = process_fixed_fps
# This prevent minor grid alignment errors when the camera is moving very fast
particle_node.preprocess = 1.0 / float(process_fixed_fps)
if mesh_material_override:
particle_node.material_override = mesh_material_override
particle_node.use_fixed_seed = true
if (x > -half_grid and z > -half_grid): # Use the same seed across all nodes
particle_node.seed = particle_nodes[0].seed
self.add_child(particle_node)
particle_node.emitting = true
particle_nodes.push_back(particle_node)
last_pos = Vector3.ZERO
func _set_offsets() -> void:
var half_grid: int = grid_width / 2
offsets.clear()
for x in range(-half_grid, half_grid + 1):
for z in range(-half_grid, half_grid + 1):
var offset := Vector3(
float(x * rows) * instance_spacing,
0.0,
float(z * rows) * instance_spacing
)
offsets.append(offset)
func _destroy_grid() -> void:
for node: GPUParticles3D in particle_nodes:
if is_instance_valid(node):
node.queue_free()
particle_nodes.clear()
func _position_grid(pos: Vector3) -> void:
for i in particle_nodes.size():
var node: GPUParticles3D = particle_nodes[i]
var snap = Vector3(pos.x, 0, pos.z).snapped(Vector3.ONE) + offsets[i]
node.global_position = (snap / instance_spacing).round() * instance_spacing
node.reset_physics_interpolation()
node.restart(true) # keep the same seed.
func _update_process_parameters() -> void:
if process_material:
var process_rid: RID = process_material.get_rid()
if terrain and process_rid.is_valid():
RenderingServer.material_set_param(process_rid, "_background_mode", terrain.material.world_background)
RenderingServer.material_set_param(process_rid, "_vertex_spacing", terrain.vertex_spacing)
RenderingServer.material_set_param(process_rid, "_vertex_density", 1.0 / terrain.vertex_spacing)
RenderingServer.material_set_param(process_rid, "_region_size", terrain.region_size)
RenderingServer.material_set_param(process_rid, "_region_texel_size", 1.0 / terrain.region_size)
RenderingServer.material_set_param(process_rid, "_region_map_size", 32)
RenderingServer.material_set_param(process_rid, "_region_map", terrain.data.get_region_map())
RenderingServer.material_set_param(process_rid, "_region_locations", terrain.data.get_region_locations())
RenderingServer.material_set_param(process_rid, "_height_maps", terrain.data.get_height_maps_rid())
RenderingServer.material_set_param(process_rid, "_control_maps", terrain.data.get_control_maps_rid())
RenderingServer.material_set_param(process_rid, "_color_maps", terrain.data.get_color_maps_rid())
RenderingServer.material_set_param(process_rid, "instance_spacing", instance_spacing)
RenderingServer.material_set_param(process_rid, "instance_rows", rows)
RenderingServer.material_set_param(process_rid, "max_dist", min_draw_distance)

View File

@@ -0,0 +1 @@
uid://bp7r4ppgq1m0g

View File

@@ -0,0 +1,67 @@
// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
// This shader snippet draws a hex grid
// To use it, add this line to the top of your shader:
// #include "res://addons/terrain_3d/extras/shaders/hex_grid.gdshaderinc"
// And this line at the bottom of your shader:
// draw_hex_grid(uv2, _region_texel_size, w_normal, ALBEDO);
mat2 rotate2d(float _angle) {
return mat2(vec2(cos(_angle),-sin(_angle)), vec2(sin(_angle), cos(_angle)));
}
void draw_hex_grid(vec2 uv, float texel_size, vec3 normal, inout vec3 albedo) {
float hex_size = 0.02;
float line_thickness = 0.04;
vec2 guv = (uv - vec2(0.5 * texel_size)) / hex_size;
// Convert UV to axial hex coordinates
float q = (sqrt(3.0) / 3.0 * guv.x - 1.0 / 3.0 * guv.y);
float r = (2.0 / 3.0 * guv.y);
// Cube coordinates for the hex (q, r, -q-r)
float x = q;
float z = r;
float y = -x - z;
// Round to the nearest hex center
vec3 rounded = round(vec3(x, y, z));
vec3 diff = abs(vec3(x, y, z) - rounded);
// Fix rounding errors
if (diff.x > diff.y && diff.x > diff.z) {
rounded.x = -rounded.y - rounded.z;
} else if (diff.y > diff.z) {
rounded.y = -rounded.x - rounded.z;
} else {
rounded.z = -rounded.x - rounded.y;
}
// Find the hex center in UV space
vec2 hex_center = vec2(
sqrt(3.0) * rounded.x + sqrt(3.0) / 2.0 * rounded.z,
3.0 / 2.0 * rounded.z
);
// Relative position within the hex
vec2 local_pos = guv - hex_center;
vec2 lines_uv = local_pos;
float line = 1.0;
for (int i = 0; i < 6; i++) {
vec2 luv = lines_uv * rotate2d(radians(60.0 * float(i) + 30.0));
float dist = abs(dot(luv + vec2(0.90), vec2(0.0, 1.0)));
line = min(line, dist);
}
// Filter lines by slope
float slope = 4.; // Can also assign to (auto_slope * 4.) to match grass placement
float slope_factor = clamp(dot(vec3(0., 1., 0.), slope * (normal - 1.) + 1.), 0., 1.);
// Draw hex grid
albedo = mix(albedo, vec3(1.0), smoothstep(line_thickness + 0.02, line_thickness, line) * slope_factor);
// Draw Hex center dot
albedo = mix(albedo, vec3(0.0, 0.5, 0.5), smoothstep(0.11, 0.10, length(local_pos)) * slope_factor);
}

View File

@@ -0,0 +1 @@
uid://mri8pfoj2mfk

View File

@@ -0,0 +1,367 @@
shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,skip_vertex_transform;
/* This is an example stripped down shader with maximum performance in mind.
* Only Autoshader/Base/Over/Blend/Holes/Colormap are supported.
* All terrain normal calculations take place in vetex().
*
* Control map indices are processed such that each ID only requires reading ONCE.
* The following features: projection, detiling, and paintable rotation / scale
* cannot work with this method, without the additional samples required for blending
* between same ID textures with different values across indices.
*/
// Defined Constants
#define SKIP_PASS 0
#define VERTEX_PASS 1
#define FRAGMENT_PASS 2
#define COLOR_MAP vec4(1.0, 1.0, 1.0, 0.5)
#define DIV_255 0.003921568627450 // 1. / 255.
// Inline Functions
#define DECODE_BLEND(control) float(control >> 14u & 0xFFu) * DIV_255
#define DECODE_AUTO(control) bool(control & 0x1u)
#define DECODE_BASE(control) int(control >> 27u & 0x1Fu)
#define DECODE_OVER(control) int(control >> 22u & 0x1Fu)
#define DECODE_HOLE(control) bool(control >>2u & 0x1u)
#if CURRENT_RENDERER == RENDERER_COMPATIBILITY
#define fma(a, b, c) ((a) * (b) + (c))
#define dFdxCoarse(a) dFdx(a)
#define dFdyCoarse(a) dFdy(a)
#endif
// Private uniforms
uniform vec3 _camera_pos = vec3(0.f);
uniform float _mesh_size = 48.f;
uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2
uniform uint _mouse_layer = 0x80000000u; // Layer 32
uniform float _vertex_spacing = 1.0;
uniform float _vertex_density = 1.0; // = 1./_vertex_spacing
uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1./region_size
uniform int _region_map_size = 32;
uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform float _texture_normal_depth_array[32];
uniform float _texture_ao_strength_array[32];
uniform float _texture_roughness_mod_array[32];
uniform float _texture_uv_scale_array[32];
uniform vec4 _texture_color_array[32];
uniform highp sampler2DArray _height_maps : repeat_disable;
uniform highp sampler2DArray _control_maps : repeat_disable;
uniform highp sampler2DArray _color_maps : source_color, filter_linear_mipmap_anisotropic, repeat_disable;
uniform highp sampler2DArray _texture_array_albedo : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
uniform highp sampler2DArray _texture_array_normal : hint_normal, filter_linear_mipmap_anisotropic, repeat_enable;
// Public uniforms
uniform bool enable_texturing = true;
uniform float blend_sharpness : hint_range(0, 1) = 0.5;
uniform bool flat_terrain_normals = false;
// Autoshader
uniform float auto_slope : hint_range(0, 10) = 1.0;
uniform float auto_height_reduction : hint_range(0, 1) = 0.1;
uniform int auto_base_texture : hint_range(0, 31) = 0;
uniform int auto_overlay_texture : hint_range(0, 31) = 1;
// Macro Variation
uniform bool enable_macro_variation = true;
uniform vec3 macro_variation1 : source_color = vec3(1.);
uniform vec3 macro_variation2 : source_color = vec3(1.);
uniform float macro_variation_slope : hint_range(0., 1.) = 0.333;
uniform highp sampler2D noise_texture : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
uniform float noise1_scale : hint_range(0.001, 1.) = 0.04; // Used for macro variation 1. Scaled up 10x
uniform float noise1_angle : hint_range(0, 6.283) = 0.;
uniform vec2 noise1_offset = vec2(0.5);
uniform float noise2_scale : hint_range(0.001, 1.) = 0.076; // Used for macro variation 2. Scaled up 10x
// Varyings & Types
varying vec3 v_normal;
varying vec3 v_vertex;
varying mat3 TBN;
////////////////////////
// Vertex
////////////////////////
// Takes in world space XZ (UV) coordinates & search depth (only applicable for background mode none)
// Returns ivec3 with:
// XY: (0 to _region_size - 1) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
ivec3 get_index_coord(const vec2 uv, const int search) {
vec2 r_uv = round(uv);
vec2 o_uv = mod(r_uv,_region_size);
ivec2 pos;
int bounds, layer_index = -1;
for (int i = -1; i < clamp(search, SKIP_PASS, FRAGMENT_PASS); i++) {
if ((layer_index == -1 && _background_mode == 0u ) || i < 0) {
r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x));
pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2);
bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1);
}
}
return ivec3(ivec2(mod(r_uv,_region_size)), layer_index);
}
// Takes in descaled (world_space / region_size) world to region space XZ (UV2) coordinates, returns vec3 with:
// XY: (0. to 1.) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
vec3 get_index_uv(const vec2 uv2) {
ivec2 pos = ivec2(floor(uv2)) + (_region_map_size / 2);
int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
return vec3(uv2 - _region_locations[layer_index], float(layer_index));
}
void vertex() {
// Get vertex of flat plane in world coordinates and set world UV
v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
// Camera distance to vertex on flat plane
float v_vertex_xz_dist = length(v_vertex.xz - _camera_pos.xz);
// Geomorph vertex, set end and start for linear height interpolate
float scale = MODEL_MATRIX[0][0];
float vertex_lerp = smoothstep(0.55, 0.95, (v_vertex_xz_dist / scale - _mesh_size - 4.0) / (_mesh_size - 2.0));
vec2 v_fract = fract(VERTEX.xz * 0.5) * 2.0;
// For LOD0 morph from a regular grid to an alternating grid to align with LOD1+
vec2 shift = (scale < _vertex_spacing + 1e-6) ? // LOD0 or not
// Shift from regular to symetric
mix(v_fract, vec2(v_fract.x, -v_fract.y),
round(fract(round(mod(v_vertex.z * _vertex_density, 4.0)) *
round(mod(v_vertex.x * _vertex_density, 4.0)) * 0.25))
) :
// Symetric shift
v_fract * round((fract(v_vertex.xz * 0.25 / scale) - 0.5) * 4.0);
vec2 start_pos = v_vertex.xz * _vertex_density;
vec2 end_pos = (v_vertex.xz - shift * scale) * _vertex_density;
v_vertex.xz -= shift * scale * vertex_lerp;
// UV coordinates in world space. Values are 0 to _region_size within regions
UV = v_vertex.xz * _vertex_density;
// UV coordinates in region space + texel offset. Values are 0 to 1 within regions
UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size));
// Discard vertices for Holes. 1 lookup
ivec3 v_region = get_index_coord(start_pos, VERTEX_PASS);
uint control = floatBitsToUint(texelFetch(_control_maps, v_region, 0)).r;
bool hole = DECODE_HOLE(control);
// Show holes to all cameras except mouse camera (on exactly 1 layer)
if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) &&
(hole || (_background_mode == 0u && v_region.z == -1))) {
v_vertex.x = 0. / 0.;
} else {
// Set final vertex height & calculate vertex normals. 3 lookups
ivec3 uv_a = get_index_coord(start_pos, VERTEX_PASS);
ivec3 uv_b = get_index_coord(end_pos, VERTEX_PASS);
float h = mix(texelFetch(_height_maps, uv_a, 0).r,texelFetch(_height_maps, uv_b, 0).r,vertex_lerp);
v_vertex.y = h;
// Vertex normals
float u = mix(texelFetch(_height_maps, get_index_coord(start_pos + vec2(1,0), VERTEX_PASS), 0).r,
texelFetch(_height_maps, get_index_coord(end_pos + vec2(1,0), VERTEX_PASS), 0).r, vertex_lerp);
float v = mix(texelFetch(_height_maps, get_index_coord(start_pos + vec2(0,1), VERTEX_PASS), 0).r,
texelFetch(_height_maps, get_index_coord(end_pos + vec2(0,1), VERTEX_PASS), 0).r, vertex_lerp);
v_normal = normalize(vec3(h - u, _vertex_spacing, h - v));
}
// Convert model space to view space w/ skip_vertex_transform render mode
VERTEX = (VIEW_MATRIX * vec4(v_vertex, 1.0)).xyz;
// Apply terrain normals
vec3 w_tangent = normalize(cross(v_normal, vec3(0.0, 0.0, 1.0)));
vec3 w_binormal = normalize(cross(v_normal, w_tangent));
TBN = mat3(w_tangent, w_binormal, v_normal);
NORMAL = normalize((VIEW_MATRIX * vec4(v_normal, 0.0)).xyz);
BINORMAL = normalize((VIEW_MATRIX * vec4(w_binormal, 0.0)).xyz);
TANGENT = normalize((VIEW_MATRIX * vec4(w_tangent, 0.0)).xyz);
}
////////////////////////
// Fragment
////////////////////////
mat2 rotate_plane(float angle) {
float c = cos(angle), s = sin(angle);
return mat2(vec2(c, s), vec2(-s, c));
}
void fragment() {
// Recover UVs
vec2 uv = UV;
vec2 uv2 = UV2;
// Lookup offsets, ID and blend weight
vec3 region_uv = get_index_uv(uv2);
const vec3 offsets = vec3(0, 1, 2);
vec2 index_id = floor(uv);
vec2 weight = fract(uv);
vec2 invert = 1.0 - weight;
vec4 weights = vec4(
invert.x * weight.y, // 0
weight.x * weight.y, // 1
weight.x * invert.y, // 2
invert.x * invert.y // 3
);
ivec3 index[4];
// control map lookups, used for some normal lookups as well
index[0] = get_index_coord(index_id + offsets.xy, FRAGMENT_PASS);
index[1] = get_index_coord(index_id + offsets.yy, FRAGMENT_PASS);
index[2] = get_index_coord(index_id + offsets.yx, FRAGMENT_PASS);
index[3] = get_index_coord(index_id + offsets.xx, FRAGMENT_PASS);
vec3 base_ddx = dFdxCoarse(v_vertex);
vec3 base_ddy = dFdyCoarse(v_vertex);
vec4 base_dd = vec4(base_ddx.xz, base_ddy.xz);
// Calculate the effective mipmap for regionspace
float region_mip = log2(max(length(base_ddx.xz), length(base_ddy.xz)) * _vertex_density);
// Color map
vec4 color_map = region_uv.z > -1.0 ? textureLod(_color_maps, region_uv, region_mip) : COLOR_MAP;
if (flat_terrain_normals) {
NORMAL = normalize(cross(dFdyCoarse(VERTEX),dFdxCoarse(VERTEX)));
TANGENT = normalize(cross(NORMAL, VIEW_MATRIX[2].xyz));
BINORMAL = normalize(cross(NORMAL, TANGENT));
}
// defaults
vec4 normal_rough = vec4(0., 1., 0., 0.7);
vec4 albedo_height = vec4(1.);
float normal_map_depth = 1.;
float ao_strength = 0.;
if (enable_texturing) {
// set to zero before accumulation
albedo_height = vec4(0.);
normal_rough = vec4(0.);
normal_map_depth = 0.;
ao_strength = 0.;
float total_weight = 0.;
float sharpness = fma(56., blend_sharpness, 8.);
// Get index control data
// 1 - 4 lookups
uvec4 control = floatBitsToUint(vec4(
texelFetch(_control_maps, index[0], 0).r,
texelFetch(_control_maps, index[1], 0).r,
texelFetch(_control_maps, index[2], 0).r,
texelFetch(_control_maps, index[3], 0).r));
{
// Auto blend calculation
float auto_blend = clamp(fma(auto_slope * 2.0, (v_normal.y - 1.0), 1.0)
- auto_height_reduction * 0.01 * v_vertex.y, 0.0, 1.0);
// Enable Autoshader if outside regions or painted in regions, otherwise manual painted
uvec4 is_auto = (control & uvec4(0x1u)) | uvec4(uint(region_uv.z < 0.0));
uint u_auto =
((uint(auto_base_texture) & 0x1Fu) << 27u) |
((uint(auto_overlay_texture) & 0x1Fu) << 22u) |
((uint(fma(auto_blend, 255.0 , 0.5)) & 0xFFu) << 14u);
control = control * (1u - is_auto) + u_auto * is_auto;
}
// Texture weights
// Vectorised Deocode of all texture IDs, then swizzle to per index mapping.
ivec4 t_id[2] = {ivec4(control >> uvec4(27u) & uvec4(0x1Fu)),
ivec4(control >> uvec4(22u) & uvec4(0x1Fu))};
ivec2 texture_ids[4] = ivec2[4](
ivec2(t_id[0].x, t_id[1].x),
ivec2(t_id[0].y, t_id[1].y),
ivec2(t_id[0].z, t_id[1].z),
ivec2(t_id[0].w, t_id[1].w));
// interpolated weights.
vec4 weights_id_1 = vec4(control >> uvec4(14u) & uvec4(0xFFu)) * DIV_255 * weights;
vec4 weights_id_0 = weights - weights_id_1;
vec2 t_weights[4] = {vec2(0), vec2(0), vec2(0), vec2(0)};
for (int i = 0; i < 4; i++) {
vec2 w_0 = vec2(weights_id_0[i]);
vec2 w_1 = vec2(weights_id_1[i]);
ivec2 id_0 = texture_ids[i].xx;
ivec2 id_1 = texture_ids[i].yy;
t_weights[0] += fma(w_0, vec2(equal(texture_ids[0], id_0)), w_1 * vec2(equal(texture_ids[0], id_1)));
t_weights[1] += fma(w_0, vec2(equal(texture_ids[1], id_0)), w_1 * vec2(equal(texture_ids[1], id_1)));
t_weights[2] += fma(w_0, vec2(equal(texture_ids[2], id_0)), w_1 * vec2(equal(texture_ids[2], id_1)));
t_weights[3] += fma(w_0, vec2(equal(texture_ids[3], id_0)), w_1 * vec2(equal(texture_ids[3], id_1)));
}
// Process control data to determine each texture ID present, so that only
// a single sample will be needed later, as all id are contiguous when features
// like detiling, scale, rotation, and projection are not present.
// 2 to 16 lookups
uint id_read = 0u; // 1 bit per possible ID
// world normal adjustment requires acess to previous id during next iteration
vec4 nrm = vec4(0.0, 1.0, 0.0, 1.0);
// adjust uv scale to account for vertex spacing
uv *= _vertex_spacing;
for (int i = 0; i < 4; i++) {
for (int t = 0; t < 2; t++) {
int id = texture_ids[i][t];
uint mask = 1u << uint(id);
if ((id_read & mask) == 0u) {
// Set this id bit
id_read |= mask;
float id_w = t_weights[i][t];
float id_scale = _texture_uv_scale_array[id] * 0.5;
vec2 id_uv = fma(uv, vec2(id_scale), vec2(0.5));
vec4 i_dd = base_dd * id_scale;
vec4 alb = textureGrad(_texture_array_albedo, vec3(id_uv, float(id)), i_dd.xy, i_dd.zw);
float world_normal = clamp(fma(TBN[0], vec3(nrm.x), fma(TBN[1], vec3(nrm.z), v_normal * vec3(nrm.y))).y, 0., 1.);
nrm = textureGrad(_texture_array_normal, vec3(id_uv, float(id)), i_dd.xy, i_dd.zw);
alb.rgb *= _texture_color_array[id].rgb;
nrm.a = clamp(nrm.a + _texture_roughness_mod_array[id], 0., 1.);
// Unpack normal map for blending.
nrm.xyz = fma(nrm.xzy, vec3(2.0), vec3(-1.0));
// height weight modifier.
float id_weight = exp2(sharpness * log2(id_w + alb.a * world_normal));
albedo_height += alb * id_weight;
normal_rough += nrm * id_weight;
normal_map_depth += _texture_normal_depth_array[id] * id_weight;
ao_strength += _texture_ao_strength_array[id] * id_weight;
total_weight += id_weight;
}
}
}
// normalize accumulated values back to 0.0 - 1.0 range.
float weight_inv = 1.0 / total_weight;
albedo_height *= weight_inv;
normal_rough *= weight_inv;
normal_map_depth *= weight_inv;
ao_strength *= weight_inv;
}
// Macro variation. 2 lookups
vec3 macrov = vec3(1.);
if (enable_macro_variation) {
float noise1 = texture(noise_texture, (uv * noise1_scale * .1 + noise1_offset) * rotate_plane(noise1_angle)).r;
float noise2 = texture(noise_texture, uv * noise2_scale * .1).r;
macrov = mix(macro_variation1, vec3(1.), noise1);
macrov *= mix(macro_variation2, vec3(1.), noise2);
macrov = mix(vec3(1.0), macrov, clamp(v_normal.y + macro_variation_slope, 0., 1.));
}
// Wetness/roughness modifier, converting 0 - 1 range to -1 to 1 range, clamped to Godot roughness values
float roughness = clamp(fma(color_map.a - 0.5, 2.0, normal_rough.a), 0., 1.);
// Apply PBR
ALBEDO = albedo_height.rgb * color_map.rgb * macrov;
ROUGHNESS = roughness;
SPECULAR = 1. - normal_rough.a;
// Repack final normal map value.
NORMAL_MAP = fma(normalize(normal_rough.xzy), vec3(0.5), vec3(0.5));
NORMAL_MAP_DEPTH = normal_map_depth;
// Higher and/or facing up, less occluded.
float ao = (1. - (albedo_height.a * log(2.1 - ao_strength))) * (1. - normal_rough.y);
AO = clamp(1. - ao * ao_strength, albedo_height.a, 1.0);
AO_LIGHT_AFFECT = (1.0 - albedo_height.a) * clamp(normal_rough.y, 0., 1.);
}

View File

@@ -0,0 +1 @@
uid://bbx2xhanpq5l3

View File

@@ -0,0 +1,217 @@
// Copyright © 2025 Cory Petkovsek, Roope Palmroos, and Contributors.
// This shader is the minimum needed to allow the terrain to function, without any texturing.
shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,skip_vertex_transform;
// Defined Constants
#define SKIP_PASS 0
#define VERTEX_PASS 1
#define FRAGMENT_PASS 2
#if CURRENT_RENDERER == RENDERER_COMPATIBILITY
#define fma(a, b, c) ((a) * (b) + (c))
#define dFdxCoarse(a) dFdx(a)
#define dFdyCoarse(a) dFdy(a)
#endif
// Private uniforms
// Commented uniforms aren't needed for this shader, but are available for your own needs.
uniform vec3 _camera_pos = vec3(0.f);
uniform float _mesh_size = 48.f;
uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2
uniform uint _mouse_layer = 0x80000000u; // Layer 32
uniform float _vertex_spacing = 1.0;
uniform float _vertex_density = 1.0; // = 1/_vertex_spacing
uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1/1024
uniform int _region_map_size = 32;
uniform int _region_map[1024];
//uniform vec2 _region_locations[1024];
//uniform float _texture_uv_scale_array[32];
//uniform float _texture_detile_array[32];
//uniform vec4 _texture_color_array[32];
uniform highp sampler2DArray _height_maps : repeat_disable;
uniform highp sampler2DArray _control_maps : repeat_disable;
//uniform highp sampler2DArray _color_maps : source_color, filter_linear_mipmap_anisotropic, repeat_disable;
//uniform highp sampler2DArray _texture_array_albedo : source_color, filter_linear_mipmap_anisotropic, repeat_enable;
//uniform highp sampler2DArray _texture_array_normal : hint_normal, filter_linear_mipmap_anisotropic, repeat_enable;
// Public Uniforms
uniform bool flat_terrain_normals = false;
// Varyings & Types
// Some are required for editor functions
varying float v_vertex_xz_dist;
varying vec3 v_vertex;
////////////////////////
// Vertex
////////////////////////
// Takes in world space XZ (UV) coordinates & search depth (only applicable for background mode none)
// Returns ivec3 with:
// XY: (0 to _region_size - 1) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
ivec3 get_index_coord(const vec2 uv, const int search) {
vec2 r_uv = round(uv);
vec2 o_uv = mod(r_uv,_region_size);
ivec2 pos;
int bounds, layer_index = -1;
for (int i = -1; i < clamp(search, SKIP_PASS, FRAGMENT_PASS); i++) {
if ((layer_index == -1 && _background_mode == 0u ) || i < 0) {
r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x));
pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2);
bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1);
}
}
return ivec3(ivec2(mod(r_uv,_region_size)), layer_index);
}
void vertex() {
// Get vertex of flat plane in world coordinates and set world UV
v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
// Camera distance to vertex on flat plane
v_vertex_xz_dist = length(v_vertex.xz - _camera_pos.xz);
// Geomorph vertex, set end and start for linear height interpolate
float scale = MODEL_MATRIX[0][0];
float vertex_lerp = smoothstep(0.55, 0.95, (v_vertex_xz_dist / scale - _mesh_size - 4.0) / (_mesh_size - 2.0));
vec2 v_fract = fract(VERTEX.xz * 0.5) * 2.0;
// For LOD0 morph from a regular grid to an alternating grid to align with LOD1+
vec2 shift = (scale < _vertex_spacing + 1e-6) ? // LOD0 or not
// Shift from regular to symetric
mix(v_fract, vec2(v_fract.x, -v_fract.y),
round(fract(round(mod(v_vertex.z * _vertex_density, 4.0)) *
round(mod(v_vertex.x * _vertex_density, 4.0)) * 0.25))
) :
// Symetric shift
v_fract * round((fract(v_vertex.xz * 0.25 / scale) - 0.5) * 4.0);
vec2 start_pos = v_vertex.xz * _vertex_density;
vec2 end_pos = (v_vertex.xz - shift * scale) * _vertex_density;
v_vertex.xz -= shift * scale * vertex_lerp;
// UV coordinates in world space. Values are 0 to _region_size within regions
UV = v_vertex.xz * _vertex_density;
// UV coordinates in region space + texel offset. Values are 0 to 1 within regions
UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size));
// Discard vertices for Holes. 1 lookup
ivec3 v_region = get_index_coord(start_pos, VERTEX_PASS);
uint control = floatBitsToUint(texelFetch(_control_maps, v_region, 0)).r;
bool hole = bool(control >>2u & 0x1u);
// Show holes to all cameras except mouse camera (on exactly 1 layer)
if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) &&
(hole || (_background_mode == 0u && v_region.z < 0))) {
v_vertex.x = 0. / 0.;
} else {
// Interpolate Geomorph Start & End, set height. 2 Lookups.
ivec3 uv_a = get_index_coord(start_pos, VERTEX_PASS);
ivec3 uv_b = get_index_coord(end_pos, VERTEX_PASS);
float h = mix(texelFetch(_height_maps, uv_a, 0).r, texelFetch(_height_maps, uv_b, 0).r, vertex_lerp);
v_vertex.y = h;
}
// Convert model space to view space w/ skip_vertex_transform render mode
VERTEX = (VIEW_MATRIX * vec4(v_vertex, 1.0)).xyz;
NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz);
TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
}
////////////////////////
// Fragment
////////////////////////
void fragment() {
// Recover UVs
vec2 uv = UV;
//vec2 uv2 = UV2;
// Lookup offsets, ID and blend weight
const vec3 offsets = vec3(0, 1, 2);
vec2 index_id = floor(uv);
vec2 weight = fract(uv);
vec2 invert = 1.0 - weight;
vec4 weights = vec4(
invert.x * weight.y, // 0
weight.x * weight.y, // 1
weight.x * invert.y, // 2
invert.x * invert.y // 3
);
vec3 base_ddx = dFdxCoarse(v_vertex);
vec3 base_ddy = dFdyCoarse(v_vertex);
//vec4 base_derivatives = vec4(base_ddx.xz, base_ddy.xz);
// Calculate the effective mipmap for regionspace, and if less than 0,
// skip all extra lookups required for bilinear blend.
float region_mip = log2(max(length(base_ddx.xz), length(base_ddy.xz)) * _vertex_density);
bool bilerp = region_mip < 0.0;
ivec3 index[4];
// control map lookups, used for some normal lookups as well
index[0] = get_index_coord(index_id + offsets.xy, FRAGMENT_PASS);
index[1] = get_index_coord(index_id + offsets.yy, FRAGMENT_PASS);
index[2] = get_index_coord(index_id + offsets.yx, FRAGMENT_PASS);
index[3] = get_index_coord(index_id + offsets.xx, FRAGMENT_PASS);
// Terrain normals
vec3 index_normal[4];
float h[4];
// allows additional derivatives, eg world noise, brush previews etc
float u = 0.0;
float v = 0.0;
// Re-use index[] for the first lookups, skipping some math. 3 lookups
h[3] = texelFetch(_height_maps, index[3], 0).r; // 0 (0,0)
h[2] = texelFetch(_height_maps, index[2], 0).r; // 1 (1,0)
h[0] = texelFetch(_height_maps, index[0], 0).r; // 2 (0,1)
index_normal[3] = normalize(vec3(h[3] - h[2] + u, _vertex_spacing, h[3] - h[0] + v));
// Set flat world normal - overriden if bilerp is true
vec3 w_normal = index_normal[3];
// Branching smooth normals must be done seperatley for correct normals at all 4 index ids
if (bilerp) {
// 5 lookups
// Fetch the additional required height values for smooth normals
h[1] = texelFetch(_height_maps, index[1], 0).r; // 3 (1,1)
float h_4 = texelFetch(_height_maps, get_index_coord(index_id + offsets.yz, FRAGMENT_PASS), 0).r; // 4 (1,2)
float h_5 = texelFetch(_height_maps, get_index_coord(index_id + offsets.zy, FRAGMENT_PASS), 0).r; // 5 (2,1)
float h_6 = texelFetch(_height_maps, get_index_coord(index_id + offsets.zx, FRAGMENT_PASS), 0).r; // 6 (2,0)
float h_7 = texelFetch(_height_maps, get_index_coord(index_id + offsets.xz, FRAGMENT_PASS), 0).r; // 7 (0,2)
// Calculate the normal for the remaining index ids.
index_normal[0] = normalize(vec3(h[0] - h[1] + u, _vertex_spacing, h[0] - h_7 + v));
index_normal[1] = normalize(vec3(h[1] - h_5 + u, _vertex_spacing, h[1] - h_4 + v));
index_normal[2] = normalize(vec3(h[2] - h_6 + u, _vertex_spacing, h[2] - h[1] + v));
// Set interpolated world normal
w_normal =
index_normal[0] * weights[0] +
index_normal[1] * weights[1] +
index_normal[2] * weights[2] +
index_normal[3] * weights[3] ;
}
// Apply terrain normals
vec3 w_tangent = normalize(cross(w_normal, vec3(0.0, 0.0, 1.0)));
vec3 w_binormal = normalize(cross(w_normal, w_tangent));
NORMAL = mat3(VIEW_MATRIX) * w_normal;
TANGENT = mat3(VIEW_MATRIX) * w_tangent;
BINORMAL = mat3(VIEW_MATRIX) * w_binormal;
if (flat_terrain_normals) {
NORMAL = normalize(cross(dFdyCoarse(VERTEX),dFdxCoarse(VERTEX)));
TANGENT = normalize(cross(NORMAL, VIEW_MATRIX[2].xyz));
BINORMAL = normalize(cross(NORMAL, TANGENT));
}
// Apply PBR
ALBEDO = vec3(.2);
ROUGHNESS = .7;
}

View File

@@ -0,0 +1 @@
uid://01qauauvd8aa

View File

@@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="16"
viewBox="0 0 16 16"
width="16"
version="1.1"
id="svg3088"
sodipodi:docname="icon_terrain_material.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3092">
<linearGradient
id="linearGradient7208"
gradientUnits="userSpaceOnUse"
x1="8.3533525"
x2="8.3533525"
y1="8.3028736"
y2="12.261972">
<stop
offset="0.07497349"
stop-color="#5fb2ff"
id="stop7204"
style="stop-color:#ffd4d4;stop-opacity:1;" />
<stop
offset="0.63987136"
stop-color="#5fb2ff"
id="stop7210"
style="stop-color:#e69971;stop-opacity:1;" />
<stop
offset="1"
stop-color="#a2d2ff"
id="stop7206"
style="stop-color:#88fc7f;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient7200"
gradientUnits="userSpaceOnUse"
x1="8.3533525"
x2="8.3533525"
y1="8.3028736"
y2="12.261972">
<stop
offset="0.0442211"
stop-color="#5fb2ff"
id="stop7186"
style="stop-color:#ff4545;stop-opacity:1;" />
<stop
offset="0.1382958"
stop-color="#5fb2ff"
id="stop7188"
style="stop-color:#ffe345;stop-opacity:1;" />
<stop
offset="0.32638258"
stop-color="#5fb2ff"
id="stop7190"
style="stop-color:#80ff45;stop-opacity:1;" />
<stop
offset="0.5233199"
stop-color="#5fb2ff"
id="stop7192"
style="stop-color:#45ffa2;stop-opacity:1;" />
<stop
offset="0.69092047"
stop-color="#5fb2ff"
id="stop7194"
style="stop-color:#45d7ff;stop-opacity:1;" />
<stop
offset="0.85671425"
stop-color="#5fb2ff"
id="stop7196"
style="stop-color:#8045ff;stop-opacity:1;" />
<stop
offset="1"
stop-color="#a2d2ff"
id="stop7198"
style="stop-color:#ff4596;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="a-78"
gradientUnits="userSpaceOnUse"
x1="8.3533525"
x2="8.3533525"
y1="8.3028736"
y2="12.261972">
<stop
offset="0.04827991"
stop-color="#5fb2ff"
id="stop974"
style="stop-color:#ff4545;stop-opacity:1;" />
<stop
offset="0.1382958"
stop-color="#5fb2ff"
id="stop6790"
style="stop-color:#ffe345;stop-opacity:1;" />
<stop
offset="0.32638258"
stop-color="#5fb2ff"
id="stop6861"
style="stop-color:#80ff45;stop-opacity:1;" />
<stop
offset="0.5233199"
stop-color="#5fb2ff"
id="stop6932"
style="stop-color:#45ffa2;stop-opacity:1;" />
<stop
offset="0.69092047"
stop-color="#5fb2ff"
id="stop6934"
style="stop-color:#45d7ff;stop-opacity:1;" />
<stop
offset="0.85671425"
stop-color="#5fb2ff"
id="stop6936"
style="stop-color:#8045ff;stop-opacity:1;" />
<stop
offset="1"
stop-color="#a2d2ff"
id="stop28-9"
style="stop-color:#ff4596;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient986"
gradientUnits="userSpaceOnUse"
x1="8.3533525"
x2="8.3533525"
y1="8.3028736"
y2="12.261972">
<stop
offset="0.33542365"
stop-color="#5fb2ff"
id="stop982"
style="stop-color:#ffa7a7;stop-opacity:1;" />
<stop
offset="1"
stop-color="#a2d2ff"
id="stop984"
style="stop-color:#fc7f7f;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient7208"
id="linearGradient7167"
x1="-11.46914"
y1="2.1907859"
x2="-11.460287"
y2="13.545624"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(19.493797)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient7208"
id="linearGradient7202"
x1="-14.857841"
y1="4.9543786"
x2="-14.958795"
y2="12.934526"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(19.493797)" />
</defs>
<sodipodi:namedview
id="namedview3090"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
showgrid="false"
inkscape:zoom="12.59375"
inkscape:cx="-7.5037221"
inkscape:cy="12.466501"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg3088" />
<path
id="path31"
style="fill:url(#linearGradient7167);fill-opacity:1;stroke-width:1.11229"
d="m 8.0074686,1.7910156 c -1.368915,0.09588 -1.692429,3.8264137 -2.822266,3.7910156 -1.977176,-0.061946 -2.315719,3.0789623 -3.148437,4.6777348 L 0.20278059,11.044922 7.9898906,14.380859 15.775047,11.044922 13.997703,10.283203 C 13.467188,8.6236354 13.491849,7.2829163 12.616843,6.2304688 11.823643,5.2764167 11.444597,3.7773719 8.6637186,1.9941406 8.4200366,1.8378802 8.2030276,1.7773185 8.0074686,1.7910156 Z" />
<path
d="m 1.6979896,10.77748 c 1.112295,-1.282509 1.320286,-5.8794797 3.544055,-5.8098075 4.6412106,4.5094283 2.498421,3.8179938 4.057225,7.7556465 -3.217392,0.01725 -3.237576,-1.158088 -7.60128,-1.945839 z"
fill="url(#a)"
id="path978"
style="fill:url(#linearGradient7202);fill-opacity:1;stroke-width:1.19437"
sodipodi:nodetypes="cccc" />
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bdwolwswwy8wr"
path="res://.godot/imported/autoshader.svg-9998e61bbc6afd5b134b767acd17a425.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/autoshader.svg"
dest_files=["res://.godot/imported/autoshader.svg-9998e61bbc6afd5b134b767acd17a425.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg2"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="icon_color.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
id="metadata12"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs10"><linearGradient
inkscape:collect="always"
id="linearGradient40333"><stop
style="stop-color:#fc7f7f;stop-opacity:1;"
offset="0"
id="stop40329" /><stop
style="stop-color:#7fb0bd;stop-opacity:1;"
offset="0.50160772"
id="stop40337" /><stop
style="stop-color:#7ffc7f;stop-opacity:1;"
offset="1"
id="stop40331" /></linearGradient><inkscape:path-effect
effect="spiro"
id="path-effect8712"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="powerstroke"
id="path-effect8643"
is_visible="true"
lpeversion="1"
offset_points="0.86174895,0.26516503"
not_jump="true"
sort_points="true"
interpolator_type="CentripetalCatmullRom"
interpolator_beta="0.75"
start_linecap_type="round"
linejoin_type="spiro"
miter_limit="4"
scale_width="1"
end_linecap_type="round" /><inkscape:path-effect
effect="simplify"
id="path-effect8641"
is_visible="true"
lpeversion="1"
steps="1"
threshold="0.0028332064"
smooth_angles="0"
helper_size="0"
simplify_individual_paths="false"
simplify_just_coalesce="false"
step="1" /><inkscape:path-effect
effect="spiro"
id="path-effect5927"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect5921"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect5163"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4431"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4425"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4419"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4413"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4407"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4401"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4395"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4389"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect2931"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect2925"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect3156"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4245"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect4977"
is_visible="true"
lpeversion="1" /><inkscape:path-effect
effect="spiro"
id="path-effect3156-0"
is_visible="true"
lpeversion="1" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient40333"
id="linearGradient35201"
x1="5.3624678"
y1="3.5122564"
x2="12.772088"
y2="11.423013"
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1009"
id="namedview8"
showgrid="false"
inkscape:zoom="22.627418"
inkscape:cx="7.5793003"
inkscape:cy="9.4133584"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
inkscape:object-paths="false"
inkscape:snap-smooth-nodes="false"
inkscape:object-nodes="true"
inkscape:snap-grids="false"
inkscape:snap-to-guides="true"
inkscape:pagecheckerboard="0"
inkscape:showpageshadow="0"
inkscape:deskcolor="#d1d1d1"><inkscape:grid
type="xygrid"
id="grid4140" /></sodipodi:namedview><path
fill="none"
d="M -0.76108454,-0.19858458 H 16.761085 V 17.323585 H -0.76108454 Z"
id="path34808"
style="stroke-width:0.73009" /><path
d="M 3.3537048,4.6462952 8,0 12.646295,4.6462952 c 4.13963,4.139681 1.207353,11.2167178 -4.6462951,11.2167178 -5.8536477,0 -8.78592555,-7.0770368 -4.6462951,-11.2167178 z"
id="path34810"
style="fill:url(#linearGradient35201);fill-opacity:1;stroke-width:0.73009"
sodipodi:nodetypes="cccsc" /></svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://krrmpalen8xu"
path="res://.godot/imported/color_paint.svg-2a416ebf35da04135017e5c6ef53ea57.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/color_paint.svg"
dest_files=["res://.godot/imported/color_paint.svg-2a416ebf35da04135017e5c6ef53ea57.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" sodipodi:docname="icon_height_add.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<defs>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect4977"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect4245"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect3156"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect2324"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="powerstroke" is_visible="true" scale_width="1" miter_limit="4" linejoin_type="spiro" sort_points="true" not_jump="true" offset_points="0.76255776,0.35156248" id="path-effect2285" start_linecap_type="round" end_linecap_type="round" interpolator_type="CentripetalCatmullRom" interpolator_beta="0.75">
</inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="simplify" is_visible="true" step="1" helper_size="0" smooth_angles="0" threshold="0.0028332064" steps="1" id="path-effect2283" simplify_individual_paths="false" simplify_just_coalesce="false">
</inkscape:path-effect>
</defs>
<sodipodi:namedview inkscape:cy="12.81631" inkscape:cx="8.1096304" inkscape:zoom="22.627418" showgrid="false" guidetolerance="10" gridtolerance="10" objecttolerance="10" borderopacity="1" pagecolor="#ffffff" bordercolor="#666666" id="namedview8" inkscape:current-layer="path3154" inkscape:window-maximized="1" inkscape:window-y="-8" inkscape:window-x="-8" inkscape:object-nodes="true" inkscape:snap-grids="false" inkscape:window-height="1009" inkscape:window-width="1920" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:object-paths="false" inkscape:snap-smooth-nodes="false" inkscape:snap-to-guides="true" inkscape:pagecheckerboard="0" inkscape:showpageshadow="0" inkscape:deskcolor="#d1d1d1" showguides="false">
<inkscape:grid type="xygrid" id="grid4140"></inkscape:grid>
</sodipodi:namedview>
<path fill="#FC7F7F" d="M15.203,9.736c-0.887-0.184-1.725-0.729-2.248-1.467c-0.525-0.739-0.82-1.83-1.424-2.988
C11.229,4.7,10.833,4.103,10.26,3.613C9.678,3.116,8.924,2.751,8.064,2.732c-0.908-0.02-1.713,0.354-2.332,0.875
C5.124,4.12,4.712,4.752,4.398,5.367c-0.624,1.225-0.924,2.378-1.49,3.139C2.425,9.154,1.684,9.641,0.895,9.82L0,9.979V16h16V9.9
L15.203,9.736z M9,10.688v4H7v-4H4l4-5.25l4,5.25H9z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bcmbqryggekg1"
path="res://.godot/imported/height_add.svg-9e680ce71fa4c541748e081b99167369.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/height_add.svg"
dest_files=["res://.godot/imported/height_add.svg-9e680ce71fa4c541748e081b99167369.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="svg2"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="icon_height_div.svg"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2033">
<inkscape:path-effect
id="path-effect6469"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect6463"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect4977"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect4245"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect3156"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect2324"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
offset_points="0.76255776,0.35156248"
not_jump="true"
sort_points="true"
linejoin_type="spiro"
miter_limit="4"
scale_width="1"
id="path-effect2285"
is_visible="true"
effect="powerstroke"
lpeversion="1"
interpolator_beta="0.75"
interpolator_type="CentripetalCatmullRom"
end_linecap_type="round"
start_linecap_type="round">
</inkscape:path-effect>
<inkscape:path-effect
steps="1"
threshold="0.0028332064"
smooth_angles="0"
helper_size="0"
step="1"
id="path-effect2283"
is_visible="true"
effect="simplify"
lpeversion="1"
simplify_just_coalesce="false"
simplify_individual_paths="false">
</inkscape:path-effect>
<inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect4977-4" /><inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect4245-1" /><inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect3156-8" /><inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect2324-5" /><inkscape:path-effect
lpeversion="1"
effect="powerstroke"
is_visible="true"
scale_width="1"
miter_limit="4"
linejoin_type="spiro"
sort_points="true"
not_jump="true"
offset_points="0.76255776,0.35156248"
id="path-effect2285-9"
start_linecap_type="round"
end_linecap_type="round"
interpolator_type="CentripetalCatmullRom"
interpolator_beta="0.75">
</inkscape:path-effect><inkscape:path-effect
lpeversion="1"
effect="simplify"
is_visible="true"
step="1"
helper_size="0"
smooth_angles="0"
threshold="0.0028332064"
steps="1"
id="path-effect2283-2"
simplify_individual_paths="false"
simplify_just_coalesce="false">
</inkscape:path-effect></defs>
<sodipodi:namedview
showguides="false"
bordercolor="#666666"
pagecolor="#ffffff"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
showgrid="false"
inkscape:zoom="11.313709"
inkscape:cx="3.4913396"
inkscape:cy="13.788582"
id="namedview8"
inkscape:deskcolor="#d1d1d1"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:snap-to-guides="true"
inkscape:snap-smooth-nodes="false"
inkscape:object-paths="false"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:snap-grids="false"
inkscape:object-nodes="true"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid4140" />
</sodipodi:namedview>
<path
id="path4012"
style="fill:#fc7f7f;fill-opacity:1;stroke-width:0.764771"
d="M 1.5898438 3.2871094 C 1.0957748 3.280765 0.56716282 3.3249664 0 3.4257812 L 0 15.955078 L 16 15.955078 L 16 12.246094 C 10.09046 15.642843 7.1418918 10.840026 5.1035156 6.2128906 C 6.678498 7.1187996 6.5445981 7.3630122 8.4746094 9.703125 C 11.163354 13.034961 13.74668 11.801049 16 10.460938 L 16 8.2597656 C 8.6991041 14.580269 9.0008764 3.3822748 1.5898438 3.2871094 z " /><path
id="path16308"
sodipodi:nodetypes="sssscccccccccccssss"
display="none"
fill="#FC7F7F"
d="M8.064,1.4 C7.156,1.38,6.351,1.753,5.732,2.275C5.124,2.788,4.711,3.42,4.398,4.035C3.774,5.26,3.475,6.414,2.908,7.173 c-0.483,0.65-1.224,1.135-2.013,1.315L0,8.646V10.8c1.843,0.457,5.033-1.792,5.506-4.325C6.03,5.322,6.454,3.693,7.883,3.408h0.049 l0.1-0.006c1.329,0.167,1.81,1.646,2.282,2.701c0.816,3.09,3.985,4.793,5.687,4.59V8.568l-0.797-0.166 c-0.888-0.183-1.726-0.729-2.248-1.467c-0.524-0.739-0.819-1.83-1.424-2.988c-0.304-0.581-0.698-1.178-1.271-1.668 C9.678,1.784,8.924,1.418,8.064,1.4z" />
<path
id="path16308_2_"
sodipodi:nodetypes="sssscccccccccccssss"
display="none"
fill="#FC7F7F"
d="M8.064,2.835 C7.156,2.815,6.351,3.188,5.732,3.71c-0.608,0.513-1.021,1.145-1.334,1.76C3.774,6.695,3.475,7.85,2.908,8.608 c-0.483,0.65-1.224,1.136-2.013,1.315L0,10.082v2.153c1.843,0.457,5.033-1.792,5.506-4.325C6.03,6.758,6.454,5.128,7.883,4.844 h0.049l0.1-0.006c1.329,0.167,1.81,1.646,2.282,2.701c0.816,3.09,3.985,4.793,5.687,4.59v-2.125l-0.797-0.166 c-0.888-0.183-1.726-0.729-2.248-1.466c-0.524-0.739-0.819-1.83-1.424-2.988c-0.304-0.581-0.698-1.178-1.271-1.668 C9.678,3.22,8.924,2.854,8.064,2.835z" />
<path
id="path16308_1_"
sodipodi:nodetypes="sssscccccccccccssss"
display="none"
fill="#FC7F7F"
d="M0,6.91v2.139 c1.578,0,16.001,0,16.001,0V6.91H0z" />
<path
display="none"
fill="#FC7F7F"
d="M10.064,9.872C9.579,8.813,9.3,6.726,7.882,6.742C6.454,7.026,6.5,8.686,5.976,9.842 C5.39,11.51,1.708,12.982,0,13.574V16c4,0,12,0,16,0v-2.537C14.176,12.84,10.674,11.646,10.064,9.872z"
id="path2040" />
<path
display="none"
fill="#FC7F7F"
d="M0,8c0,0,0.917,2.709,2.104,2.479S3,5.375,4.063,5.167s0.521,6.083,2.188,5.958 S6.104,4.313,8.458,3.438s-1.583,7.979,0.563,8.688s2.208-8.479,4.521-9.729s-1.292,10.271,1.375,10.75"
id="path2042" />
<path
d="M 0,0 14.842,0.004 16,0 Z"
id="rect12437" /></svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://danh7tb2v6rx7"
path="res://.godot/imported/height_div.svg-449a465f9fdd11ab59f2f1c78815408c.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/height_div.svg"
dest_files=["res://.godot/imported/height_div.svg-449a465f9fdd11ab59f2f1c78815408c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" sodipodi:docname="icon_height_flat.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<defs>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect4977"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect4245"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect3156"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="spiro" is_visible="true" id="path-effect2324"></inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="powerstroke" is_visible="true" scale_width="1" miter_limit="4" linejoin_type="spiro" sort_points="true" not_jump="true" offset_points="0.76255776,0.35156248" id="path-effect2285" start_linecap_type="round" end_linecap_type="round" interpolator_type="CentripetalCatmullRom" interpolator_beta="0.75">
</inkscape:path-effect>
<inkscape:path-effect lpeversion="1" effect="simplify" is_visible="true" step="1" helper_size="0" smooth_angles="0" threshold="0.0028332064" steps="1" id="path-effect2283" simplify_individual_paths="false" simplify_just_coalesce="false">
</inkscape:path-effect>
</defs>
<sodipodi:namedview inkscape:cy="6.8059028" inkscape:cx="11.866136" inkscape:zoom="22.627417" showgrid="false" guidetolerance="10" gridtolerance="10" objecttolerance="10" borderopacity="1" pagecolor="#ffffff" bordercolor="#666666" id="namedview8" inkscape:current-layer="svg2" inkscape:window-maximized="1" inkscape:window-y="-8" inkscape:window-x="-8" inkscape:object-nodes="true" inkscape:snap-grids="false" inkscape:window-height="1009" inkscape:window-width="1920" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:object-paths="false" inkscape:snap-smooth-nodes="false" inkscape:snap-to-guides="true" inkscape:pagecheckerboard="0" inkscape:showpageshadow="0" inkscape:deskcolor="#d1d1d1" showguides="false">
<inkscape:grid type="xygrid" id="grid4140"></inkscape:grid>
</sodipodi:namedview>
<path id="path3133" sodipodi:nodetypes="cscccccccscc" fill="#FC7F7F" d="M4.398,8.417c-0.624,1.225-0.924,2.378-1.49,3.138
c-0.483,0.649-1.225,1.135-2.014,1.314L0,13.027V16l1.158-0.004L16,16v-3.051l-0.797-0.164c-0.887-0.183-1.725-0.729-2.248-1.467
c-0.525-0.738-0.82-1.83-1.424-2.988L4.398,8.417z"/>
<polygon fill="#FC7F7F" points="3.375,5.331 7.375,5.331 7.375,8.331 12.625,4.331 7.375,0.331 7.375,3.331 3.375,3.331 "/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://crj0xfyiyr45u"
path="res://.godot/imported/height_flat.svg-be726a006bf06e05a7a8867510f3996e.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/height_flat.svg"
dest_files=["res://.godot/imported/height_flat.svg-be726a006bf06e05a7a8867510f3996e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="svg2"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="icon_height_mul.svg"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2033">
<inkscape:path-effect
id="path-effect6469"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect6463"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect4977"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect4245"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect3156"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
id="path-effect2324"
is_visible="true"
effect="spiro"
lpeversion="1" />
<inkscape:path-effect
offset_points="0.76255776,0.35156248"
not_jump="true"
sort_points="true"
linejoin_type="spiro"
miter_limit="4"
scale_width="1"
id="path-effect2285"
is_visible="true"
effect="powerstroke"
lpeversion="1"
interpolator_beta="0.75"
interpolator_type="CentripetalCatmullRom"
end_linecap_type="round"
start_linecap_type="round">
</inkscape:path-effect>
<inkscape:path-effect
steps="1"
threshold="0.0028332064"
smooth_angles="0"
helper_size="0"
step="1"
id="path-effect2283"
is_visible="true"
effect="simplify"
lpeversion="1"
simplify_just_coalesce="false"
simplify_individual_paths="false">
</inkscape:path-effect>
<inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect4977-4" /><inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect4245-1" /><inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect3156-8" /><inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect2324-5" /><inkscape:path-effect
lpeversion="1"
effect="powerstroke"
is_visible="true"
scale_width="1"
miter_limit="4"
linejoin_type="spiro"
sort_points="true"
not_jump="true"
offset_points="0.76255776,0.35156248"
id="path-effect2285-9"
start_linecap_type="round"
end_linecap_type="round"
interpolator_type="CentripetalCatmullRom"
interpolator_beta="0.75">
</inkscape:path-effect><inkscape:path-effect
lpeversion="1"
effect="simplify"
is_visible="true"
step="1"
helper_size="0"
smooth_angles="0"
threshold="0.0028332064"
steps="1"
id="path-effect2283-2"
simplify_individual_paths="false"
simplify_just_coalesce="false">
</inkscape:path-effect></defs>
<sodipodi:namedview
showguides="false"
bordercolor="#666666"
pagecolor="#ffffff"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
showgrid="false"
inkscape:zoom="11.313709"
inkscape:cx="13.832776"
inkscape:cy="18.031222"
id="namedview8"
inkscape:deskcolor="#d1d1d1"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:snap-to-guides="true"
inkscape:snap-smooth-nodes="false"
inkscape:object-paths="false"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:snap-grids="false"
inkscape:object-nodes="true"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid4140" />
</sodipodi:namedview>
<path
style="fill:#fc7f7f;fill-opacity:1;stroke-width:0.764771"
d="M 1.5898438,5.5417983 C 1.0957744,5.5354539 0.56716339,5.5780631 0,5.6788781 V 15.955806 H 16 V 10.513229 C 8.6990968,16.833739 9.0008839,5.6369638 1.5898438,5.5417983 Z"
id="path4012"
sodipodi:nodetypes="sccccs" /><path
id="path16308"
sodipodi:nodetypes="sssscccccccccccssss"
display="none"
fill="#FC7F7F"
d="M8.064,1.4 C7.156,1.38,6.351,1.753,5.732,2.275C5.124,2.788,4.711,3.42,4.398,4.035C3.774,5.26,3.475,6.414,2.908,7.173 c-0.483,0.65-1.224,1.135-2.013,1.315L0,8.646V10.8c1.843,0.457,5.033-1.792,5.506-4.325C6.03,5.322,6.454,3.693,7.883,3.408h0.049 l0.1-0.006c1.329,0.167,1.81,1.646,2.282,2.701c0.816,3.09,3.985,4.793,5.687,4.59V8.568l-0.797-0.166 c-0.888-0.183-1.726-0.729-2.248-1.467c-0.524-0.739-0.819-1.83-1.424-2.988c-0.304-0.581-0.698-1.178-1.271-1.668 C9.678,1.784,8.924,1.418,8.064,1.4z" />
<path
id="path16308_2_"
sodipodi:nodetypes="sssscccccccccccssss"
display="none"
fill="#FC7F7F"
d="M8.064,2.835 C7.156,2.815,6.351,3.188,5.732,3.71c-0.608,0.513-1.021,1.145-1.334,1.76C3.774,6.695,3.475,7.85,2.908,8.608 c-0.483,0.65-1.224,1.136-2.013,1.315L0,10.082v2.153c1.843,0.457,5.033-1.792,5.506-4.325C6.03,6.758,6.454,5.128,7.883,4.844 h0.049l0.1-0.006c1.329,0.167,1.81,1.646,2.282,2.701c0.816,3.09,3.985,4.793,5.687,4.59v-2.125l-0.797-0.166 c-0.888-0.183-1.726-0.729-2.248-1.466c-0.524-0.739-0.819-1.83-1.424-2.988c-0.304-0.581-0.698-1.178-1.271-1.668 C9.678,3.22,8.924,2.854,8.064,2.835z" />
<path
id="path16308_1_"
sodipodi:nodetypes="sssscccccccccccssss"
display="none"
fill="#FC7F7F"
d="M0,6.91v2.139 c1.578,0,16.001,0,16.001,0V6.91H0z" />
<path
display="none"
fill="#FC7F7F"
d="M10.064,9.872C9.579,8.813,9.3,6.726,7.882,6.742C6.454,7.026,6.5,8.686,5.976,9.842 C5.39,11.51,1.708,12.982,0,13.574V16c4,0,12,0,16,0v-2.537C14.176,12.84,10.674,11.646,10.064,9.872z"
id="path2040" />
<path
display="none"
fill="#FC7F7F"
d="M0,8c0,0,0.917,2.709,2.104,2.479S3,5.375,4.063,5.167s0.521,6.083,2.188,5.958 S6.104,4.313,8.458,3.438s-1.583,7.979,0.563,8.688s2.208-8.479,4.521-9.729s-1.292,10.271,1.375,10.75"
id="path2042" />
<path
d="M 0,0 14.842,0.004 16,0 Z"
id="rect12437" /><path
id="path7096"
style="fill:#fc7f7f;fill-opacity:1;stroke-width:0.764771"
d="M 0,2.0234375 V 3.8085938 C 2.8512164,3.4688215 4.2747356,4.3685854 5.2041205,5.9137947 6.7118368,6.8603322 6.6718914,7.2163955 8.3808594,8.5644531 6.2801351,4.1747406 5.2031416,1.5917313 0,2.0234375 Z"
sodipodi:nodetypes="ccccc" /></svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bu3q0645kb3el"
path="res://.godot/imported/height_mul.svg-2dca20fa42a85408713e9bfe411f3c79.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/height_mul.svg"
dest_files=["res://.godot/imported/height_mul.svg-2dca20fa42a85408713e9bfe411f3c79.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="svg2"
sodipodi:docname="icon_height_slope.svg"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">&#10;<defs
id="defs1">&#10; &#10; <inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect4977" />&#10; <inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect4245" />&#10; <inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect3156" />&#10; <inkscape:path-effect
lpeversion="1"
effect="spiro"
is_visible="true"
id="path-effect2324" />&#10; &#10; <inkscape:path-effect
lpeversion="1"
effect="powerstroke"
is_visible="true"
scale_width="1"
miter_limit="4"
linejoin_type="spiro"
sort_points="true"
not_jump="true"
offset_points="0.76255776,0.35156248"
id="path-effect2285"
start_linecap_type="round"
end_linecap_type="round"
interpolator_type="CentripetalCatmullRom"
interpolator_beta="0.75">&#10; </inkscape:path-effect>&#10; &#10; <inkscape:path-effect
lpeversion="1"
effect="simplify"
is_visible="true"
step="1"
helper_size="0"
smooth_angles="0"
threshold="0.0028332064"
steps="1"
id="path-effect2283"
simplify_individual_paths="false"
simplify_just_coalesce="false">&#10; </inkscape:path-effect>&#10;</defs>&#10;<sodipodi:namedview
inkscape:cy="27.665553"
inkscape:cx="-14.760854"
inkscape:zoom="5.6568543"
showgrid="false"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
pagecolor="#ffffff"
bordercolor="#666666"
id="namedview8"
inkscape:current-layer="svg2"
inkscape:window-maximized="1"
inkscape:window-y="32"
inkscape:window-x="0"
inkscape:object-nodes="true"
inkscape:snap-grids="false"
inkscape:window-height="1011"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
inkscape:object-paths="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-to-guides="true"
inkscape:pagecheckerboard="0"
inkscape:showpageshadow="0"
inkscape:deskcolor="#d1d1d1"
showguides="false">&#10; <inkscape:grid
type="xygrid"
id="grid4140"
originx="0"
originy="0"
spacingy="1"
spacingx="1"
units="px"
visible="false" />&#10;</sodipodi:namedview>&#10;&#10;<polygon
fill="#fc7f7f"
points="3.375,5.331 7.375,5.331 7.375,8.331 12.625,4.331 7.375,0.331 7.375,3.331 3.375,3.331 "
id="polygon1"
transform="rotate(45,9.0843727,9.1561132)" />&#10;<path
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:2"
d="M 0,0 16,16 H 0 Z"
id="path1"
sodipodi:nodetypes="cccc" /></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://0cd7so4kw7da"
path="res://.godot/imported/height_slope.svg-e20540c5538d0c57a9d229a772b3d1b3.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/terrain_3d/icons/height_slope.svg"
dest_files=["res://.godot/imported/height_slope.svg-e20540c5538d0c57a9d229a772b3d1b3.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=false

Some files were not shown because too many files have changed in this diff Show More