toxi_toxiclibs · WingedEdgeMesh
Winged-Edge Mesh
A half-edge / winged-edge data structure for triangle meshes, designed for sub-million-triangle scenes where simple flat vertex/index arrays become cumbersome. Each edge stores pointers to its two endpoint vertices, its two opposite edges (the 'wings'), and the two incident faces; traversal from edge to edge is a single pointer-deref. Karsten's toxiclibs.geom.WingedEdge class was the first Java implementation aimed at creative-coding scenes and ships a `computeVertexNormals()`, `subdivide()` (Catmull-Clark style on a triangle mesh via Loop subdivision), and an adjacency-iterator used by his subdivision demo. The structure prefigures the half-edge meshes later popularised by libraries like OpenMesh and libigl, and is the canonical example of an adjacency-graph data structure for a creative-coding context.
Original: https://web.archive.org/web/2011/http://toxiclibs.org/2010/08/wingededge-mesh/
▶ 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.
Math essence
For each triangle (v0, v1, v2), three directed edges e0=(v0,v1), e1=(v1,v2), e2=(v2,v0). For each edge, find the opposite edge in the adjacent triangle (if any) and link them. Vertex normals: average the cross products of the two outgoing edges of every face incident to the vertex. Subdivide: each triangle becomes 4 by inserting midpoint vertices on each edge (new vertex position = (v_a + v_b) / 2 for non-shared edges, or Loop-weighted blend for shared ones). The data structure supports O(1) vertex-to-face and face-to-edge traversal.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
base_shape | str | icosahedron | — | Base platonic solid to start from. |
subdivision_levels | int | 3 | 0–6 | Number of Loop-subdivision passes. |
deform_amp | float | 0.15 | 0–1 | Per-vertex noise displacement amount. |
noise_scale | float | 1.5 | 0.1–8 | Spatial frequency of the displacement noise. |
time_speed | float | 0.4 | 0–4 | Animation rate of the displacement field. |
render_mode | str | shaded | — | Shading mode for the surface. |
Reference
First 60 lines of reference.py. Full source:
library_external/toxi_toxiclibs/WingedEdgeMesh/reference.py
"""WingedEdgeMesh — half-edge / winged-edge data structure for triangle meshes.
A pure-numpy port of Karsten Schmidt's toxiclibs.geom.WingedEdge (2010)
https://web.archive.org/web/2011/http://toxiclibs.org/2010/08/wingededge-mesh/
Each directed edge stores:
* `v_from`, `v_to` — its two endpoint vertices
* `opp_a`, `opp_b` — the 'wings' (the two opposite edges,
one in each of the two incident faces)
* `f_left`, `f_right` — the two incident triangle faces
This lets you traverse from edge to edge in O(1) and compute vertex
normals by averaging the cross products of outgoing edges.
The original 2010 Karsten demo included a Catmull-Clark style
subdivision pass; this port uses Loop subdivision (the variant
for triangle meshes) and a 3D Perlin-style displacement field.
"""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
@dataclass
class _Edge:
v_from: int
v_to: int
f_left: int
opp_a: int = -1
f_right: int = -1
opp_b: int = -1
# The reverse-direction edge (used internally during build)
twin_idx: int = -1
def _build_platonic(name: str):
"""Return (V, F) for a base platonic solid."""
if name == 'tetrahedron':
V = np.array([
[1, 1, 1], [-1, -1, 1], [-1, 1, -1], [1, -1, -1],
], dtype=np.float32) * 0.8
F = np.array([[0, 1, 2], [0, 3, 1], [0, 2, 3], [1, 3, 2]], dtype=np.int32)
elif name == 'cube':
V = np.array([
[-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1],
[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1],
], dtype=np.float32)
F = np.array([
[0, 1, 2], [0, 2, 3], [4, 6, 5], [4, 7, 6],
[0, 4, 5], [0, 5, 1], [2, 6, 7], [2, 7, 3],
[1, 5, 6], [1, 6, 2], [0, 3, 7], [0, 7, 4],
], dtype=np.int32)
elif name == 'octahedron':
V = np.array([
[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1],
], dtype=np.float32)
F = np.array([
[0, 2, 4], [2, 1, 4], [1, 3, 4], [3, 0, 4], Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/toxi_toxiclibs/WingedEdgeMesh/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from toxi_toxiclibs
Additive Waves — 3D Terrain
toxi_toxiclibs · AdditiveWaves3D
A 2D height-field terrain driven by the sum of multiple wave generators (sine, FBM noise, sawtooth, constant offset) defined in Karsten Schmidt's toxiclibscore wave module.
Super-Ellipsoid Mesh
toxi_toxiclibs · SuperEllipsoid
A super-ellipsoid is a 3D primitive that smoothly interpolates between a sphere, a box, and a pinched pillow via two shape parameters e1 (longitude exponent) and e2 (latitude exponent).
Verlet Physics 3D — Mass-Spring Cloth
toxi_toxiclibs · VerletPhysics3D
A 3D mass-spring system integrated with Verlet position-based dynamics and Jakobsen-style constraint relaxation.