FFT Ocean.

OceanSurface3D is an open-sea plane whose waves come from an FFT of a Tessendorf (Phillips) spectrum rather than a sum of analytic waves. Each frame the spectrum is inverse-transformed into displacement, slope and foam maps for up to three cascades, from long swell to fine ripple, which sum into rolling swell, choppy crests and foam on the steep, folding faces. The quality tier picks the cascade count and texture size.

▶ Run in browser

Tags: 3d ocean fft water transparent

The surface is shaded by a WaterMaterial, the same one WaterSurface3D (the Gerstner water) uses: shallow_colour, deep_colour and depth_fade_distance tint by water depth, wave_amplitude scales the wave height, wave_steepness the chop, and refraction_strength how far the submerged island and pillars wobble. foam_colour tints both the crest foam and the shore foam, and foam_amount is how deep the shore-foam band around the island and pillars reaches. Refraction reads a copy of the HDR scene, so a WorldEnvironment is required. Its wind_direction and wind_strength steer the spectrum, and the specular glint is placed along the wind heading.

Make the plane large and finely subdivided (size, subdivisions) so the cascades resolve across the whole view.

Source

 1# /// simvx
 2# tags = ["3d", "ocean", "fft", "water", "transparent"]
 3# screenshot_frame = 70
 4# ///
 5"""FFT Ocean.
 6
 7`OceanSurface3D` is an open-sea plane whose waves come from an FFT of a
 8Tessendorf (Phillips) spectrum rather than a sum of analytic waves. Each frame
 9the spectrum is inverse-transformed into displacement, slope and foam maps for
10up to three cascades, from long swell to fine ripple, which sum into rolling
11swell, choppy crests and foam on the steep, folding faces. The quality tier
12picks the cascade count and texture size.
13
14The surface is shaded by a `WaterMaterial`, the same one `WaterSurface3D` (the
15Gerstner water) uses: `shallow_colour`, `deep_colour` and `depth_fade_distance`
16tint by water depth, `wave_amplitude` scales the wave height, `wave_steepness`
17the chop, and `refraction_strength` how far the submerged island and pillars
18wobble. `foam_colour` tints both the crest foam and the shore foam, and
19`foam_amount` is how deep the shore-foam band around the island and pillars
20reaches. Refraction reads a copy of the HDR scene,
21so a `WorldEnvironment` is required. Its `wind_direction` and `wind_strength`
22steer the spectrum, and the specular glint is placed along the wind heading.
23
24Make the plane large and finely subdivided (`size`, `subdivisions`) so the
25cascades resolve across the whole view.
26"""
27
28from simvx.core import (
29    Camera3D,
30    DirectionalLight3D,
31    Material,
32    Mesh,
33    MeshInstance3D,
34    Node,
35    OceanSurface3D,
36    WaterMaterial,
37    WorldEnvironment,
38)
39from simvx.graphics import App
40
41
42class OceanScene(Node):
43    def on_ready(self):
44        self.add_child(WorldEnvironment(wind_direction=(0.8, 0.35), wind_strength=0.7))
45        # High enough that the crests never reach eye level.
46        self.add_child(Camera3D(position=(0, 5.0, 20.0), look_at=(0, 1.5, -30.0)))
47        self.add_child(DirectionalLight3D(intensity=3.2, direction=(-0.6, -0.7, -0.5)))
48
49        # An island and two half-submerged pillars give the depth fade and refraction something to show.
50        rock = Material(colour=(0.42, 0.38, 0.32, 1.0), roughness=0.9)
51        self.add_child(MeshInstance3D(mesh=Mesh.sphere(6.0), material=rock, position=(-6.0, -1.5, -14.0)))
52        pillar = Material(colour=(0.30, 0.28, 0.26, 1.0), roughness=0.7)
53        for x, z in [(5.0, -6.0), (9.0, -12.0)]:
54            self.add_child(MeshInstance3D(mesh=Mesh.box((1.4, 4.0, 1.4)), material=pillar, position=(x, -0.5, z)))
55
56        water = WaterMaterial(
57            shallow_colour=(0.06, 0.30, 0.36),
58            deep_colour=(0.01, 0.06, 0.12),
59            depth_fade_distance=8.0,
60            wave_amplitude=1.4,
61            wave_steepness=0.75,
62            foam_colour=(0.92, 0.96, 1.0),
63            foam_amount=1.2,
64            refraction_strength=0.4,
65        )
66        self.add_child(OceanSurface3D(material=water, size=(800.0, 800.0), subdivisions=320))
67
68
69if __name__ == "__main__":
70    App(width=1280, height=720, title="FFT Ocean").run(OceanScene())