Water Surface.

An animated sea over a sloped sandy floor, with three pillars standing in the water and a half-sunk sphere forming an island.

▶ Run in browser

Tags: 3d water gerstner refraction transparent

WaterSurface3D is a built-in render pass, not a ShaderMaterial: place the node at the water level and give it a size (x, z) in world units. Its vertex stage displaces a grid by four Gerstner waves, and its fragment stage refracts whatever is below the surface, tints it from shallow_colour to deep_colour over depth_fade_distance, blends in a Fresnel reflection of the environment, and draws foam where the water column is thinner than foam_amount. The appearance lives on a WaterMaterial passed as the node’s material.

The waves follow the wind: WorldEnvironment.wind_direction sets their heading and wind_strength scales their height. With no wind the material’s own wave_direction and wave_amplitude drive them, so water moves out of the box.

Here the floor rises away from the camera into a beach, so the water is deep and dark in front and shoals to foam along the far shore; the pillars show the refraction wobble and depth tint, and the island shows foam curving around its shore. For a true mirror of the world above the surface, see planar_water.py.

Source

 1# /// simvx
 2# tags = ["3d", "water", "gerstner", "refraction", "transparent"]
 3# screenshot_frame = 40
 4# ///
 5"""Water Surface.
 6
 7An animated sea over a sloped sandy floor, with three pillars standing in the water and a
 8half-sunk sphere forming an island.
 9
10`WaterSurface3D` is a built-in render pass, not a `ShaderMaterial`: place the node at the water
11level and give it a `size` (x, z) in world units. Its vertex stage displaces a grid by four
12Gerstner waves, and its fragment stage refracts whatever is below the surface, tints it from
13`shallow_colour` to `deep_colour` over `depth_fade_distance`, blends in a Fresnel reflection of
14the environment, and draws foam where the water column is thinner than `foam_amount`. The
15appearance lives on a `WaterMaterial` passed as the node's `material`.
16
17The waves follow the wind: `WorldEnvironment.wind_direction` sets their heading and
18`wind_strength` scales their height. With no wind the material's own `wave_direction` and
19`wave_amplitude` drive them, so water moves out of the box.
20
21Here the floor rises away from the camera into a beach, so the water is deep and dark in front
22and shoals to foam along the far shore; the pillars show the refraction wobble and depth tint,
23and the island shows foam curving around its shore. For a true mirror of the world above the
24surface, see `planar_water.py`.
25"""
26
27from simvx.core import (
28    Camera3D,
29    DirectionalLight3D,
30    Material,
31    Mesh,
32    MeshInstance3D,
33    Node,
34    WaterMaterial,
35    WaterSurface3D,
36    WorldEnvironment,
37)
38from simvx.graphics import App
39
40PILLARS = [
41    ((-3.5, -0.8, -1.0), (0.85, 0.3, 0.3, 1.0)),
42    ((0.0, -0.8, -3.0), (0.3, 0.8, 0.45, 1.0)),
43    ((3.5, -0.8, -1.5), (0.35, 0.5, 0.9, 1.0)),
44]
45
46
47class WaterScene(Node):
48    def on_ready(self):
49        self.add_child(WorldEnvironment(wind_direction=(0.7, 0.7), wind_strength=0.6))
50        self.add_child(Camera3D(position=(0, 3.2, 11.0), look_at=(0, 0.2, 0)))
51        self.add_child(DirectionalLight3D(intensity=3.0, direction=(-0.5, -1.0, -0.4)))
52
53        sand = Material(colour=(0.72, 0.62, 0.42, 1.0), roughness=0.9)
54        floor = self.add_child(
55            MeshInstance3D(mesh=Mesh.box((30.0, 0.5, 26.0)), material=sand, position=(0, -2.2, -6.0))
56        )
57        floor.rotation_degrees = (16.0, 0.0, 0.0)
58
59        for position, colour in PILLARS:
60            pillar = Material(colour=colour, roughness=0.6)
61            self.add_child(MeshInstance3D(mesh=Mesh.box((0.9, 3.0, 0.9)), material=pillar, position=position))
62
63        rock = Material(colour=(0.6, 0.55, 0.4, 1.0), roughness=0.85)
64        self.add_child(MeshInstance3D(mesh=Mesh.sphere(1.6), material=rock, position=(-1.5, -0.2, 2.0)))
65
66        water = WaterMaterial(
67            shallow_colour=(0.10, 0.42, 0.46),
68            deep_colour=(0.01, 0.07, 0.14),
69            depth_fade_distance=2.6,
70            wave_amplitude=0.16,
71            wave_length=6.5,
72            foam_amount=0.7,
73            refraction_strength=0.4,
74        )
75        self.add_child(WaterSurface3D(material=water, size=(40.0, 40.0)))
76
77
78if __name__ == "__main__":
79    App(title="Water Surface", width=1280, height=720).run(WaterScene())