mise a jour addons

This commit is contained in:
deed 2024-01-26 21:00:32 +01:00
parent 9a36dd059c
commit c27c38be13
51 changed files with 576 additions and 251 deletions

View file

@ -1,3 +1,3 @@
source_md5="d28fc1b4998adc3f0ef9aeebc3099059"
dest_md5="9d25e863ac55fd1d3e430f85c32712f4"
dest_md5="6ce83fd2912a369d4bda57c992027f33"

View file

@ -221,7 +221,7 @@ static func request_parent_to_rebuild(node: Node, deferred := true) -> void:
# Recursively search for all MeshInstances3D in the node's children and
# returns them all in an array. If node is a MeshInstance, it will also be
# added to the array
static func get_all_mesh_instances_from(node: Node3D) -> Array[MeshInstance3D]:
static func get_all_mesh_instances_from(node: Node) -> Array[MeshInstance3D]:
var res: Array[MeshInstance3D] = []
if node is MeshInstance3D:
@ -427,7 +427,7 @@ static func get_merged_meshes_from(item: ProtonScatterItem) -> MeshInstance3D:
return instance
static func get_all_static_bodies_from(node: Node3D) -> Array[StaticBody3D]:
static func get_all_static_bodies_from(node: Node) -> Array[StaticBody3D]:
var res: Array[StaticBody3D] = []
if node is StaticBody3D:

View file

@ -2,7 +2,7 @@
importer="glsl"
type="RDShaderFile"
uid="uid://p5gs3onqlpf2"
uid="uid://dksrw0kl2yjtg"
path="res://.godot/imported/compute_relax.glsl-b06f9e60cda7719b78bde9673f2501b7.res"
[deps]

View file

@ -153,7 +153,8 @@ func _on_load_full_preset(path: String) -> void:
ProtonScatterUtil.set_owner_recursive(_scatter_node, get_tree().get_edited_scene_root())
preset.queue_free()
_scatter_node.rebuild.call_deferred()
hide()

View file

@ -721,5 +721,10 @@ func _on_transforms_ready(new_transforms: ProtonScatterTransformList) -> void:
update_gizmos()
build_version += 1
if not is_inside_tree():
return
await get_tree().process_frame
build_completed.emit()

View file

@ -4,7 +4,6 @@ extends "base_parameter.gd"
@onready var _label: Label = $%Label
@onready var _select_button: Button = $%SelectButton
@onready var _clear_button: Button = $%ClearButton
@onready var _popup: ConfirmationDialog = $%ConfirmationDialog
@onready var _tree: Tree = $%Tree
@ -48,26 +47,39 @@ func get_value() -> NodePath:
func _populate_tree() -> void:
_tree.clear()
var scene_root: Node = get_tree().get_edited_scene_root()
var editor_theme: Theme
var tmp = EditorPlugin.new() # TODO: check if this works in release builds
var gui: Control = tmp.get_editor_interface().get_base_control()
var editor_theme = gui.get_theme()
tmp.queue_free()
if EditorInterface.has_method("get_editor_theme"):
editor_theme = EditorInterface.get_editor_theme()
else:
# 4.1 backward compatibility
var tmp = EditorPlugin.new() # TODO: check if this works in release builds
var gui: Control = tmp.get_editor_interface().get_base_control()
editor_theme = gui.get_theme()
tmp.queue_free()
_create_items_recursive(scene_root, null, editor_theme)
func _create_items_recursive(node, parent, theme) -> void:
func _create_items_recursive(node: Node, parent: TreeItem, editor_theme: Theme) -> void:
if parent and not node.owner:
return # Hidden node.
var node_item = _tree.create_item(parent)
node_item.set_text(0, node.get_name())
node_item.set_meta("node", node)
node_item.set_icon(0, theme.get_icon(node.get_class(), "EditorIcons"))
var node_icon: Texture2D
var node_class := node.get_class()
if is_instance_valid(editor_theme):
if editor_theme.has_icon(node_class, "EditorIcons"):
node_icon = editor_theme.get_icon(node_class, "EditorIcons")
else:
node_icon = editor_theme.get_icon("Node", "EditorIcons")
node_item.set_icon(0, node_icon)
for child in node.get_children():
_create_items_recursive(child, node_item, theme)
_create_items_recursive(child, node_item, editor_theme)
func _on_select_button_pressed() -> void:

View file

@ -73,6 +73,7 @@ func _validate_stack_connections() -> void:
if _modifier_stack.just_created:
%Presets.load_default(_scatter)
_modifier_stack.just_created = false
rebuild_ui()
func _set_children_owner(new_owner: Node, node: Node):

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends Node3D
@ -62,10 +62,10 @@ func _physics_process(delta: float) -> void:
var altitude = _system.get_water_altitude(global_transform.origin)
if altitude < 0.0:
var flow = _system.get_water_flow(global_transform.origin)
_rb.add_central_force(Vector3.UP * buoyancy_force * -altitude)
_rb.apply_central_force(Vector3.UP * buoyancy_force * -altitude)
var rot = _get_rotation_correction()
_rb.add_torque(rot * up_correcting_force)
_rb.add_central_force(flow * flow_force)
_rb.apply_torque(rot * up_correcting_force)
_rb.apply_central_force(flow * flow_force)
_rb.linear_damp = water_resistance
_rb.angular_damp = water_resistance
else:

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
extends EditorProperty

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends SubViewport

View file

@ -2,17 +2,18 @@
[ext_resource type="Script" path="res://addons/waterways/filter_renderer.gd" id="1"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_8d4jc"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_wr5gn"]
[node name="Renderer" type="SubViewport"]
own_world_3d = true
transparent_bg = true
use_hdr_2d = true
gui_disable_input = true
size = Vector2i(256, 256)
render_target_update_mode = 1
script = ExtResource("1")
[node name="ColorRect" type="ColorRect" parent="."]
material = SubResource("ShaderMaterial_8d4jc")
material = SubResource("ShaderMaterial_wr5gn")
offset_right = 256.0
offset_bottom = 256.0

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends HBoxContainer

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends Window

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends HBoxContainer

View file

@ -1,10 +1,10 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
extends EditorNode3DGizmoPlugin
const RiverManager = preload("./river_manager.gd")
const RiverControls = preload("./gui/river_controls.gd")
const RiverManager = preload("./../river_manager.gd")
const RiverControls = preload("./river_controls.gd")
const HANDLES_PER_POINT = 5
const AXIS_CONSTRAINT_LENGTH = 4096
const AXIS_MAPPING := {
@ -71,22 +71,18 @@ func _init() -> void:
add_material("handle_lines", mat)
func _get_gizmo_name():
return "Waterways"
func reset() -> void:
_handle_base_transform = null
func get_name() -> String:
func _get_gizmo_name() -> String:
return "RiverInput"
func _has_gizmo(spatial) -> bool:
return spatial is RiverManager
func _has_gizmo(node_3d) -> bool:
return node_3d is RiverManager
# TODO - figure out of this new "secondary" bool should be used
# TODO - figure out how this new "secondary" bool should be used
func _get_handle_name(gizmo: EditorNode3DGizmo, index: int, secondary: bool) -> String:
return "Handle " + str(index)
@ -180,7 +176,7 @@ func _get_handle_value(gizmo: EditorNode3DGizmo, index: int, secondary: bool):
# Called when handle is moved
# TODO - figure out of this new "secondary" bool should be used
# TODO - figure out how this new "secondary" bool should be used
func _set_handle(gizmo: EditorNode3DGizmo, index: int, secondary: bool, camera: Camera3D, point: Vector2) -> void:
var river : RiverManager = gizmo.get_node_3d()
var space_state = river.get_world_3d().direct_space_state
@ -263,8 +259,8 @@ func _set_handle(gizmo: EditorNode3DGizmo, index: int, secondary: bool, camera:
if editor_plugin.local_editing:
normal = _handle_base_transform.basis * (normal)
var projected : Vector3 = old_pos_global.project(normal)
var direction : Vector3 = sign(projected.dot(normal))
var distance : Vector3 = direction * projected.length()
var direction : float = signf(projected.dot(normal))
var distance : float = direction * projected.length()
var plane := Plane(normal, distance)
new_pos = plane.intersects_ray(ray_from, ray_dir)
@ -289,6 +285,7 @@ func _set_handle(gizmo: EditorNode3DGizmo, index: int, secondary: bool, camera:
# Widths handles
if is_width_left or is_width_right:
print("is width left or right")
var p1 = base
var p2
if is_width_left:
@ -302,10 +299,12 @@ func _set_handle(gizmo: EditorNode3DGizmo, index: int, secondary: bool, camera:
var dir = geo_points[0].distance_to(base) - old_pos.distance_to(base)
river.widths[p_index] += dir
# Ensure width handles don't end up inside the center point
river.widths[p_index] = max(river.widths[p_index], MIN_DIST_TO_CENTER_HANDLE)
# ensures that setter get's called so river regenerates - TODO probably find a nicer way of doing this
river.widths = river.widths
_redraw(gizmo)
# Handle Undo / Redo of handle movements
@ -358,12 +357,12 @@ func _redraw(gizmo: EditorNode3DGizmo) -> void:
if not _handle_lines_mat:
_handle_lines_mat = get_material("handle_lines", gizmo)
gizmo.clear()
var river := gizmo.get_node_3d() as RiverManager
if not river.is_connected("river_changed", Callable(self, "_redraw")):
river.river_changed.connect(_redraw.bind(gizmo))
_draw_path(gizmo, river.curve)
_draw_handles(gizmo, river)

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends MenuButton

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends HBoxContainer

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=3 format=3 uid="uid://dub07tcwh54lt"]
[gd_scene load_steps=3 format=3 uid="uid://b7sb78as2wbok"]
[ext_resource type="Script" path="res://addons/waterways/gui/water_system_controls.gd" id="1"]
[ext_resource type="Script" path="res://addons/waterways/gui/water_system_menu.gd" id="2"]

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends MenuButton

View file

@ -0,0 +1,97 @@
extends EditorNode3DGizmoPlugin
const WaterfallManager = preload("./../waterfall_manager.gd")
var editor_plugin : EditorPlugin
func _init() -> void:
create_handle_material("handles")
var handles_mat := get_material("handles")
handles_mat.set_albedo(Color(1.0, 0.0, 0.0, 1.0))
handles_mat.set_flag(StandardMaterial3D.FLAG_DISABLE_DEPTH_TEST, false)
# var mat = StandardMaterial3D.new()
# mat.shading_mode = StandardMaterial3D.SHADING_MODE_UNSHADED
# mat.set_flag(StandardMaterial3D.FLAG_DISABLE_DEPTH_TEST, true)
# mat.set_albedo(Color(1.0, 1.0, 0.0))
# mat.render_priority = 10
# add_material("path", mat)
func _get_gizmo_name() -> String:
return "WaterfallInput"
func _has_gizmo(node_3d: Node3D) -> bool:
return node_3d is WaterfallManager
func _get_handle_name(gizmo: EditorNode3DGizmo, index: int, secondary: bool) -> String:
return "Handle " + str(index)
func _get_handle_value(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool):
var waterfall : WaterfallManager = gizmo.get_node_3d()
if handle_id == 0:
return waterfall.points[0]
if handle_id == 1:
return waterfall.points[1]
func _set_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, camera: Camera3D, screen_pos: Vector2) -> void:
var waterfall : WaterfallManager = gizmo.get_node_3d()
var global_transform : Transform3D = waterfall.transform
if waterfall.is_inside_tree():
global_transform = waterfall.get_global_transform()
var ray_from = camera.project_ray_origin(screen_pos)
var ray_dir = camera.project_ray_normal(screen_pos)
var old_pos : Vector3 = waterfall.get_points()[handle_id]
var old_pos_global : Vector3 = waterfall.to_global(old_pos)
var new_pos : Vector3
var plane = Plane(old_pos_global, old_pos_global + camera.transform.basis.x, old_pos_global + camera.transform.basis.y)
new_pos = plane.intersects_ray(ray_from, ray_dir)
var new_pos_local = waterfall.to_local(new_pos)
waterfall.set_point(handle_id, new_pos_local)
_redraw(gizmo)
func _commit_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, restore, cancel: bool) -> void:
var waterfall : WaterfallManager = gizmo.get_node_3d()
var ur := editor_plugin.get_undo_redo()
ur.create_action("Change Waterfall Shape")
if handle_id == 0:
ur.add_do_method(waterfall, "set_point", 0, waterfall.points[0])
ur.add_undo_method(waterfall, "set_point", 0, restore)
if handle_id == 1:
ur.add_do_method(waterfall, "set_point", 1, waterfall.points[1])
ur.add_undo_method(waterfall, "set_point", 1, restore)
ur.add_do_method(waterfall, "properties_changed")
ur.add_undo_method(waterfall, "properties_changed")
ur.commit_action()
func _redraw(gizmo: EditorNode3DGizmo) -> void:
gizmo.clear()
var waterfall := gizmo.get_node_3d() as WaterfallManager
var handles := PackedVector3Array()
handles.append(waterfall.points[0])
handles.append(waterfall.points[1])
gizmo.add_handles(handles, get_material("handles", gizmo), [])
if not waterfall.is_connected("waterfall_changed", Callable(self, "_redraw")):
waterfall.waterfall_changed.connect(_redraw.bind(gizmo))

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/buoyant.svg-ac69eb28a931579c132428200cb0835d.
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/create.svg-60b9f1716ebcb842a99e86316911f9a2.c
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/delete.svg-1b0c65778cb549f4dbd4d033751da946.c
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/river.svg-233e9c2c3b3e593909a8b0720e3d3ed5.ct
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/select.svg-76eee65280a05a4a0c6a5b26562361ea.c
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/system.svg-c22af9c26d0684bdbe9cafe3e334da94.c
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
extends EditorInspectorPlugin
@ -10,7 +10,7 @@ func _can_handle(object) -> bool:
return object is RiverManager
func _parse_property(object: Object, type: Variant.Type, name: String, hint: PropertyHint, hint_text: String, usage: int, wide: bool) -> bool:
func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags, wide: bool) -> bool:
if type == TYPE_PROJECTION and "color" in name:
var editor_property = _editor.new()
add_property_editor(name, editor_property)

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends EditorPlugin
@ -6,12 +6,16 @@ extends EditorPlugin
const WaterHelperMethods = preload("./water_helper_methods.gd")
const WaterSystem = preload("./water_system_manager.gd")
const RiverManager = preload("./river_manager.gd")
const RiverGizmo = preload("./river_gizmo.gd")
const WaterfallManager = preload("./waterfall_manager.gd")
const WaterfallConfiguration = preload("./waterfall_configuration.gd")
const RiverGizmo = preload("./gui/river_gizmo.gd")
const WaterfallGizmo = preload("./gui/waterfall_gizmo.gd")
const InspectorPlugin = preload("./inspector_plugin.gd")
const ProgressWindow = preload("./gui/progress_window.tscn")
const RiverControls = preload("./gui/river_controls.gd")
var river_gizmo: RiverGizmo = RiverGizmo.new()
var waterfall_gizmo: WaterfallGizmo = WaterfallGizmo.new()
var gradient_inspector: InspectorPlugin = InspectorPlugin.new()
var _river_controls = preload("./gui/river_controls.tscn").instantiate()
@ -26,12 +30,16 @@ var local_editing := false
func _enter_tree() -> void:
add_custom_type("River", "Node3D", preload("./river_manager.gd"), preload("./icons/river.svg"))
add_custom_type("River", "Node3D",RiverManager, preload("./icons/river.svg"))
add_custom_type("Waterfall", "Node3D", WaterfallManager, preload("./icons/river.svg"))
add_custom_type("WaterfallConfiguration", "Resource", WaterfallConfiguration, preload("./icons/river.svg"))
add_custom_type("WaterSystem", "Node3D", preload("./water_system_manager.gd"), preload("./icons/system.svg"))
add_custom_type("Buoyant", "Node3D", preload("./buoyant_manager.gd"), preload("./icons/buoyant.svg"))
add_node_3d_gizmo_plugin(river_gizmo)
add_node_3d_gizmo_plugin(waterfall_gizmo)
add_inspector_plugin(gradient_inspector)
river_gizmo.editor_plugin = self
waterfall_gizmo.editor_plugin = self
_river_controls.connect("mode", Callable(self, "_on_mode_change"))
_river_controls.connect("options", Callable(self, "_on_option_change"))
_progress_window = ProgressWindow.instantiate()
@ -60,9 +68,12 @@ func _on_generate_system_maps_pressed() -> void:
func _exit_tree() -> void:
remove_custom_type("River")
remove_custom_type("Water System")
remove_custom_type("Waterfall")
remove_custom_type("WaterfallConfiguration")
remove_custom_type("WaterSystem")
remove_custom_type("Buoyant")
remove_node_3d_gizmo_plugin(river_gizmo)
remove_node_3d_gizmo_plugin(waterfall_gizmo)
remove_inspector_plugin(gradient_inspector)
_river_controls.disconnect("mode", Callable(self, "_on_mode_change"))
_river_controls.disconnect("options", Callable(self, "_on_option_change"))
@ -74,9 +85,10 @@ func _exit_tree() -> void:
func _handles(node):
return node is RiverManager or node is WaterSystem
return node is RiverManager or node is WaterfallManager or node is WaterSystem
# TODO - I think this was commented out for 4.0 conversion and isn't needed anymore
#func _edit(node):
# print("edit(), node is: ", node)
# if node is RiverManager:
@ -88,11 +100,12 @@ func _handles(node):
func _on_selection_change() -> void:
_editor_selection = get_editor_interface().get_selection()
#print("_on_selection_change(), Selection: ", _editor_selection)
var selected = _editor_selection.get_selected_nodes()
_hide_water_system_control_panel()
_hide_river_control_panel()
if len(selected) == 0:
return
if selected[0] is RiverManager:
@ -101,22 +114,16 @@ func _on_selection_change() -> void:
_river_controls.menu.debug_view_menu_selected = _edited_node.debug_view
if not _edited_node.is_connected("progress_notified", Callable(self, "_river_progress_notified")):
_edited_node.connect("progress_notified", Callable(self, "_river_progress_notified"))
_hide_water_system_control_panel()
elif selected[0] is WaterfallManager:
_edited_node = selected[0] as WaterfallManager
elif selected[0] is WaterSystem:
# TODO - is there anything we need to add here?
_show_water_system_control_panel()
_edited_node = selected[0] as WaterSystem
_hide_river_control_panel()
else:
print("_edited_node set to null")
_edited_node = null
_hide_river_control_panel()
_hide_water_system_control_panel()
func _on_scene_changed(scene_root) -> void:
# TODO - Hmmm
# print(scene_root)
_hide_river_control_panel()
_hide_water_system_control_panel()
@ -134,28 +141,38 @@ func _on_option_change(option, value) -> void:
if option == "constraint":
constraint = value
if constraint == RiverControls.CONSTRAINTS.COLLIDERS:
WaterHelperMethods.reset_all_colliders(_edited_node.get_tree().root)
# WaterHelperMethods.reset_all_colliders(_edited_node.get_tree().root)
# TODO - figure out if this is needed any more
pass
elif option == "local_mode":
local_editing = value
func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int:
if not _edited_node:
# TODO - This should be updated to the enum when it's fixed https://github.com/godotengine/godot/pull/64465
return 0
return AFTER_GUI_INPUT_PASS
if _edited_node is RiverManager:
return _forward_3d_gui_input_river(camera, event)
elif _edited_node is WaterfallManager:
return AFTER_GUI_INPUT_PASS
return AFTER_GUI_INPUT_PASS
func _forward_3d_gui_input_river(camera: Camera3D, event: InputEvent) -> int:
var global_transform: Transform3D = _edited_node.transform
if _edited_node.is_inside_tree():
global_transform = _edited_node.get_global_transform()
var global_inverse: Transform3D = global_transform.affine_inverse()
if (event is InputEventMouseButton) and (event.button_index == MOUSE_BUTTON_LEFT):
var ray_from = camera.project_ray_origin(event.position)
var ray_dir = camera.project_ray_normal(event.position)
var g1 = global_inverse * (ray_from)
var g2 = global_inverse * (ray_from + ray_dir * 4096)
# Iterate through points to find closest segment
var curve_points = _edited_node.get_curve_points()
var closest_distance = 4096.0
@ -197,7 +214,7 @@ func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int:
if _mode == "select":
if not event.pressed:
river_gizmo.reset()
return 0
return AFTER_GUI_INPUT_PASS
if _mode == "add" and not event.pressed:
# if we don't have a point on the line, we'll calculate a point
# based of a plane of the last point of the curve
@ -217,11 +234,12 @@ func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int:
var new_pos
if constraint == RiverControls.CONSTRAINTS.COLLIDERS:
var space_state = _edited_node.get_world_3d().direct_space_state
var result = space_state.intersect_ray(ray_from, ray_from + ray_dir * 4096)
var ray_params = PhysicsRayQueryParameters3D.create(ray_from, ray_from + ray_dir * 4096)
var result = space_state.intersect_ray(ray_params)
if result:
new_pos = result.position
else:
return 0
return AFTER_GUI_INPUT_PASS
elif constraint == RiverControls.CONSTRAINTS.NONE:
new_pos = plane.intersects_ray(ray_from, ray_from + ray_dir * 4096)
@ -240,8 +258,8 @@ func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int:
if local_editing:
normal = _handle_base_transform.basis * (normal)
var projected : Vector3 = end_pos_global.project(normal)
var direction : Vector3 = sign(projected.dot(normal))
var distance : Vector3 = direction * projected.length()
var direction : float = signf(projected.dot(normal))
var distance : float = direction * projected.length()
plane = Plane(normal, distance)
new_pos = plane.intersects_ray(ray_from, ray_dir)
@ -285,8 +303,7 @@ func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int:
ur.add_undo_property(_edited_node, "valid_flowmap", _edited_node.valid_flowmap)
ur.add_undo_method(_edited_node, "update_configuration_warnings")
ur.commit_action()
# TODO - This should be updated to the enum when it's fixed https://github.com/godotengine/godot/pull/64465
return 1
return AFTER_GUI_INPUT_STOP
elif _edited_node is RiverManager:
# Forward input to river controls. This is cleaner than handling
@ -296,9 +313,7 @@ func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int:
# method needs to be exposed.
# TODO - so this was returning a bool before? Check this
return _river_controls.spatial_gui_input(event)
# TODO - This should be updated to the enum when it's fixed https://github.com/godotengine/godot/pull/64465
return 0
return AFTER_GUI_INPUT_PASS
func _river_progress_notified(progress : float, message : String) -> void:

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends Node3D
@ -103,7 +103,7 @@ var baking_foam_blur : float = 0.02
# Public variables
var curve : Curve3D
var widths := [1.0, 1.0]: set = set_widths
var widths : Array[float] = [1.0, 1.0]: set = set_widths
var valid_flowmap := false
var debug_view : int = 0: set = set_debug_view
var mesh_instance : MeshInstance3D
@ -332,9 +332,6 @@ func _get_property_list() -> Array:
]
var combined_props = props + props2 + props3
# TODO, remember to remove this
# print(var2str(combined_props))
return combined_props
@ -348,37 +345,32 @@ func _set(property: StringName, value) -> bool:
func _get(property : StringName):
#print("in _get(), property: ", property)
if str(property).begins_with("mat_"):
var param_name = str(property).replace("mat_", "")
#print("property name in _get is: ", property)
#print("param name in _get is: ", param_name)
#print ("_material.get_shader_parameter(param_name): ", _material.get_shader_parameter(param_name))
return _material.get_shader_parameter(param_name)
# TODO - This doesn't currently work in Godot 4. https://github.com/godotengine/godot/issues/69335
#func _property_can_revert(property : StringName) -> bool:
# if str(property).begins_with("mat_"):
## if "color" in property:
## # TODO - we are disabling revert for color parameters due to this
## # bug: https://github.com/godotengine/godot/issues/45388
## return false
# var param_name = str(property).replace("mat_", "")
# return _material._property_can_revert(str("shader_param/", param_name))
#
# if not DEFAULT_PARAMETERS.has(property):
# return false
# if get(property) != DEFAULT_PARAMETERS[property]:
# return true
# return false
#
#
#func _property_get_revert(property : StringName):
# if str(property).begins_with("mat_"):
# var param_name = str(property).replace("mat_", "")
# var revert_value = _material._property_get_revert(str("shader_param/", param_name))
# return revert_value
func _property_can_revert(property : StringName) -> bool:
if str(property).begins_with("mat_"):
# if "color" in property:
# # TODO - we are disabling revert for color parameters due to this
# # bug: https://github.com/godotengine/godot/issues/45388
# return false
var param_name = str(property).replace("mat_", "")
return _material.property_can_revert(str("shader_param/", param_name))
if not DEFAULT_PARAMETERS.has(property):
return false
if get(property) != DEFAULT_PARAMETERS[property]:
return true
return false
func _property_get_revert(property : StringName):
if str(property).begins_with("mat_"):
var param_name = str(property).replace("mat_", "")
var revert_value = _material.property_get_revert(str("shader_param/", param_name))
return revert_value
func _init() -> void:
@ -443,12 +435,12 @@ func add_point(position : Vector3, index : int, dir : Vector3 = Vector3.ZERO, wi
if index == -1:
var last_index := curve.get_point_count() - 1
var dist = position.distance_to(curve.get_point_position(last_index))
var new_dir = dir if dir != Vector3.ZERO else (position - curve.get_point_position(last_index) - curve.get_point_out(last_index) ).normalized() * 0.25 * dist
var new_dir :Vector3 = dir if dir != Vector3.ZERO else (position - curve.get_point_position(last_index) - curve.get_point_out(last_index) ).normalized() * 0.25 * dist
curve.add_point(position, -new_dir, new_dir, -1)
widths.append(widths[widths.size() - 1]) # If this is a new point at the end, add a width that's the same as last
else:
var dist = curve.get_point_position(index).distance_to(curve.get_point_position(index + 1))
var new_dir = dir if dir != Vector3.ZERO else (curve.get_point_position(index + 1) - curve.get_point_position(index)).normalized() * 0.25 * dist
var new_dir : Vector3 = dir if dir != Vector3.ZERO else (curve.get_point_position(index + 1) - curve.get_point_position(index)).normalized() * 0.25 * dist
curve.add_point(position, -new_dir, new_dir, index + 1)
var new_width = width if width != 0.0 else (widths[index] + widths[index + 1]) / 2.0
widths.insert(index + 1, new_width) # We set the width to the average of the two surrounding widths
@ -472,6 +464,7 @@ func bake_texture() -> void:
func set_curve_point_position(index : int, position : Vector3) -> void:
print("set curve point position")
curve.set_point_position(index, position)
_generate_river()
@ -487,6 +480,7 @@ func set_curve_point_out(index : int, position : Vector3) -> void:
func set_widths(new_widths) -> void:
print("set widths")
widths = new_widths
if _first_enter_tree:
return
@ -626,7 +620,7 @@ func _generate_river() -> void:
func _generate_flowmap(flowmap_resolution : float) -> void:
WaterHelperMethods.reset_all_colliders(get_tree().root)
#WaterHelperMethods.reset_all_colliders(get_tree().root)
var image := Image.create(flowmap_resolution, flowmap_resolution, true, Image.FORMAT_RGB8)
image.fill(Color(0.0, 0.0, 0.0))

View file

@ -1,10 +1,8 @@
// Copyright © 2022 Kasper Arnklit Frandsen - MIT License
// Copyright © 2023 Kasper Arnklit Frandsen - MIT License
// See `LICENSE.md` included in the source distribution for details.
shader_type spatial;
render_mode depth_draw_always, cull_disabled;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
// If you are making your own shader, you can customize or add your own
// parameters below and they will automatically get parsed and displayed in
// the River inspector.

View file

@ -1,11 +1,8 @@
// Copyright © 2022 Kasper Arnklit Frandsen - MIT License
// Copyright © 2023 Kasper Arnklit Frandsen - MIT License
// See `LICENSE.md` included in the source distribution for details.
shader_type spatial;
render_mode depth_draw_always, specular_schlick_ggx, cull_disabled;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// If you are making your own shader, you can customize or add your own
// parameters below and they will automatically get parsed and displayed in
// the River inspector.
@ -55,6 +52,8 @@ uniform sampler2D i_distmap : hint_default_white;
uniform bool i_valid_flowmap = false;
uniform int i_uv2_sides = 2;
uniform sampler2D depth_texture : hint_depth_texture;
uniform sampler2D screen_texture : hint_screen_texture;
vec3 FlowUVW(vec2 uv_in, vec2 flowVector, vec2 jump, vec3 tiling, float time, bool flowB) {
float phaseOffset = flowB ? 0.5 : 0.0;
@ -183,7 +182,7 @@ void fragment() {
// We do two depth tests, one with the standard SCREEN_UV and one with the distorted
// refraction UVs. We do this to be able to dismiss refractions that are in front
// of objects
float depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;
float depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);
world_pos.xyz/=world_pos.w;
float water_depth = VERTEX.z - world_pos.z;
@ -205,7 +204,7 @@ void fragment() {
float ref_amount = 1.0 - clamp(clar_t + combined_foam, 0.0, 1.0);
// Depthtest 2
float refracted_depth_tex = textureLod(DEPTH_TEXTURE, ref_ofs, 0.0).r;
float refracted_depth_tex = textureLod(depth_texture, ref_ofs, 0.0).r;
vec4 refracted_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, refracted_depth_tex, 1.0);
refracted_world_pos.xyz /= refracted_world_pos.w;
float refracted_water_depth = VERTEX.z - refracted_world_pos.z;
@ -225,7 +224,7 @@ void fragment() {
vec3 alb_mix = mix(albedo_color_near.rgb, albedo_color_far.rgb, alb_t);
ALBEDO = mix(alb_mix, foam_color.rgb, combined_foam);
ALBEDO *= 1.0 - ref_amount;
EMISSION += textureLod(SCREEN_TEXTURE, ref_ofs, ROUGHNESS * water_depth).rgb * ref_amount;
EMISSION += textureLod(screen_texture, ref_ofs, ROUGHNESS * water_depth).rgb * ref_amount;
ALPHA = 1.0;
ALPHA *= clamp(1.0 - smoothstep(world_pos.z + edge_fade, world_pos.z, VERTEX.z), 0.0, 1.0);
}

View file

@ -1,4 +1,4 @@
// Copyright © 2022 Kasper Arnklit Frandsen - MIT License
// Copyright © 2023 Kasper Arnklit Frandsen - MIT License
// See `LICENSE.md` included in the source distribution for details.
shader_type spatial;

View file

@ -9,17 +9,42 @@ uniform float flow_distance : hint_range(0.0, 8.0) = 1.0;
uniform float flow_pressure : hint_range(0.0, 8.0) = 1.0;
uniform float flow_max : hint_range(0.0, 8.0) = 4.0;
uniform bool valid_flowmap = false;
uniform int uv2_sides = 2;
varying vec3 binormal_world;
// Converts a color from linear light gamma to sRGB gamma
vec4 fromLinear(vec4 linearRGB)
{
bvec4 cutoff = lessThan(linearRGB, vec4(0.0031308));
vec4 higher = vec4(1.055)*pow(linearRGB, vec4(1.0/2.4)) - vec4(0.055);
vec4 lower = linearRGB * vec4(12.92);
return mix(higher, lower, cutoff);
}
// Converts a color from sRGB gamma to linear light gamma
vec4 toLinear(vec4 sRGB)
{
bvec4 cutoff = lessThan(sRGB, vec4(0.04045));
vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));
vec4 lower = sRGB/vec4(12.92);
return mix(higher, lower, cutoff);
}
void vertex() {
binormal_world = (MODEL_MATRIX * vec4(BINORMAL, 0.0)).xyz;
}
void fragment() {
vec2 flow_foam_noise = textureLod(flowmap, UV2, 0.0).rg;
vec2 dist_pressure = textureLod(distmap, UV2, 0.0).xy;
vec2 custom_UV = (UV2 + 1.0 / float(uv2_sides)) * (float(uv2_sides) / float(uv2_sides + 2));
vec2 flow_foam_noise = textureLod(flowmap, custom_UV, 0.0).rg;
vec2 dist_pressure = textureLod(distmap, custom_UV, 0.0).xy;
vec2 flow;
float distance_map;
@ -49,5 +74,7 @@ void fragment() {
float sine = sin(rotation);
mat2 rotation_mat = mat2(vec2(cosine, -sine), vec2(sine, cosine));
vec2 new_flow = rotation_mat * flow;
new_flow = toLinear(vec4(new_flow, 0.0, 1.0)).rg;
ALBEDO = vec3((new_flow), 0.0) * 0.5 + 0.5; // repack flowmap
//ALBEDO = vec3(flow, 0.0);
}

View file

@ -5,11 +5,23 @@ uniform float lower_bounds = 0.0;
uniform float upper_bounds = 10.0;
varying vec3 vertex_trans;
// Converts a color from sRGB gamma to linear light gamma
vec4 toLinear(vec4 sRGB)
{
bvec4 cutoff = lessThan(sRGB, vec4(0.04045));
vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));
vec4 lower = sRGB/vec4(12.92);
return mix(higher, lower, cutoff);
}
void vertex() {
vertex_trans = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
void fragment() {
float range = upper_bounds - lower_bounds;
ALBEDO = vec3( clamp((vertex_trans.y - lower_bounds) / range, 0.0, 1.0) );
float height = clamp((vertex_trans.y - lower_bounds) / range, 0.0, 1.0);
//height = toLinear(vec4(vec3(height), 1.0)).r;
ALBEDO = vec3( height );
}

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends SubViewport
@ -7,7 +7,7 @@ const HEIGHT_SHADER_PATH = "res://addons/waterways/shaders/system_renders/system
const FLOW_SHADER_PATH = "res://addons/waterways/shaders/system_renders/system_flow.gdshader"
const ALPHA_SHADER_PATH = "res://addons/waterways/shaders/system_renders/alpha.gdshader"
const RiverManager = preload("./river_manager.gd")
var renderer = SubViewport
var _camera: Camera3D
var _container: Node3D
@ -48,8 +48,7 @@ func grab_height(water_objects: Array[RiverManager], aabb : AABB, resolution : f
await get_tree().process_frame
var height : Image = get_texture().get_image()
var height_result := ImageTexture.new()
height_result.create_from_image(height)
var height_result := ImageTexture.create_from_image(height)
for child in _container.get_children():
_container.remove_child(child)
@ -91,8 +90,7 @@ func grab_alpha(water_objects: Array[RiverManager], aabb: AABB, resolution: floa
await get_tree().process_frame
var alpha : Image = get_texture().get_image()
var alpha_result := ImageTexture.new()
alpha_result.create_from_image(alpha)
var alpha_result := ImageTexture.create_from_image(alpha)
for child in _container.get_children():
_container.remove_child(child)
@ -105,30 +103,32 @@ func grab_flow(water_objects: Array[RiverManager], aabb : AABB, resolution : flo
_camera = $Camera3D as Camera3D
_container = $Container as Node3D
var flow_mat := ShaderMaterial.new()
var flow_shader := load(FLOW_SHADER_PATH) as Shader
flow_mat.shader = flow_shader
for i in water_objects.size():
var flow_mat := ShaderMaterial.new()
var flow_shader := load(FLOW_SHADER_PATH) as Shader
flow_mat.shader = flow_shader
flow_mat.set_shader_parameter("flowmap", water_objects[i].flow_foam_noise)
flow_mat.set_shader_parameter("distmap", water_objects[i].dist_pressure)
flow_mat.set_shader_parameter("flow_base", water_objects[i].get_shader_parameter("flow_base"))
flow_mat.set_shader_parameter("flow_steepness", water_objects[i].get_shader_parameter("flow_steepness"))
flow_mat.set_shader_parameter("flow_distance", water_objects[i].get_shader_parameter("flow_distance"))
flow_mat.set_shader_parameter("flow_pressure", water_objects[i].get_shader_parameter("flow_pressure"))
flow_mat.set_shader_parameter("flow_max", water_objects[i].get_shader_parameter("flow_max"))
flow_mat.set_shader_parameter("valid_flowmap", water_objects[i].get_shader_parameter("i_valid_flowmap"))
flow_mat.set_shader_parameter("uv2_sides", water_objects[i].get_shader_parameter("i_uv2_sides"))
var water_mesh_copy := water_objects[i].mesh_instance.duplicate(true)
_container.add_child(water_mesh_copy)
water_mesh_copy.transform = water_objects[i].transform
water_mesh_copy.material_override = flow_mat
water_mesh_copy.material_override.set_shader_parameter("flowmap", water_objects[i].flow_foam_noise)
water_mesh_copy.material_override.set_shader_parameter("distmap", water_objects[i].dist_pressure)
water_mesh_copy.material_override.set_shader_parameter("flow_base", water_objects[i].get_shader_parameter("flow_base"))
water_mesh_copy.material_override.set_shader_parameter("flow_steepness", water_objects[i].get_shader_parameter("flow_steepness"))
water_mesh_copy.material_override.set_shader_parameter("flow_distance", water_objects[i].get_shader_parameter("flow_distance"))
water_mesh_copy.material_override.set_shader_parameter("flow_pressure", water_objects[i].get_shader_parameter("flow_pressure"))
water_mesh_copy.material_override.set_shader_parameter("flow_max", water_objects[i].get_shader_parameter("flow_max"))
water_mesh_copy.material_override.set_shader_parameter("valid_flowmap", water_objects[i].get_shader_parameter("i_valid_flowmap"))
var longest_axis := aabb.get_longest_axis_index()
match longest_axis:
Vector3.AXIS_X:
_camera.position = aabb.position + Vector3(aabb.size.x / 2.0, aabb.size.y + 1.0, aabb.size.x / 2.0)
Vector3.AXIS_Y:
# This shouldn't happen, we might need some code to handle if it does
# This shouldn't happen, we might need some code to handle if it does - TODO
pass
Vector3.AXIS_Z:
_camera.position = aabb.position + Vector3(aabb.size.z / 2.0, aabb.size.y + 1.0, aabb.size.z / 2.0)
@ -142,8 +142,7 @@ func grab_flow(water_objects: Array[RiverManager], aabb : AABB, resolution : flo
await get_tree().process_frame
var flow : Image = get_texture().get_image()
var flow_result := ImageTexture.new()
flow_result.create_from_image(flow)
var flow_result := ImageTexture.create_from_image(flow)
for child in _container.get_children():
_container.remove_child(child)

View file

@ -3,8 +3,10 @@
[ext_resource type="Script" path="res://addons/waterways/system_map_renderer.gd" id="1"]
[node name="SystemMatRenderer" type="SubViewport"]
own_world_3d = true
transparent_bg = true
debug_draw = 1
use_hdr_2d = true
gui_disable_input = true
render_target_update_mode = 1
script = ExtResource("1")

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/flow_offset_noise.png-f3f9e08ae624dc7c49a4bff
[params]
compress/mode=1
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=2
compress/channel_pack=0
mipmaps/generate=true

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/lava_normal_bump.png-7ae873772cb659577ce76e96
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=2
compress/channel_pack=0
mipmaps/generate=true

View file

@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/water1_normal_bump.png-1e68aa6d8e854a1982405b
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=2
compress/channel_pack=0
mipmaps/generate=true

View file

@ -1,4 +1,4 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
#const RiverManager = preload("./river_manager.gd")
@ -25,16 +25,8 @@ static func bary2cart(a : Vector3, b : Vector3, c: Vector3, barycentric: Vector3
static func point_in_bariatric(v : Vector3) -> bool:
return 0 <= v.x and v.x <= 1 and 0 <= v.y and v.y <= 1 and 0 <= v.z and v.z <= 1;
static func reset_all_colliders(node):
for n in node.get_children():
if n.get_child_count() > 0:
reset_all_colliders(n)
if n is CollisionShape3D:
if n.disabled == false:
n.disabled = true
n.disabled = false
static func sum_array(array : Array) -> float:
static func sum_array(array : Array[float]) -> float:
var sum := 0.0
for element in array:
sum += element
@ -48,7 +40,7 @@ static func calculate_side(steps : int) -> int:
return int(side_float)
static func generate_river_width_values(curve : Curve3D, steps : int, step_length_divs : int, step_width_divs : int, widths : Array) -> Array[float]:
static func generate_river_width_values(curve : Curve3D, steps : int, step_length_divs : int, step_width_divs : int, widths : Array[float]) -> Array[float]:
var river_width_values: Array[float]
var length := curve.get_baked_length()
for step in steps * step_length_divs + 1:
@ -158,8 +150,6 @@ static func generate_river_mesh(curve: Curve3D, steps: int, step_length_divs: in
static func generate_collisionmap(image: Image, mesh_instance: MeshInstance3D, raycast_dist: float, raycast_layers: int, steps: int, step_length_divs: int, step_width_divs: int, river) -> Image:
var space_state := mesh_instance.get_world_3d().direct_space_state
print("is the space state what we expect?")
print(space_state)
var uv2 := mesh_instance.mesh.surface_get_arrays(0)[5] as PackedVector2Array
var verts := mesh_instance.mesh.surface_get_arrays(0)[0] as PackedVector3Array
@ -175,13 +165,11 @@ static func generate_collisionmap(image: Image, mesh_instance: MeshInstance3D, r
river.emit_signal("progress_notified", percentage, "Calculating Collisions (" + str(image.get_width()) + "x" + str(image.get_width()) + ")")
await river.get_tree().process_frame
var ray_params := PhysicsRayQueryParameters3D.create(Vector3(0.0, 5.0, 0.0), Vector3(0.0, 0.0, 0.0))
#var ray_params := PhysicsRayQueryParameters3D.create(Vector3(0.0, 5.0, 0.0), Vector3(0.0, 0.0, 0.0), raycast_layers)
#ray_params_up.collision_mask = raycast_layers
var result = space_state.intersect_ray(ray_params)
#var result = space_state.intersect_ray(ray_params)
print("Single cast test!")
print(result)
print("done")
#print(result)
for x in image.get_width():
var cur_percentage := float(x) / float(image.get_width())
@ -227,23 +215,12 @@ static func generate_collisionmap(image: Image, mesh_instance: MeshInstance3D, r
var real_pos := bary2cart(vert0, vert1, vert2, baryatric_coords)
var real_pos_up := real_pos + Vector3.UP * raycast_dist
var ray_params_up := PhysicsRayQueryParameters3D.create(real_pos, real_pos_up)
#ray_params_up.collision_mask = raycast_layers
var ray_params_up := PhysicsRayQueryParameters3D.create(real_pos, real_pos_up, raycast_layers)
var result_up = space_state.intersect_ray(ray_params_up)
var ray_params_down := PhysicsRayQueryParameters3D.create(real_pos_up, real_pos)
#ray_params_down.collision_mask = raycast_layers
var ray_params_down := PhysicsRayQueryParameters3D.create(real_pos_up, real_pos, raycast_layers)
var result_down = space_state.intersect_ray(ray_params_down)
if (x == 32 and y == 32) or (x == 50 and y == 50):
print("real pos at x: ", x, ", y: ", y)
print(real_pos)
print(real_pos_up)
print("ray_params_down")
print(var_to_str(ray_params_down))
print(result_up)
print(result_down)
var up_hit_frontface := false
if result_up:
if result_up.normal.y < 0:
@ -251,7 +228,6 @@ static func generate_collisionmap(image: Image, mesh_instance: MeshInstance3D, r
if result_up or result_down:
if not up_hit_frontface and result_down:
# print("Does this ever happen") - Nope
image.set_pixel(x, y, Color(1.0, 1.0, 1.0))
return image

View file

@ -1,11 +1,11 @@
# Copyright © 2022 Kasper Arnklit Frandsen - MIT License
# Copyright © 2023 Kasper Arnklit Frandsen - MIT License
# See `LICENSE.md` included in the source distribution for details.
@tool
extends Node3D
const RiverManager = preload("./river_manager.gd")
const SystemMapRenderer = preload("./system_map_renderer.tscn")
const FilterRenderer = preload("./filter_renderer.tscn")
const RiverManager = preload("./river_manager.gd")
var system_map : ImageTexture = null: set = set_system_map
var system_bake_resolution := 2
@ -112,8 +112,9 @@ func generate_system_maps() -> void:
for river in rivers:
var river_aabb = river.get_transformed_aabb()
_system_aabb = _system_aabb.merge(river_aabb)
print(_system_aabb)
var renderer = SystemMapRenderer
var renderer = SystemMapRenderer.instantiate()
add_child(renderer)
var resolution := pow(2, system_bake_resolution + 7)
var flow_map: ImageTexture = await renderer.grab_flow(rivers, _system_aabb, resolution)

View file

@ -0,0 +1,26 @@
@tool
extends Resource
@export var width: float = 3.0:
set(value):
width = value
emit_changed()
print("width set in resource, right after emit changed is called")
@export var step_length_divs: int = 1:
set(value):
step_length_divs = value
emit_changed()
@export var step_width_divs: int = 1:
set(value):
step_width_divs = value
emit_changed()
#signal width_changed
#signal step_length_divs_changed
#signal step_width_divs_changed
func _init(p_width: float = 3.0, p_step_length_divs: int = 1, p_step_width_divs: int = 1) -> void:
# TODO - These don't seem to be filled in as expected?!? I had to fill the default values above instead
width = p_width
step_length_divs = p_step_length_divs
step_width_divs = p_step_width_divs

View file

@ -0,0 +1,141 @@
@tool
extends Node3D
const WaterfallConfiguration = preload("./waterfall_configuration.gd")
const WaterHelperMethods = preload("./water_helper_methods.gd")
const line_sample_resolution := 100
@export var configuration: WaterfallConfiguration:
set(value):
configuration = value
configuration.changed.connect(_configuration_changed)
print("configuration set function is called")
#@export var width := 3.0:
# set(value):
# width = value
# _generate_waterfall()
#@export var step_length_divs := 1:
# set(value):
# step_length_divs = value
# _generate_waterfall()
#@export var step_width_divs := 1:
# set(value):
# step_width_divs = value
# _generate_waterfall()
var points := PackedVector3Array([Vector3(0.0, 4.0, 0.0), Vector3(0.0, 0.0, 1.0)]):
set(value):
points = value
_generate_waterfall()
emit_signal("waterfall_changed")
var mesh_instance : MeshInstance3D
var _st : SurfaceTool
var _mdt : MeshDataTool
var _steps := 2
var _first_enter_tree = true
# TODO - connect this
signal waterfall_changed
func get_points() -> PackedVector3Array:
return points
func set_point(id: int, position: Vector3) -> void:
points[id] = position
_generate_waterfall()
emit_signal("waterfall_changed")
func _configuration_changed() -> void:
print("_configuration changed")
# TODO - I assume we can pass a parameter about whether a re-gen is needed
_generate_waterfall()
emit_signal("waterfall_changed")
func _enter_tree() -> void:
if Engine.is_editor_hint() and _first_enter_tree:
_first_enter_tree = false
if get_child_count() <= 0:
var new_mesh_instance := MeshInstance3D.new()
new_mesh_instance.name = "WaterfallMeshInstance"
add_child(new_mesh_instance)
mesh_instance = get_child(0) as MeshInstance3D
_generate_waterfall()
else:
mesh_instance = get_child(0) as MeshInstance3D
# TODO set material?
func _generate_waterfall() -> void:
# TODO - This spams "the target vector can't be zero", not sure which part, maybe cross product
var to_from: Vector3 = points[1] - points[0]
var to_from_2d = Vector3(to_from.x, 0.0, to_from.z)
var dist = to_from_2d.length()
var line_points := PackedVector3Array()
var curve := Curve3D.new()
for i in line_sample_resolution + 1:
var val = float(i) / float(line_sample_resolution)
var position = points[0] + to_from_2d * val + Vector3(0.0, ease_back_in(val) * to_from.y, 0.0)
curve.add_point(position)
line_points.append(position)
var curve_length := curve.get_baked_length()
_steps = int( max(1.0, round(curve_length / configuration.width)))
_st = SurfaceTool.new()
_st.begin(Mesh.PRIMITIVE_TRIANGLES)
_st.set_smooth_group(0)
# Generating the verts
for step in _steps * configuration.step_length_divs + 1:
var position := curve.sample_baked(float(step) / float(_steps * configuration.step_length_divs) * curve_length, false)
var backward_pos := curve.sample_baked((float(step) - 0.05) / float(_steps * configuration.step_length_divs) * curve_length, false)
var forward_pos := curve.sample_baked((float(step) + 0.05) / float(_steps *configuration. step_length_divs) * curve_length, false)
var forward_vector := forward_pos - backward_pos
var right_vector := forward_vector.cross(Vector3.UP).normalized()
for w_sub in configuration.step_width_divs + 1:
_st.set_uv(Vector2(float(w_sub) / (float(configuration.step_width_divs)), float(step) / float(configuration.step_length_divs) ))
_st.add_vertex(position + right_vector * configuration.width - 2.0 * right_vector * configuration.width * float(w_sub) / (float(configuration.step_width_divs)))
# Defining the tris
for step in _steps * configuration.step_length_divs:
for w_sub in configuration.step_width_divs:
_st.add_index( (step * (configuration.step_width_divs + 1)) + w_sub)
_st.add_index( (step * (configuration.step_width_divs + 1)) + w_sub + 1)
_st.add_index( (step * (configuration.step_width_divs + 1)) + w_sub + 2 + configuration.step_width_divs - 1)
_st.add_index( (step * (configuration.step_width_divs + 1)) + w_sub + 1)
_st.add_index( (step * (configuration.step_width_divs + 1)) + w_sub + 3 + configuration.step_width_divs - 1)
_st.add_index( (step * (configuration.step_width_divs + 1)) + w_sub + 2 + configuration.step_width_divs - 1)
_st.generate_normals()
_st.generate_tangents()
_st.deindex()
var mesh := ArrayMesh.new()
mesh = _st.commit()
mesh_instance.mesh = mesh
func ease_back_in(x: float) -> float:
var c1 = 1.70158
var c3 = c1 + 1
return c3 * x * x * x - c1 * x * x
# Signal Methods
func properties_changed() -> void:
emit_signal("waterfall_changed")

View file

@ -154,7 +154,7 @@ signal transform_changed(global_transform)
@export_range(2, 5) var lod_scale := 2.0:
get:
return lod_scale
return _lodder.get_split_scale()
set(value):
_lodder.set_split_scale(value)
@ -678,7 +678,8 @@ func get_internal_transform_unscaled():
var gt := global_transform
if centered and _data != null:
var half_size := 0.5 * (_data.get_resolution() - 1.0)
gt.origin += gt.basis * (-Vector3(half_size, 0, half_size))
# Map scale still has an effect on origin when the map is centered
gt.origin += gt.basis * (-Vector3(half_size, 0, half_size) * map_scale)
return gt
@ -1279,7 +1280,7 @@ func _process(delta: float):
var u: HT_PendingChunkUpdate = _pending_chunk_updates[i]
var chunk := _get_chunk_at(u.pos_x, u.pos_y, u.lod)
assert(chunk != null)
_update_chunk(chunk, u.lod, lvisible)
_update_chunk(chunk, u.lod, lvisible and chunk.is_active())
_updated_chunks += 1
_pending_chunk_updates.clear()

View file

@ -163,12 +163,12 @@ const _API_SHADER_PARAMS = {
var _material: ShaderMaterial = null
var _default_shader: Shader = null
# Vector2 => DirectMultiMeshInstance
# Vector2 => HT_DirectMultiMeshInstance
var _chunks := {}
var _multimesh: MultiMesh
var _multimesh_need_regen = true
var _multimesh_instance_pool := []
var _multimesh_instance_pool : Array[HT_DirectMultiMeshInstance] = []
var _ambient_wind_time := 0.0
#var _auto_pick_index_on_enter_tree := Engine.is_editor_hint()
var _debug_wirecube_mesh: Mesh = null
@ -355,7 +355,7 @@ func get_render_layer_mask() -> int:
func _get_used_mesh() -> Mesh:
if instance_mesh == null:
var mesh = load(DEFAULT_MESH_PATH) as Mesh
var mesh := load(DEFAULT_MESH_PATH) as Mesh
if mesh == null:
_logger.error(str("Failed to load default mesh: ", DEFAULT_MESH_PATH))
return mesh
@ -400,13 +400,13 @@ func _notification(what: int):
func _set_visible(v: bool):
for k in _chunks:
var chunk = _chunks[k]
var chunk : HT_DirectMultiMeshInstance = _chunks[k]
chunk.set_visible(v)
func _set_world(w: World3D):
for k in _chunks:
var chunk = _chunks[k]
var chunk : HT_DirectMultiMeshInstance = _chunks[k]
chunk.set_world(w)
@ -418,12 +418,12 @@ func _on_terrain_transform_changed(gt: Transform3D):
_logger.error("Detail layer is not child of a terrain!")
return
var terrain_transform : Transform3D = terrain.get_internal_transform()
var terrain_transform : Transform3D = terrain.get_internal_transform_unscaled()
# Update AABBs and transforms, because scale might have changed
for k in _chunks:
var mmi = _chunks[k]
var aabb = _get_chunk_aabb(terrain, Vector3(k.x * CHUNK_SIZE, 0, k.y * CHUNK_SIZE))
var mmi : HT_DirectMultiMeshInstance = _chunks[k]
var aabb := _get_chunk_aabb(terrain, Vector3(k.x * CHUNK_SIZE, 0, k.y * CHUNK_SIZE))
# Nullify XZ translation because that's done by transform already
aabb.position.x = 0
aabb.position.z = 0
@ -443,7 +443,7 @@ func process(delta: float, viewer_pos: Vector3):
# Crash workaround for Godot 3.1
# See https://github.com/godotengine/godot/issues/32500
for k in _chunks:
var mmi = _chunks[k]
var mmi : HT_DirectMultiMeshInstance = _chunks[k]
mmi.set_multimesh(_multimesh)
# Detail layers are unaffected by ground map_scale
@ -451,53 +451,58 @@ func process(delta: float, viewer_pos: Vector3):
terrain.get_internal_transform_unscaled()
var local_viewer_pos := terrain_transform_without_map_scale.affine_inverse() * viewer_pos
var viewer_cx = local_viewer_pos.x / CHUNK_SIZE
var viewer_cz = local_viewer_pos.z / CHUNK_SIZE
var viewer_cx := int(local_viewer_pos.x / CHUNK_SIZE)
var viewer_cz := int(local_viewer_pos.z / CHUNK_SIZE)
var cr = int(view_distance) / CHUNK_SIZE + 1
var cr := int(view_distance) / CHUNK_SIZE + 1
var cmin_x = viewer_cx - cr
var cmin_z = viewer_cz - cr
var cmax_x = viewer_cx + cr
var cmax_z = viewer_cz + cr
var cmin_x := viewer_cx - cr
var cmin_z := viewer_cz - cr
var cmax_x := viewer_cx + cr
var cmax_z := viewer_cz + cr
var map_res = terrain.get_data().get_resolution()
var map_scale = terrain.map_scale
var terrain_data : HTerrainData = terrain.get_data()
var map_res := terrain_data.get_resolution()
var map_scale : Vector3 = terrain.map_scale
var terrain_size_x = map_res * map_scale.x
var terrain_size_z = map_res * map_scale.z
var terrain_size_x := map_res * map_scale.x
var terrain_size_z := map_res * map_scale.z
var terrain_chunks_x = terrain_size_x / CHUNK_SIZE
var terrain_chunks_z = terrain_size_z / CHUNK_SIZE
var terrain_chunks_x := terrain_size_x / CHUNK_SIZE
var terrain_chunks_z := terrain_size_z / CHUNK_SIZE
cmin_x = clampi(cmin_x, 0, terrain_chunks_x)
cmin_z = clampi(cmin_z, 0, terrain_chunks_z)
cmax_x = clampi(cmax_x, 0, terrain_chunks_x + 1)
cmax_z = clampi(cmax_z, 0, terrain_chunks_z + 1)
if DEBUG and visible:
_debug_cubes.clear()
for cz in range(cmin_z, cmax_z):
for cx in range(cmin_x, cmax_x):
_add_debug_cube(terrain, _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE))
_add_debug_cube(terrain, _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE),
terrain_transform_without_map_scale)
for cz in range(cmin_z, cmax_z):
for cx in range(cmin_x, cmax_x):
var cpos2d = Vector2(cx, cz)
var cpos2d := Vector2(cx, cz)
if _chunks.has(cpos2d):
continue
var aabb = _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE)
var d = (aabb.position + 0.5 * aabb.size).distance_to(local_viewer_pos)
var aabb := _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE)
var d := (aabb.position + 0.5 * aabb.size).distance_to(local_viewer_pos)
if d < view_distance:
_load_chunk(terrain_transform_without_map_scale, cx, cz, aabb)
var to_recycle = []
var to_recycle : Array[Vector2] = []
for k in _chunks:
var chunk = _chunks[k]
var aabb = _get_chunk_aabb(terrain, Vector3(k.x, 0, k.y) * CHUNK_SIZE)
var d = (aabb.position + 0.5 * aabb.size).distance_to(local_viewer_pos)
var aabb := _get_chunk_aabb(terrain, Vector3(k.x, 0, k.y) * CHUNK_SIZE)
var d := (aabb.position + 0.5 * aabb.size).distance_to(local_viewer_pos)
if d > view_distance:
to_recycle.append(k)
@ -514,7 +519,7 @@ func process(delta: float, viewer_pos: Vector3):
# Gets local-space AABB of a detail chunk.
# This only apply map_scale in Y, because details are not affected by X and Z map scale.
func _get_chunk_aabb(terrain, lpos: Vector3):
func _get_chunk_aabb(terrain, lpos: Vector3) -> AABB:
var terrain_scale = terrain.map_scale
var terrain_data = terrain.get_data()
var origin_cells_x := int(lpos.x / terrain_scale.x)
@ -543,7 +548,7 @@ func _load_chunk(terrain_transform_without_map_scale: Transform3D, cx: int, cz:
aabb.position.x = 0
aabb.position.z = 0
var mmi = null
var mmi : HT_DirectMultiMeshInstance = null
if len(_multimesh_instance_pool) != 0:
mmi = _multimesh_instance_pool[-1]
_multimesh_instance_pool.pop_back()
@ -565,14 +570,14 @@ func _load_chunk(terrain_transform_without_map_scale: Transform3D, cx: int, cz:
func _recycle_chunk(cpos2d: Vector2):
var mmi = _chunks[cpos2d]
var mmi : HT_DirectMultiMeshInstance = _chunks[cpos2d]
_chunks.erase(cpos2d)
mmi.set_visible(false)
_multimesh_instance_pool.append(mmi)
func _get_ambient_wind_params() -> Vector2:
var aw = 0.0
var aw := 0.0
var terrain = _get_terrain()
if terrain != null:
aw = terrain.ambient_wind
@ -584,13 +589,13 @@ func _update_material():
# Sets API shader properties. Custom properties are assumed to be set already
_logger.debug("Updating detail layer material")
var terrain_data = null
var terrain_data : HTerrainData = null
var terrain = _get_terrain()
var it = Transform3D()
var normal_basis = Basis()
var it := Transform3D()
var normal_basis := Basis()
if terrain != null:
var gt = terrain.get_internal_transform()
var gt : Transform3D = terrain.get_internal_transform()
it = gt.affine_inverse()
terrain_data = terrain.get_data()
# This is needed to properly transform normals if the terrain is scaled.
@ -598,7 +603,7 @@ func _update_material():
#normal_basis = gt.basis.inverse().transposed()
normal_basis = Basis().scaled(terrain.map_scale).inverse().transposed()
var mat = _material
var mat := _material
mat.set_shader_parameter("u_terrain_inverse_transform", it)
mat.set_shader_parameter("u_terrain_normal_basis", normal_basis)
@ -606,10 +611,10 @@ func _update_material():
mat.set_shader_parameter("u_view_distance", view_distance)
mat.set_shader_parameter("u_ambient_wind", _get_ambient_wind_params())
var heightmap_texture = null
var normalmap_texture = null
var detailmap_texture = null
var globalmap_texture = null
var heightmap_texture : Texture = null
var normalmap_texture : Texture = null
var detailmap_texture : Texture = null
var globalmap_texture : Texture = null
if terrain_data != null:
if terrain_data.is_locked():
@ -633,7 +638,7 @@ func _update_material():
mat.set_shader_parameter("u_terrain_globalmap", globalmap_texture)
func _add_debug_cube(terrain: Node3D, aabb: AABB):
func _add_debug_cube(terrain: Node3D, aabb: AABB, terrain_transform_without_scale: Transform3D):
var world : World3D = terrain.get_world_3d()
if _debug_wirecube_mesh == null:
@ -641,12 +646,16 @@ func _add_debug_cube(terrain: Node3D, aabb: AABB):
var mat := StandardMaterial3D.new()
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
_debug_wirecube_mesh.surface_set_material(0, mat)
# Flat terrain makes cubes invisible
aabb.size.y = maxf(aabb.size.y, 1.0)
var debug_cube := HT_DirectMeshInstance.new()
debug_cube.set_mesh(_debug_wirecube_mesh)
debug_cube.set_world(world)
#aabb.position.y += 0.2*randf()
debug_cube.set_transform(Transform3D(Basis().scaled(aabb.size), aabb.position))
debug_cube.set_transform(terrain_transform_without_scale \
* Transform3D(Basis().scaled(aabb.size), aabb.position))
_debug_cubes.append(debug_cube)

View file

@ -59,7 +59,13 @@ void vertex() {
v_map_uv = map_uv;
//float density = 0.5 + 0.5 * sin(4.0*TIME); // test
float density = texture(u_terrain_detailmap, map_uv).r;
float density = 0.0;
// Force density to be 0 outside of bounds. This can be necessary when terrain is scaled,
// as detail chunks will keep their size and may partially overlap outside bounds at the edges
// of the terrain.
if (map_uv.x >= 0.0 && map_uv.y >= 0.0 && map_uv.x < 1.0 && map_uv.y < 1.0) {
density = texture(u_terrain_detailmap, map_uv).r;
}
float hash = get_hash(obj_pos.xz);
if (density > hash) {

View file

@ -13,12 +13,12 @@ const HT_BrushSettingsDialog = preload("./settings_dialog/brush_settings_dialog.
@onready var _size_slider : Slider = $GridContainer/BrushSizeControl/Slider
@onready var _size_value_label : Label = $GridContainer/BrushSizeControl/Label
@onready var _size_spin_box : SpinBox = $GridContainer/BrushSizeControl/SpinBox
#onready var _size_label = _params_container.get_node("BrushSizeLabel")
@onready var _opacity_slider : Slider = $GridContainer/BrushOpacityControl/Slider
@onready var _opacity_value_label : Label = $GridContainer/BrushOpacityControl/Label
@onready var _opacity_control : Control = $GridContainer/BrushOpacityControl
@onready var _opacity_spin_box : SpinBox = $GridContainer/BrushOpacityControl/SpinBox
@onready var _opacity_label : Label = $GridContainer/BrushOpacityLabel
@onready var _flatten_height_container : Control = $GridContainer/HB
@ -58,7 +58,9 @@ func _set_visibility_of(node: Control, v: bool):
func _ready():
_size_slider.value_changed.connect(_on_size_slider_value_changed)
_size_slider.share(_size_spin_box)
_opacity_slider.value_changed.connect(_on_opacity_slider_value_changed)
_opacity_slider.share(_opacity_spin_box)
_flatten_height_box.value_changed.connect(_on_flatten_height_box_value_changed)
_color_picker.color_changed.connect(_on_color_picker_color_changed)
_density_slider.value_changed.connect(_on_density_slider_changed)
@ -190,13 +192,11 @@ func set_display_mode(mode: int):
func _on_size_slider_value_changed(v: float):
if _terrain_painter != null:
_terrain_painter.set_brush_size(int(v))
_size_value_label.text = str(v)
func _on_opacity_slider_value_changed(v: float):
if _terrain_painter != null:
_terrain_painter.set_opacity(_opacity_slider.ratio)
_opacity_value_label.text = str(v)
func _on_flatten_height_box_value_changed(v: float):

View file

@ -50,9 +50,11 @@ value = 2.0
exp_edit = true
rounded = true
[node name="Label" type="Label" parent="GridContainer/BrushSizeControl"]
[node name="SpinBox" type="SpinBox" parent="GridContainer/BrushSizeControl"]
layout_mode = 2
text = "999"
min_value = 2.0
max_value = 500.0
value = 2.0
[node name="BrushOpacityLabel" type="Label" parent="GridContainer"]
layout_mode = 2
@ -67,9 +69,9 @@ layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
[node name="Label" type="Label" parent="GridContainer/BrushOpacityControl"]
[node name="SpinBox" type="SpinBox" parent="GridContainer/BrushOpacityControl"]
layout_mode = 2
text = "999"
value = 1.0
[node name="FlattenHeightLabel" type="Label" parent="GridContainer"]
layout_mode = 2

View file

@ -97,6 +97,7 @@ size_flags_vertical = 3
[node name="Label3" type="Label" parent="Import/HS/VB2"]
modulate = Color(0.564706, 0.564706, 0.564706, 1)
custom_minimum_size = Vector2(400, 80)
layout_mode = 2
text = "These images should remain accessible for import to work.
Tip: you can place them in a folder with a `.gdignore` file, so they won't take space in your exported game."

File diff suppressed because one or more lines are too long