simvx.core.water

WaterSurface3D + WaterMaterial: a built-in animated water plane (design D16).

Water is a dedicated built-in render pass (its own GLSL + WGSL shader pair, like the tilemap / grid passes), NOT a ShaderMaterial. A :class:WaterSurface3D node places a horizontal grid whose vertices are displaced by a sum of Gerstner waves in the vertex stage (direction + strength taken from the FrameGlobals wind slot, phase from FrameGlobals time), and whose fragment stage refracts the scene behind it (sampling the scene-colour/depth copy), fades to a deep-water tint with depth, mixes a Fresnel reflection from the environment, and adds shore foam where the water meets geometry.

The appearance knobs live on the :class:WaterMaterial value object (mirrors FogMaterial / Material); geometry (extent + tessellation) lives on the node. The presence of any visible WaterSurface3D in the scene is what makes the desktop renderer split the opaque/transparent pass to produce the scene colour/depth copy the refraction reads; with no water surface the split never happens and the frame is byte-identical (zero-cost when unused).

Module Contents

Classes

WaterMaterial

Appearance of a :class:WaterSurface3D (a plain value object).

WaterSurface3D

A horizontal animated water plane rendered by the built-in water pass.

Data

API

simvx.core.water.__all__

[‘WaterMaterial’, ‘WaterSurface3D’]

class simvx.core.water.WaterMaterial(*, shallow_colour: tuple[float, float, float] = (0.1, 0.38, 0.42), deep_colour: tuple[float, float, float] = (0.02, 0.09, 0.16), depth_fade_distance: float = 3.0, wave_amplitude: float = 0.18, wave_steepness: float = 0.55, wave_length: float = 6.0, wave_direction: float = 0.6, direction_spread: float = 0.8, wave_speed: float = 1.0, normal_scroll_speed: float = 0.05, normal_strength: float = 0.5, foam_colour: tuple[float, float, float] = (0.9, 0.95, 1.0), foam_amount: float = 0.6, refraction_strength: float = 0.35, fresnel_power: float = 5.0, roughness: float = 0.04, opacity: float = 0.92)[source]

Appearance of a :class:WaterSurface3D (a plain value object).

Assign one to WaterSurface3D.material; the renderer reads these fields each frame. All colours are linear RGB. Wave direction and strength are modulated by the scene WorldEnvironment wind (FrameGlobals): with no wind the base direction/amplitude below drive the motion, so water animates out of the box.

Attributes: shallow_colour: Water tint over shallow geometry (RGB, near the shore). deep_colour: Water tint over deep geometry (RGB, far from the shore). depth_fade_distance: World distance over which shallow blends to deep and transparency ramps to opaque. wave_amplitude: Base peak height of the Gerstner sum, in world units. wave_steepness: Gerstner steepness 0..1 (0 rolling swell, 1 sharp crests). wave_length: Base wavelength of the longest Gerstner wave, world units. wave_direction: Base travel direction, radians in the XZ plane (used when the wind strength is ~0; otherwise wind direction leads). direction_spread: Angular fan of the four Gerstner components, radians. wave_speed: Multiplier on wave phase speed. normal_scroll_speed: Scroll rate of the two detail-ripple normal layers. normal_strength: Intensity of the detail ripples added to the wave normal. foam_colour: Shore-foam colour (RGB). foam_amount: Depth band (world units) over which shore foam appears. refraction_strength: Screen-space refraction offset scale (world units). fresnel_power: Fresnel exponent for the reflection/refraction blend. roughness: Surface roughness for the environment reflection sample. opacity: Overall surface opacity ceiling (deep water) 0..1.

Initialization

__slots__

(‘shallow_colour’, ‘deep_colour’, ‘depth_fade_distance’, ‘wave_amplitude’, ‘wave_steepness’, ‘wave_l…

__repr__() str[source]
class simvx.core.water.WaterSurface3D(material: simvx.core.water.WaterMaterial | None = None, reflection=None, **kwargs)[source]

Bases: simvx.core.nodes_3d.node3d.Node3D

A horizontal animated water plane rendered by the built-in water pass.

Place the node at the water level: its world XZ plane (local +Y up) is the still surface, extended to size world units and tessellated into subdivisions × subdivisions cells for the Gerstner displacement. The fragment stage refracts and depth-fades against the scene behind it, so put submerged geometry below the plane and a directional light + sky above.

Example::

water = WaterSurface3D(position=(0, 0, 0), size=(40, 40))
water.material = WaterMaterial(wave_amplitude=0.25)
scene.add_child(water)

Properties: size: Water plane extent in world units (x, z). subdivisions: Grid resolution per axis (higher = smoother crests). visible: Standard Node visibility; a hidden surface neither draws nor triggers the scene colour/depth copy.

Initialization

size

‘Property(…)’

subdivisions

‘Property(…)’

gizmo_colour

‘Property(…)’

property material: simvx.core.water.WaterMaterial[source]

The :class:WaterMaterial controlling this surface’s appearance.

property reflection[source]

Optional :class:PlanarReflection3D feeding a true planar mirror (RM-E2).

When set, the surface samples this node’s live capture as its reflection (a real mirror of the world above the water) instead of the environment cubemap, blended against the refraction below by Fresnel and rippled by the wave normal. The node must sit on the water plane (same world Y, its world +Y as the plane normal), exactly like a mirror floor; drop it in as a child and assign it here. None keeps the cubemap/sky reflection, so a surface with no reflection is byte-identical to the RM-E1 water.

get_gizmo_lines() list[tuple[simvx.core.math.types.Vec3, simvx.core.math.types.Vec3]][source]

Editor gizmo: the still-surface rectangle at the node’s world plane.

position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

render_layer

‘Property(…)’

property rotation_degrees: simvx.core.math.types.Vec3
property world_position: simvx.core.math.types.Vec3
property world_rotation: simvx.core.math.types.Quat
property world_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
face_along(forward: tuple[float, float, float] | numpy.ndarray, up: tuple[float, float, float] | numpy.ndarray | None = None) None
set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
strict_errors: ClassVar[bool]

True

script_error_raised

‘Signal(…)’

dynamic: bool

False

classmethod __init_subclass__(**kwargs)
property name: str
property update_mode: simvx.core.descriptors.UpdateMode
property visible: bool
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
get_node_or_none(path: str) simvx.core.node.Node | None
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
on_ready() None
on_enter_tree() None
on_exit_tree() None
on_update(dt: float) None
on_fixed_update(dt: float) None
on_draw(renderer) None
on_picked(event: simvx.core.events.InputEvent) None
on_unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
queue_redraw() None
property render_dirty: bool
clear_children()
destroy()
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None
property app
property tree: simvx.core.scene_tree.SceneTree
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
__repr__()