Generating Digital Landscapes: 3D Wireframe Sand Dunes in Py5

2026/8/11

Terrain generation is a classic use case for procedural noise, but rather than aiming for photorealism, it’s often more interesting to lean into a purely digital, minimalist aesthetic. In this project, the goal was to create an endless expanse of rolling sand dunes constructed entirely from glowing wireframes. By mapping mathematical noise to a 3D grid, we can simulate an infinite, shifting landscape that feels like flying over a cybernetic desert.Python and Py5 provide a perfect blend of high-level data manipulation and fast OpenGL rendering, allowing us to generate and animate this terrain smoothly in real-time.

Visual and Aesthetic Approach

The aesthetic of this piece is defined by high contrast and geometric purity. Instead of using solid polygons with complex, realistic lighting models, the sketch relies entirely on empty wireframes (py5.no_fill()) paired with an additive blend mode (py5.blend_mode(py5.ADD)).A dynamic color gradient sweeps across the terrain based on the height of the dunes. The "valleys" dip into cool, deep teals, while the "peaks" transition into warm, glowing oranges. As the virtual camera flies forward along the Y-axis, the terrain fades out softly into the distance. This depth-fading provides an atmospheric sense of scale, preventing the geometry from abruptly popping into existence at the edge of the render distance.

Code and Technical Breakdown

The foundation of the terrain is a dense 2D grid. To render this efficiently, we use py5.TRIANGLE_STRIP, which allows us to draw a continuous row of connecting triangles by only supplying a minimal number of vertices.The elevation of the terrain is driven by OpenSimplex noise.
cols = 80
rows = 60
spacing = 60

t = py5.frame_count * 0.02
z_fly = py5.frame_count * 15 # The "speed" of our forward flight

for y in range(rows - 1):
    py5.begin_shape(py5.TRIANGLE_STRIP)
    for x in range(cols):
        # Calculate noise for the top vertex of the strip
        n_val1 = py5.os_noise(x * 0.05, (y * spacing - z_fly) * 0.005, t * 0.5)
        h1 = py5.remap(n_val1, -1, 1, -500, 500)
        
        # Calculate noise for the bottom vertex of the strip
        n_val2 = py5.os_noise(x * 0.05, ((y + 1) * spacing - z_fly) * 0.005, t * 0.5)
        h2 = py5.remap(n_val2, -1, 1, -500, 500)
The trick to simulating the camera "flying" forward is in how we query the noise function. We don't actually move the grid geometry. Instead, we subtract `z_fly` from the Y-coordinate before passing it into py5.os_noise. As z_fly increases every frame, the noise pattern effectively slides backwards across our static grid, creating the perfect illusion of endless forward momentum. We also pass time t into the third dimension of the noise function, which causes the dunes to slowly shift and morph their shape, like sand blowing in the wind.To calculate the color and the depth fading:
    # Map the calculated height to a Hue value
    hue1 = (180 + py5.remap(h1, -500, 500, 0, 120) + py5.frame_count) % 360
    hue2 = (180 + py5.remap(h2, -500, 500, 0, 120) + py5.frame_count) % 360
    
    # Fade out at the back of the grid (where y is close to 0)
    alpha_val = py5.remap(y, 0, rows, 10, 100)
    
    # Draw the top vertex
    py5.stroke(hue1, 80, 100, alpha_val)
    py5.vertex(x * spacing, y * spacing, h1)
    
    # Draw the bottom vertex
    py5.stroke(hue2, 80, 100, alpha_val)
    py5.vertex(x * spacing, (y + 1) * spacing, h2)
    
py5.end_shape()
The alpha_val is directly tied to the y row index. Rows closer to the camera (y near 60) have an alpha of 100, while rows furthest away (y near 0) drop to a nearly invisible alpha of 10, creating a smooth transition into the abyss.
digital wireframe sand dunes 3d p1

Conclusion

Procedural terrain generation is a powerful technique that proves we don't need complex 3D assets to build compelling environments. By leveraging the continuous, organic nature of OpenSimplex noise and mapping it intelligently across a grid, we can synthesize endless digital worlds from pure mathematics.