Skip to content
Sample of Recursive Spherical Displacement Wireframe

shader_legends_3 · IQDisplacementSphere

Recursive Spherical Displacement Wireframe

A wireframe sphere whose surface is recursively displaced by spherical harmonics of the form amp * sin(N * theta) * cos(M * phi), rendered as overlapping latitude and meridian polylines plus random surface dots. Three nested displacement levels of decreasing amplitude produce a 'sphere on a sphere on a sphere' geometry that reads as a sea-urchin or virus shell — entirely from analytic geometry, no noise, no texture sampling.

Original: https://iquilezles.org/articles/

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
shader_legends_3
Source
shader_legends_3
Evolution
displacement
Render
wireframe
Complexity
medium
Agents
0
Year
2014
Author
Iñigo Quilez (Shadertoy user 'iq')

Math essence

For each 3D point p on the unit sphere, with theta = arccos(p.y) and phi = atan2(p.z, p.x), the displacement is r := 1 + amp_k * (0.5 + 0.5 * sin(N_k * theta + phase_t) * cos(M_k * phi + phase_t)). Apply this for k=1,2,3 in succession with decreasing amps, rotate the result by (0.4 t, 0.6 t, 0.3 t), then orthographically project. The wireframe samples n_lat latitude circles and n_lon meridian polylines; surface dots come from uniformly-spaced (theta, phi) draws.

Parameters

Name Type Default Range Description
dim int 400 160–800 Square output size in pixels.
n_lat int 28 8–80 Number of latitude circles in the wireframe.
n_lon int 56 16–160 Number of meridians in the wireframe.
n1 int 4 2–12 Theta frequency for level-1 displacement.
n2 int 3 2–12 Phi frequency for level-1 displacement (theta freq for level-2).
n3 int 5 2–12 Phi frequency for level-2 displacement (theta freq for level-3).
amp1 float 0.18 0.02–0.5 Amplitude of the level-1 displacement.
amp2 float 0.1 0.02–0.3 Amplitude of the level-2 displacement.
amp3 float 0.05 0.01–0.2 Amplitude of the level-3 displacement.
radius float 0.4 0.2–0.48 Sphere radius in canvas units.
rotate_speed float 0.18 -0.5–0.5 Per-step Euler rotation rate.
dot_density float 0.18 0–0.6 Random surface-dot density.
line_color rgb 0.45,0.85,1 null–null Wireframe colour.
fill_color rgb 0.05,0.1,0.18 null–null Silhouette fill tint.
background rgb 0.02,0.02,0.05 null–null Background colour.

Reference

First 60 lines of reference.py. Full source: library_external/shader_legends_3/IQDisplacementSphere/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


def _hash21(x: np.ndarray, y: np.ndarray, seed: int) -> np.ndarray:
    """Deterministic 2D hash → [0, 1)."""
    x = np.asarray(x, dtype=np.int64)
    y = np.asarray(y, dtype=np.int64)
    h = (x * np.int64(374761393) + y * np.int64(668265263) + np.int64(seed)) & np.int64(0xFFFFFFFF)
    h = (h ^ (h >> np.int64(13))) * np.int64(1274126177) & np.int64(0xFFFFFFFF)
    h = h ^ (h >> np.int64(16))
    return (h & np.int64(0xFFFFFFFF)).astype(np.float32) / np.float32(0xFFFFFFFF)


class IQDisplacementSphere:
    """Recursive spherical displacement — Iñigo Quilez (Shadertoy).

    IQ's classic *displacement* shader (Shadertoy) is a deceptively
    short program: a single sphere is recursively *displaced* by
    other smaller spheres on its surface, then those smaller
    spheres are again displaced, and so on, producing a wireframe
    of nested spherical "growths" that looks like a sea-urchin or
    a virus.  The math essence is:

    1. start with a base point on the unit sphere,
    2. apply ``displacement = amp * sin(N * theta) * cos(M * phi)``,
    3. rotate the result by a time-varying Euler triple,
    4. project to 2D with simple orthographic projection.

    The shader has no texture sampling, no fBM, and no lighting.
    Its richness comes entirely from the recursive spherical
    geometry.  This implementation flattens the recursion into a
    single nested series of polar displacements: three
    *generations* of ``amp * sin(N * theta) * cos(M * phi)`` of
    decreasing amplitude, rendered as a wireframe of latitude
    lines + dots, with an optional second concentric wireframe
    that adds the "sphere on a sphere" look.
    """

    family: ClassVar[str] = "shader_legends_3"
    sketch: ClassVar[str] = "iqdisplacementsphere"

    def __init__(
        self,
        dim: int = 400,
        n_lat: int = 28,
        n_lon: int = 56,
        n1: int = 4,
        n2: int = 3,
        n3: int = 5,
        amp1: float = 0.18,
        amp2: float = 0.10,
        amp3: float = 0.05,
        radius: float = 0.40,
        rotate_speed: float = 0.18,
        dot_density: float = 0.18,
        line_color: tuple[float, float, float] = (0.45, 0.85, 1.00),

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/shader_legends_3/IQDisplacementSphere/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from shader_legends_3

Sample of Animated FBM Nebula with Chromatic Aberration

Animated FBM Nebula with Chromatic Aberration

shader_legends_3 · AshleyGAnimNebula

A multi-coloured, slowly rotating cosmic gas cloud built from 5 layers of FBM noise at different scales, each layer rotated by a different angle that varies with time.

View →
Sample of Atmospheric Perspective Landscape

Atmospheric Perspective Landscape

shader_legends_3 · HubertyAtmospheric

A painterly 2D landscape built from depth-graded FBM bands: a soft sky gradient with a sun disc and cloud streaks, a low-amp haze band in the upper-middle, rolling green midground hills, and a sharp foreground silhouette of trees and grass.

View →
Sample of Bokeh Blur with Light Leaks

Bokeh Blur with Light Leaks

shader_legends_3 · TaterBokeh

A 2D bokeh effect built by stamping 50-200 soft Gaussian discs onto a near-black backdrop, each at a hash-determined centre, radius, and warm-to-cool colour.

View →
Sample of Hash-driven Procedural City Skyline

Hash-driven Procedural City Skyline

shader_legends_3 · DaveHoskinsHashCity

A 2D orthographic night-time cityscape whose per-column building heights come from 1D FBM noise and whose lit windows are a per-cell hash threshold.

View →
Sample of Volumetric Clouds from Cellular + FBM

Volumetric Clouds from Cellular + FBM

shader_legends_3 · BigWingsClouds

A painterly cumulus-cloud sky built from a Worley/cellular noise layer (cloud puffs) gated by a low-frequency FBM (large-scale cloud coverage) and a high-frequency FBM (in-cloud detail).

View →

See all shader_legends_3 artworks →