mise a jour addons
This commit is contained in:
parent
9a36dd059c
commit
c27c38be13
51 changed files with 576 additions and 251 deletions
|
@ -1,3 +1,3 @@
|
|||
source_md5="d28fc1b4998adc3f0ef9aeebc3099059"
|
||||
dest_md5="9d25e863ac55fd1d3e430f85c32712f4"
|
||||
dest_md5="6ce83fd2912a369d4bda57c992027f33"
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
importer="glsl"
|
||||
type="RDShaderFile"
|
||||
uid="uid://p5gs3onqlpf2"
|
||||
uid="uid://dksrw0kl2yjtg"
|
||||
path="res://.godot/imported/compute_relax.glsl-b06f9e60cda7719b78bde9673f2501b7.res"
|
||||
|
||||
[deps]
|
||||
|
|
|
@ -154,6 +154,7 @@ 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()
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
@ -306,6 +303,8 @@ func _set_handle(gizmo: EditorNode3DGizmo, index: int, secondary: bool, camera:
|
|||
|
||||
# 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
97
addons/waterways/gui/waterfall_gizmo.gd
Normal file
97
addons/waterways/gui/waterfall_gizmo.gd
Normal 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))
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
26
addons/waterways/waterfall_configuration.gd
Normal file
26
addons/waterways/waterfall_configuration.gd
Normal 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
|
141
addons/waterways/waterfall_manager.gd
Normal file
141
addons/waterways/waterfall_manager.gd
Normal 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")
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
@ -642,11 +647,15 @@ func _add_debug_cube(terrain: Node3D, aabb: AABB):
|
|||
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)
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue