Water surface¶
an animated Gerstner sea refracting the scene below it.
▶ Run in browserTags: 3d water gerstner refraction transparent
A WaterSurface3D is a built-in transparent pass (its own shader pair), NOT a ShaderMaterial. Its vertex stage tessellates a grid and displaces it by a sum of four Gerstner waves whose direction + strength come from the WorldEnvironment wind and whose phase comes from the frame clock. Its fragment stage refracts the submerged geometry (sampling the scene colour/depth copy that the surface’s presence switches on), fades from a shallow tint to a deep tint with water depth, mixes a Fresnel reflection, and foams where the water meets the shore. Submerged pillars and a sloped floor show the depth fade, refraction wobble and shore foam; the wind drives the swell.
Controls: ESC: Quit
Usage: uv run python examples/features/3d/water.py
Source¶
1"""Water surface: an animated Gerstner sea refracting the scene below it.
2
3A WaterSurface3D is a built-in transparent pass (its own shader pair), NOT a
4ShaderMaterial. Its vertex stage tessellates a grid and displaces it
5by a sum of four Gerstner waves whose direction + strength come from the
6WorldEnvironment wind and whose phase comes from the frame clock. Its fragment
7stage refracts the submerged geometry (sampling the scene colour/depth copy that
8the surface's presence switches on), fades from a shallow tint to a deep tint
9with water depth, mixes a Fresnel reflection, and foams where the water meets the
10shore. Submerged pillars and a sloped floor show the depth fade, refraction
11wobble and shore foam; the wind drives the swell.
12
13# /// simvx
14# tags = ["3d", "water", "gerstner", "refraction", "transparent"]
15# screenshot_frame = 40
16# ///
17
18Controls:
19 ESC: Quit
20
21Usage:
22 uv run python examples/features/3d/water.py
23"""
24
25from simvx.core import (
26 Camera3D,
27 DirectionalLight3D,
28 Input,
29 InputMap,
30 Key,
31 Material,
32 Mesh,
33 MeshInstance3D,
34 Node,
35 WaterMaterial,
36 WaterSurface3D,
37 WorldEnvironment,
38)
39from simvx.graphics import App
40
41WIDTH, HEIGHT = 1280, 720
42
43
44class WaterScene(Node):
45 def on_ready(self):
46 InputMap.add_action("quit", [Key.ESCAPE])
47
48 # Post-processing + wind. Water refracts through the HDR scene copy, so
49 # a WorldEnvironment (which enables the HDR chain) is required; the wind
50 # drives the Gerstner swell direction + strength via FrameGlobals.
51 env = self.add_child(WorldEnvironment())
52 env.wind_direction = (0.7, 0.7)
53 env.wind_strength = 0.6
54
55 self.add_child(Camera3D(position=(0, 3.2, 11.0), look_at=(0, 0.2, 0), up=(0, 1, 0)))
56 sun = self.add_child(DirectionalLight3D(intensity=3.0))
57 sun.direction = (-0.5, -1.0, -0.4)
58
59 # Sloped sandy floor descending away from the camera: gives a shoreline
60 # (thin water -> foam) near the front and deep water at the back.
61 floor = self.add_child(
62 MeshInstance3D(
63 mesh=Mesh.cube(1.0),
64 material=Material(colour=(0.72, 0.62, 0.42, 1.0), roughness=0.9),
65 position=(0, -2.2, -6.0),
66 scale=(30.0, 0.5, 26.0),
67 )
68 )
69 floor.rotation_degrees = (16.0, 0.0, 0.0)
70
71 # Submerged pillars: the refraction wobble + depth tint read clearly on
72 # tall vertical shapes seen through the surface.
73 for x, z, colour in [
74 (-3.5, -1.0, (0.85, 0.3, 0.3, 1.0)),
75 (0.0, -3.0, (0.3, 0.8, 0.45, 1.0)),
76 (3.5, -1.5, (0.35, 0.5, 0.9, 1.0)),
77 ]:
78 self.add_child(
79 MeshInstance3D(
80 mesh=Mesh.cube(1.0),
81 material=Material(colour=colour, roughness=0.6),
82 position=(x, -0.8, z),
83 scale=(0.9, 3.0, 0.9),
84 )
85 )
86
87 # A partly-emergent sphere island so the shoreline foam curves around it.
88 self.add_child(
89 MeshInstance3D(
90 mesh=Mesh.sphere(1.6),
91 material=Material(colour=(0.6, 0.55, 0.4, 1.0), roughness=0.85),
92 position=(-1.5, -0.2, 2.0),
93 )
94 )
95
96 # The water plane at y=0. Its presence switches on the scene colour/depth
97 # copy the refraction reads.
98 self.water = self.add_child(WaterSurface3D(position=(0, 0, 0), size=(40.0, 40.0)))
99 self.water.material = WaterMaterial(
100 shallow_colour=(0.10, 0.42, 0.46),
101 deep_colour=(0.01, 0.07, 0.14),
102 depth_fade_distance=2.6,
103 wave_amplitude=0.16,
104 wave_length=6.5,
105 foam_amount=0.7,
106 refraction_strength=0.4,
107 )
108
109 def on_update(self, dt):
110 if Input.is_action_pressed("quit"):
111 self.app.quit()
112
113
114def main():
115 App(width=WIDTH, height=HEIGHT, title="SimVX - Water").run(WaterScene())
116
117
118if __name__ == "__main__":
119 main()