83 lines
3.1 KiB
GDScript3
83 lines
3.1 KiB
GDScript3
|
extends Node3D
|
||
|
class_name BuyancyProbe
|
||
|
|
||
|
## How much force is applied upward
|
||
|
@export var float_strenght: float = 10.0
|
||
|
|
||
|
@export_category("Debug")
|
||
|
@export var show_probe :bool = false
|
||
|
var sphere_preview:MeshInstance3D
|
||
|
@onready var debug_sphere:SphereMesh = SphereMesh.new()
|
||
|
|
||
|
@export_category("Wave")
|
||
|
# Wave parameters (should match the shader).
|
||
|
# For a single wave, we used these parameters.
|
||
|
@export var wave_amplitude: float = 1.0
|
||
|
@export var wave_length: float = 10.0
|
||
|
@export var wave_speed: float = 1.0
|
||
|
@export var wave_direction: Vector2 = Vector2(1.0, 0.0)
|
||
|
@export var wave:Vector4
|
||
|
@onready var ocean_mat: ShaderMaterial = preload("uid://wes0mbjy8mno").surface_get_material(0)
|
||
|
@onready var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||
|
@onready var OceanNode:Ocean = get_tree().get_first_node_in_group("Ocean")
|
||
|
# For multiple waves, define an array of waves.
|
||
|
@export var waves: Array[Vector4] = [
|
||
|
Vector4(1.0, 0.0, 0.5, 10.0),
|
||
|
Vector4(0.0, 1.0, 0.25, 20.0),
|
||
|
Vector4(1.0, 1.0, 0.15, 10.0)
|
||
|
]
|
||
|
|
||
|
# Called when the node enters the scene tree for the first time.
|
||
|
func _ready() -> void:
|
||
|
if ocean_mat != null:
|
||
|
wave = ocean_mat.get_shader_parameter("wave")
|
||
|
wave_speed = ocean_mat.get_shader_parameter("wave_speed")
|
||
|
|
||
|
if show_probe:
|
||
|
sphere_preview = MeshInstance3D.new()
|
||
|
sphere_preview.set_name("Sphere")
|
||
|
add_child(sphere_preview)
|
||
|
debug_sphere.radius = 0.1
|
||
|
debug_sphere.height = 0.2
|
||
|
sphere_preview.mesh = debug_sphere
|
||
|
|
||
|
|
||
|
var Oceantime:float
|
||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||
|
func _process(delta: float) -> void:
|
||
|
if OceanNode != null:
|
||
|
Oceantime = OceanNode.time
|
||
|
if show_probe && sphere_preview != null:
|
||
|
sphere_preview.global_position.y = get_gerstner_wave(global_position,wave,Oceantime).y
|
||
|
#print(get_gerstner_wave(global_position,wave,Oceantime).y)
|
||
|
|
||
|
# Calculate the wave height using a sine function.
|
||
|
func get_wave_height(position: Vector3, time: float) -> float:
|
||
|
var frequency = (2.0 * PI) / wave_length
|
||
|
var phase = frequency * (wave_direction.dot(Vector2(position.x, position.z))) + time * wave_speed
|
||
|
return wave_amplitude * sin(phase)
|
||
|
|
||
|
# Approximate the wave's normal based on the derivative of the wave function.
|
||
|
func get_wave_normal(position: Vector3, time: float) -> Vector3:
|
||
|
var frequency = (2.0 * PI) / wave_length
|
||
|
var phase = frequency * (wave_direction.dot(Vector2(global_position.x, global_position.z))) + time * wave_speed
|
||
|
var dHeight_dx = wave_amplitude * cos(phase) * frequency * wave_direction.x
|
||
|
var dHeight_dz = wave_amplitude * cos(phase) * frequency * wave_direction.y
|
||
|
var normal = Vector3(-dHeight_dx, 1.0, -dHeight_dz).normalized()
|
||
|
return normal
|
||
|
|
||
|
func get_gerstner_wave(p: Vector3, wave: Vector4, time: float) -> Vector3:
|
||
|
var steepness = wave.z
|
||
|
var wavelength = wave.w
|
||
|
var k = 2 * PI / wavelength
|
||
|
var c = sqrt(gravity / k) # Wave speed factor (gravity-based)
|
||
|
var d = Vector2(wave.x, wave.y).normalized()
|
||
|
var f = k * ( d.dot(Vector2(p.x, p.z)) - c * time * wave_speed )
|
||
|
var a = steepness / k
|
||
|
# Return the displacement vector.
|
||
|
return Vector3(
|
||
|
d.x * (a * cos(f)),
|
||
|
a * sin(f),
|
||
|
d.y * (a * cos(f))
|
||
|
)
|