Isosurfaces#
Isosurface rendering extracts and displays the zero level-set of a scalar function inside a 3D mesh. A second function can be colored on the isosurface.
Basic Isosurface#
Render the zero level-set of a function, colored by another function:
[1]:
from netgen.occ import *
from ngsolve import *
from ngsolve_webgpu.mesh import MeshData
from ngsolve_webgpu.cf import FunctionData
from ngsolve_webgpu.isosurface import IsoSurfaceRenderer, NegativeSurfaceRenderer, NegativeClippingRenderer
from webgpu.clipping import Clipping
from webgpu.colormap import Colorbar, Colormap
from webgpu.jupyter import Draw
box = Box((-1, -1, -1), (1, 1, 1))
mesh = Mesh(OCCGeometry(box).GenerateMesh(maxh=0.2))
gf = GridFunction(H1(mesh, order=2))
levelset = 0.8**2 - (x**2 + y**2 + z**2)
gf.Set(levelset)
mesh_data = MeshData(mesh)
colormap = Colormap()
clipping = Clipping()
func_data = FunctionData(mesh_data, x, order=2)
levelset_data = FunctionData(mesh_data, -gf, order=2)
iso = IsoSurfaceRenderer(func_data, levelset_data, clipping, colormap)
neg_surface = NegativeSurfaceRenderer(func_data, levelset_data, clipping=clipping, colormap=colormap)
neg_clip = NegativeClippingRenderer(func_data, levelset_data, clipping, colormap)
clipping.mode = clipping.Mode.PLANE
scene = Draw([iso, neg_clip, neg_surface, Colorbar(colormap)])
Three renderers work together:
``IsoSurfaceRenderer`` — extracts and renders the zero level-set surface via a compute shader. The level-set data is negated by convention (negative = inside).
``NegativeSurfaceRenderer`` — renders the outer mesh surface only where the level-set is negative (inside the domain).
``NegativeClippingRenderer`` — renders the clipping cross-section only inside the level-set domain.
Updating the Level Set#
The isosurface updates when the underlying GridFunction changes and scene.redraw() is called.
[2]:
gf.Set(0.5**2 - (x**2 + y**2 + z**2))
scene.redraw()
[ ]: