Skip to content

Shaders#

The octarine.shaders module contains the custom materials and post-processing passes powering some of Octarine's features - see Effects & Shading for an introduction. Requires pygfx>=0.17.

Note that you will rarely have to touch these directly: they are typically employed via the respective octarine.Viewer methods (e.g. add_sparse_volume, set_silhouette or set_depth_of_field).

octarine.shaders.SparseVolume #

A sparse volume defined by brick-packed voxel data.

PARAMETER DESCRIPTION
packed
    Brick-packed voxel data (see `pack_sparse_voxels`).

TYPE: PackedBricks

material
    The material defining the appearance of the volume.

TYPE: SparseVolumeMaterial

octarine.shaders.SparseVolumeMaterial #

Material for rendering a SparseVolume.

In addition to the properties of pygfx.VolumeBasicMaterial (clim, map, gamma, interpolation, opacity), this material has a render_mode:

  • "mip": maximum intensity projection (like pygfx.VolumeMipMaterial)
  • "density": front-to-back emission/absorption for a cloud-like look; density sets the extinction per voxel
  • "iso" (alias "surface"): shaded isosurface at threshold
PARAMETER DESCRIPTION
render_mode
        See above.

TYPE: "mip" | "density" | "iso" DEFAULT: 'mip'

step_size
        Ray-march step (in voxels) inside occupied bricks:
        smaller = fewer misses of small structures but slower
        rendering.

TYPE: float DEFAULT: 0.5

threshold
        "iso" mode only: the level at which the surface sits,
        given as a fraction of `clim`.

TYPE: float DEFAULT: 0.5

density
        "density" mode only: extinction per voxel at the top of
        `clim`. Higher = more opaque.

TYPE: float DEFAULT: 0.1

gradient_delta
        "iso" mode only: half-width (in voxels) of the central
        differences used to derive the surface normal. Larger
        values give smoother normals on blocky (e.g. binary)
        data but round off features thinner than the delta.

TYPE: float DEFAULT: 1.0

smoothing
        "iso" mode only: width (in voxels) of an extra filter
        applied to the field the *normal* is taken from. 0 (the
        default) is off. Removes the voxel-scale stipple from the
        shading without moving the surface.

TYPE: float DEFAULT: 0.0

shininess
        "iso" mode only: size of the specular highlight.

TYPE: float DEFAULT: 30

emissive
        "iso" mode only: color the surface emits regardless of
        lighting.

TYPE: Color DEFAULT: '#000'

density property writable #

Extinction per voxel at the top of clim ("density" mode).

emissive property writable #

Color the isosurface emits regardless of lighting.

gradient_delta property writable #

Half-width (in voxels) of the normal's central differences.

render_mode property writable #

The render mode: "mip", "density" or "iso".

shininess property writable #

Size of the specular highlight on the isosurface.

smoothing property writable #

Width (in voxels) of the extra filter applied to the normal.

step_size property writable #

Ray-march step (in voxels) inside occupied bricks.

threshold property writable #

Isosurface level, as a fraction of clim ("iso" mode).

octarine.shaders.pack_sparse_voxels(voxels, values=None, clim=None, brick_size=16, max_atlas_dim=2048, fill_ratio_warn=0.005) #

Pack sparse (N, 3) voxel coordinates into a brick map.

PARAMETER DESCRIPTION
voxels
        Voxel coordinates (xyz). Floats are floored to integers.

TYPE: (N, 3) array

values
        Per-voxel scalar values. If given, values are quantized
        into the 1-255 range (0 is reserved for empty space)
        according to `clim`; voxels hit by multiple points keep
        the maximum. Without values, occupied voxels are set
        to 255.

TYPE: (N,) array DEFAULT: None

clim
        Range used to quantize `values`. Defaults to the data
        min/max.

TYPE: (min, max) tuple DEFAULT: None

brick_size
        Brick edge length in voxels; must be a power of two.

TYPE: int DEFAULT: 16

max_atlas_dim
        Maximum edge length of the atlas texture. The default
        matches WebGPU's default `max_texture_dimension_3d`.

TYPE: int DEFAULT: 2048

fill_ratio_warn
        Warn if the fraction of atlas voxels actually hit by a
        point falls below this value.

TYPE: float DEFAULT: 0.005

RETURNS DESCRIPTION
PackedBricks

octarine.shaders.BitmaskVolume #

A binary sparse volume defined by bitmask-packed voxel runs.

PARAMETER DESCRIPTION
packed
    Bitmask-packed voxel data (see `pack_voxel_runs`).

TYPE: PackedBitmask

material
    The material defining the appearance of the volume.

TYPE: BitmaskVolumeMaterial

octarine.shaders.BitmaskVolumeMaterial #

Material for rendering a BitmaskVolume.

The data is binary occupancy, so there is nothing to map onto a colormap: the volume is drawn in a single color.

PARAMETER DESCRIPTION
render_mode
        - "mip": flat silhouette (for binary data the first hit
          *is* the maximum)
        - "density": front-to-back absorption, so thicker parts
          render more opaque
        - "iso" (alias "surface"): shaded isosurface

TYPE: "mip" | "density" | "iso" DEFAULT: 'mip'

color
        Color of the volume.

TYPE: Color DEFAULT: '#ffffff'

step_size
        Ray-march step (in voxels) inside occupied bricks.

TYPE: float DEFAULT: 0.5

threshold
        "iso" mode only: level at which the surface sits, between
        0 (just outside a voxel) and 1 (a voxel center).

TYPE: float DEFAULT: 0.5

density
        "density" mode only: extinction per voxel.

TYPE: float DEFAULT: 0.1

gradient_delta
        "iso" mode only: half-width (in voxels) of the central
        differences used to derive the surface normal.

TYPE: float DEFAULT: 1.0

smoothing
        "iso" mode only: width (in voxels) of an extra filter
        applied to the field the *normal* is taken from. 0 (the
        default) is off. Removes the voxel-scale stipple from the
        shading without moving the surface.

TYPE: float DEFAULT: 0.0

shininess
        "iso" mode only: size of the specular highlight.

TYPE: float DEFAULT: 30

emissive
        "iso" mode only: color emitted regardless of lighting.

TYPE: Color DEFAULT: '#000'

color property writable #

Color of the volume.

density property writable #

Extinction per voxel ("density" mode).

emissive property writable #

Color the isosurface emits regardless of lighting.

gradient_delta property writable #

Half-width (in voxels) of the normal's central differences.

render_mode property writable #

The render mode: "mip", "density" or "iso".

shininess property writable #

Size of the specular highlight on the isosurface.

smoothing property writable #

Width (in voxels) of the extra filter applied to the normal.

step_size property writable #

Ray-march step (in voxels) inside occupied bricks.

threshold property writable #

Isosurface level ("iso" mode).

octarine.shaders.pack_voxel_runs(runs, brick_size=16, max_buffer_bytes=128 * 1024 ** 2) #

Pack (N, 4) run-length-encoded voxels into a bitmask brick map.

PARAMETER DESCRIPTION
runs
        Runs as (x, y, z, x_run_length), i.e. the layout DVID's
        `sparsevol` endpoint returns (see `dvid.get_sparsevol`
        with ``voxels=False``). Runs extend along x and the length
        is an inclusive voxel count.

TYPE: (N, 4) array

brick_size
        Brick edge length in voxels; must be a power of two in
        8-64. The default of 16 is the measured optimum.

TYPE: int DEFAULT: 16

max_buffer_bytes
        Storage-buffer size to check the payload against; matches
        WebGPU's default `maxStorageBufferBindingSize`.

TYPE: int DEFAULT: 128 * 1024 ** 2

RETURNS DESCRIPTION
PackedBitmask

octarine.shaders.runs_from_voxels(voxels) #

Convert (N, 3) voxel coordinates to (N, 4) runs along x.

PARAMETER DESCRIPTION
voxels
    Voxel coordinates (xyz). Floats are floored to integers.

TYPE: (N, 3) array

RETURNS DESCRIPTION
(M, 4) int64 array

Runs as (x, y, z, length), sorted by (z, y, x).

octarine.shaders.TubeVisual #

A tube surface defined by per-node radial profile coefficients.

PARAMETER DESCRIPTION
coefs
    Per-node coefficients, as produced by
    `sparsecubes.TubeProfile.to_gpu_buffer()` in its Cartesian
    form: position (3), frame quaternion xyzw (4), mean radius
    a0 (1), then K cosine and K sine coefficients. Positions are
    expected in physical units (i.e. with any voxel spacing
    already applied).

TYPE: (M, 8 + 2K) array

edges
    Index pairs into the nodes. A skeleton is a tree, so the
    surface is swept per edge - consecutive node indices are not
    assumed to be connected.

TYPE: (E, 2) array

material
    The material defining the appearance of the tube.

TYPE: TubeMaterial

colors
    Per-node RGBA colors. Requires the material's `color_mode`
    to be "vertex".

TYPE: (M, 4) array DEFAULT: None

octarine.shaders.TubeMaterial #

Material for rendering a TubeVisual.

In addition to the properties of pygfx.MeshPhongMaterial, this material has the two angular level-of-detail knobs:

  • n_theta: number of angular samples around the tube (>= 3). This is both a uniform and the draw-call size; changing it neither re-uploads nor reallocates the coefficients.
  • k_max: number of harmonics evaluated for the surface position. Clamped in the shader to the number actually present in the buffer; 0 renders circular tubes of radius a0.
  • k_normal: number of harmonics evaluated for the normal, clamped to k_max. Deliberately separate and usually much lower - dr/dtheta weights harmonic k by k, so the harmonics that still sharpen the silhouette already make the shading look like sandpaper (and dark where the normal tilts past the view direction). 1 is the default, 0 the smooth-tube floor.

color_mode may be "uniform" (the material's color) or "vertex" (per-node RGBA from geometry.colors).

k_max property writable #

Number of harmonics evaluated for the position; 0 gives circular tubes.

k_normal property writable #

Number of harmonics evaluated for the normal; clamped to k_max.

n_theta property writable #

Number of angular samples around the tube.

octarine.shaders.decimate_edges(edges, n_nodes, step) #

Thin an edge list step-fold along its unbranched runs.

Nodes of degree != 2 - branch points and tips - are always kept, so the topology is untouched and no arm can go missing; only the interior of each run is thinned. Striding the node array instead would silently reconnect unrelated branches.

Note that this leaves the surviving nodes' frames describing a centreline that no longer exists: the stored tangent is the local direction at full resolution, and the chord it is now swept along spans step times as much of the centreline's jitter. Follow with align_frames(..., retangent=True) or the decimated tube's rings sit further off their sweep than the undecimated ones did.

PARAMETER DESCRIPTION
edges
    Index pairs into the nodes.

TYPE: (E, 2) array

n_nodes
    Number of nodes the indices refer to.

TYPE: int

step
    Keep every `step`-th interior node. 1 is a no-op.

TYPE: int

RETURNS DESCRIPTION
(E', 2) int32 array

octarine.shaders.align_frames(coefs, edges, retangent=True) #

Rebuild the per-node frame so that it is consistent along edges.

Two things about the frames as they arrive show up as jagged geometry, and this fixes both:

  • The stored theta = 0 reference is rotation-minimizing only within an unbranched run. The chain restarts at every branch point, so an edge spanning a junction connects theta = 0 on one ring to an unrelated angle on the other and the quad between them is twisted. The runs also drift against a true rotation-minimizing frame in the interior. One chain is propagated over the whole tree here instead.
  • The stored tangent is the centreline's local direction. For a skeleton traced from voxels that sits well off the chord the surface is actually swept along, which tilts the ring relative to its own sweep and is what makes consecutive rings punch through each other; decimate_edges makes it worse, not better, because the chord then spans more of the jitter. retangent re-derives the tangent from the edge list.

The profile is rotated to follow the new frame, which is exact (see rotate_profile), so no shape is lost to the realignment itself. Re-tangenting does move the surface - the profile was measured in the old cross-section plane and is applied in a slightly tilted one - but that error is second order in the tilt while the punch-through it removes is first order.

PARAMETER DESCRIPTION
coefs
    Per-node coefficients. Not modified; a new array is returned.

TYPE: (M, 8 + 2K) array

edges
    The edge list the surface will actually be swept along - i.e.
    after any decimation, not before.

TYPE: (E, 2) array

retangent
    Whether to re-derive the tangents as well as the phase. Phase
    alignment alone leaves the geometry untouched.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
(M, 8 + 2K) float32 array

octarine.shaders.rotate_profile(coefs, psi) #

Rotate each node's profile by psi (M,) radians about its own tangent.

Exact, and the reason the frame can be rebuilt without losing any shape: substituting theta -> theta + psi into

r(theta) = a0 + sum_k [a_k cos(k theta) + b_k sin(k theta)]

and re-collecting gives

a'_k = a_k cos(k psi) + b_k sin(k psi)
b'_k = b_k cos(k psi) - a_k sin(k psi)

i.e. each harmonic rotates by k psi, and a0 is untouched.

PARAMETER DESCRIPTION
coefs
    Modified in place.

TYPE: (M, 8 + 2K) float array

psi
    Angle from the old `u` to the new one, in the old frame.

TYPE: (M,) array

octarine.shaders.split_runs(edges, n_nodes) #

Split an edge list into its unbranched runs.

Each run is a list of node indices [start, ...interior..., end] whose ends have degree != 2 - branch points and tips - and whose interior is all degree 2. Every edge belongs to exactly one run. A closed loop, which has no node of degree != 2 to start from, is broken open at an arbitrary node and comes back with run[0] == run[-1].

PARAMETER DESCRIPTION
edges
    Index pairs into the nodes.

TYPE: (E, 2) array

n_nodes
    Number of nodes the indices refer to.

TYPE: int

RETURNS DESCRIPTION
list of list of int

octarine.shaders.SilhouetteMeshMaterial #

A Phong mesh material with a Neuroglancer-style silhouette effect.

In addition to the properties of pygfx.MeshPhongMaterial, this material has a silhouette exponent: fragments are multiplied by pow(1 - |dot(normal, view_dir)|, silhouette), making face-on regions transparent and emphasizing edges/creases. 0 disables the effect; typical values are 1-8.

Note that for the transparency to composite sensibly the material should use a transparent alpha_mode (octarine defaults to "weighted_blend").

silhouette property writable #

Silhouette exponent; 0 disables the effect.

octarine.shaders.SubsurfaceMeshMaterial #

A Phong mesh material with subsurface scattering (translucency).

In addition to the properties of pygfx.MeshPhongMaterial (and the silhouette exponent of SilhouetteMeshMaterial, which is off by default here), this material scatters light through the surface.

PARAMETER DESCRIPTION
subsurface
        Master strength of the effect; 0 disables it entirely.
        Typical values are 0.5-2.

TYPE: float DEFAULT: 1.0

scatter_color
        The color light picks up while travelling through the
        material. Defaults to a warm red.

TYPE: str | tuple DEFAULT: '#a03028'

thickness
        How much material the light has to cross, in [0, 1].
        Constant across the mesh - lower it for thin, papery
        objects, raise it for chunky ones.

TYPE: float DEFAULT: 0.5

distortion
        How far the transmitted light direction is bent along
        the surface normal, in [0, 1]. 0 makes the glow appear
        only under near-exact backlighting; higher values wrap
        it around the silhouette.

TYPE: float DEFAULT: 0.2

falloff
        Exponent of the transmission lobe (>= 1). Higher values
        tighten the glow around the light direction.

TYPE: float DEFAULT: 4.0

wrap
        How far diffuse light bleeds past the terminator, in
        [0, 1]. 0 leaves pygfx's Lambertian shading untouched.

TYPE: float DEFAULT: 0.5

glow
        A view-independent floor added to the transmission,
        giving translucent objects a slight overall lift.
        (Called "ambient" in the original formulation; renamed
        to avoid confusion with `pygfx.AmbientLight`.)

TYPE: float DEFAULT: 0.0

Notes

The transmission term deliberately ignores shadows: light that scatters through an object is exactly the light that did not reach the surface directly, so attenuating it by a shadow lookup would cancel the effect.

distortion property writable #

How far transmitted light bends along the normal, in [0, 1].

falloff property writable #

Exponent of the transmission lobe; higher tightens the glow.

glow property writable #

View-independent floor added to the transmission.

scatter_color property writable #

The color light picks up while travelling through the material.

subsurface property writable #

Master strength of the scattering; 0 disables the effect.

thickness property writable #

How much material the light has to cross, in [0, 1].

wrap property writable #

How far diffuse light bleeds past the terminator, in [0, 1].

octarine.shaders.MatcapMeshMaterial #

A mesh material shaded by a matcap instead of by the scene's lights.

The surface normal in view space looks up a color in the matcap image (a picture of a shaded sphere), which becomes the color of the fragment. The scene's lights, shadows and ambient occlusion play no part in it.

In addition to the properties of pygfx.MeshBasicMaterial:

PARAMETER DESCRIPTION
matcap
    The matcap. A preset name or recipe dict is rendered on the
    spot (see `make_matcap` and `MATCAP_PRESETS`); an image is
    used as-is.

TYPE: str | dict | array | pygfx.Texture | pygfx.TextureMap DEFAULT: 'pearl'

tint
    How much of the material's own `color` (and any vertex
    colors) tints the matcap, from 0 (the matcap's colors win)
    to 1 (fully multiplied in). Neutral matcaps are usually
    worth tinting - it keeps differently colored objects
    distinguishable - while strongly colored ones are not.

TYPE: float DEFAULT: 1.0

kwargs
    Additional kwargs are passed to `pygfx.MeshBasicMaterial`.

TYPE: Any DEFAULT: {}

matcap property writable #

The matcap image, as a pygfx.TextureMap.

tint property writable #

How much the material's own color tints the matcap (0-1).

octarine.shaders.make_matcap(preset='pearl', *, size=256, environment=None, **overrides) #

Render a matcap image by lighting a virtual sphere.

PARAMETER DESCRIPTION
preset
    Name of an entry in `MATCAP_PRESETS` (e.g. "pearl", "clay",
    "metal", "gold", "jade" or "neon"), or a dict of the
    properties below.

TYPE: str | dict DEFAULT: 'pearl'

size
    Width/height of the generated image in pixels. 256 is ample -
    a matcap is a very smooth image.

TYPE: int DEFAULT: 256

environment
    Lighting setup to shade the sphere with; see
    `octarine.shaders.environment.ENVIRONMENT_PRESETS`. Defaults
    to whatever the matcap preset asks for.

TYPE: str | dict DEFAULT: None

**overrides
    Individual `base_color`, `specular`, `shininess`, `rim`,
    `rim_color`, `rim_power`, `bands`, `band_softness`, `edge`,
    `edge_width` or `tint` values overriding the preset's.

DEFAULT: {}

RETURNS DESCRIPTION
(size, size, 4) float32 array

Linear (physical) RGBA. Highlights may well exceed 1 - the image is high dynamic range, like the environments it is lit with.

octarine.shaders.matcap_texture(matcap='pearl', *, size=256, **kwargs) #

Build a matcap texture, ready to be assigned to MatcapMeshMaterial.

PARAMETER DESCRIPTION
matcap
    A preset name or recipe dict (see `make_matcap`), or an
    image to use directly: an (N, M, 3) or (N, M, 4) array of
    floats (linear) or uint8 (sRGB), which is what an
    off-the-shelf matcap PNG looks like once loaded.

TYPE: str | dict | array | pygfx.Texture | pygfx.TextureMap DEFAULT: 'pearl'

size
    Size of the generated image; ignored if `matcap` is already
    an image.

TYPE: int DEFAULT: 256

**kwargs
    Passed on to `make_matcap`; ignored if `matcap` is already
    an image.

DEFAULT: {}

RETURNS DESCRIPTION
pygfx.TextureMap

octarine.shaders.GradientBackgroundMaterial #

A radial gradient background.

The color ramp runs from color_inner at the center, through color_mid half-way out, to color_outer at (and beyond) radius. Distances are measured in units of the canvas width, so the gradient stays circular whatever the window's aspect ratio.

PARAMETER DESCRIPTION
colors
    Two or three colors: `(inner, mid, outer)` or - with the
    mid stop interpolated - `(inner, outer)`.

TYPE: tuple DEFAULT: ('#34383A', '#171A1B', '#050607')

center
    Center of the gradient in relative image coordinates:
    `(0, 0)` is the top left, `(1, 1)` the bottom right corner.

TYPE: (x, y) tuple DEFAULT: (0.5, 0.4)

radius
    Distance at which the gradient reaches `color_outer`, as a
    fraction of the canvas width.

TYPE: float DEFAULT: 0.65

falloff
    Shape of the ramp. Values > 1 keep the core bright and push
    the transition towards the rim (3 ~ "the outer 30% of the
    radius"), 1 is linear, values < 1 drop off right at the
    center and trail out.

TYPE: float DEFAULT: 3.0

vignette
    Strength (0-1) of the additional darkening towards the
    corners of the frame. 0 disables it.

TYPE: float DEFAULT: 0.5

kwargs
    Additional kwargs are passed to `pygfx.Material`.

TYPE: Any DEFAULT: {}

center property writable #

Center of the gradient; (0, 0) is the top left corner.

color_inner property writable #

Color at the center of the gradient.

color_mid property writable #

Color half-way between the center and radius.

color_outer property writable #

Color at (and beyond) radius.

colors property writable #

The gradient's (inner, mid, outer) colors.

falloff property writable #

Shape of the radial ramp; > 1 keeps the core bright.

radius property writable #

Radius of the gradient as a fraction of the canvas width.

vignette property writable #

Strength (0-1) of the darkening towards the corners.

from_preset(preset, **kwargs) classmethod #

Create a material from one of the BACKGROUND_PRESETS.

PARAMETER DESCRIPTION
preset
    Name of a preset (see `BACKGROUND_PRESETS`) or a dict of
    parameters.

TYPE: str | dict

kwargs
    Override individual preset parameters.

TYPE: Any DEFAULT: {}

set_colors(*colors) #

Set the gradient's colors.

Accepts three colors (inner, mid, outer) or two (inner, outer), in which case the mid stop is the average of the two. Colors can be passed as separate arguments or as a single sequence.

octarine.shaders.FlexPointsMaterial #

A marker points material with flexible size/edge-width spaces.

In addition to the properties of pygfx.PointsMarkerMaterial, this material supports:

  • edge_size_space: coordinate space for edge_width ("screen", "world" or "model"). If None (default), edge_width uses the same space as size (i.e. size_space), matching stock pygfx behavior.
  • min_size / max_size: clamp the final on-screen point size, in logical pixels. Useful with size_space="world" to keep far-away points visible ("world-sized but at least N pixels"). The clamp is applied after the size has been converted to screen pixels, so it also works with per-vertex sizes. If both are set, max_size wins.
  • min_edge_width: a floor for the final on-screen edge width, in logical pixels. Only applies when edge_width > 0 (i.e. it does not conjure up an edge that was disabled).

edge_size_space property writable #

The coordinate space in which the edge width is expressed.

One of "screen", "world" or "model" (see :obj:pygfx.utils.enums.CoordSpace), or None to use the same space as the point size (size_space).

max_size property writable #

Maximum on-screen point size in logical pixels (None = no maximum).

min_edge_width property writable #

Minimum on-screen edge width in logical pixels (0 = no minimum).

min_size property writable #

Minimum on-screen point size in logical pixels (0 = no minimum).

octarine.shaders.DepthOfFieldPass #

A depth-of-field (focal blur) post-processing pass.

PARAMETER DESCRIPTION
camera
    The camera used to render the scene. Needed to map depth
    values back to world-unit distances.

TYPE: pygfx.Camera

focus
    Distance of the focal plane from the camera in world units.
    For orthographic cameras this may be negative: pygfx places
    the camera in the middle of the scene. If None (default),
    continuously auto-focuses on whatever is at the center of
    the view (if that is empty space, the image is left sharp).

TYPE: float DEFAULT: None

aperture
    Blur strength: the blur radius in physical pixels of a
    point at 100% relative defocus - relative to the focus
    distance for perspective cameras, and to the visible height
    of the view for orthographic ones. Typical values are
    50-300.

TYPE: float DEFAULT: 100.0

max_radius
    Upper limit for the blur radius in physical pixels.

TYPE: float DEFAULT: 16.0

num_taps
    Number of samples in the blur kernel. More taps give a
    smoother blur at a higher rendering cost.

TYPE: int DEFAULT: 64

smooth
    Only relevant for autofocus (`focus=None`): if > 0, changes
    in focus are eased over approximately this many seconds
    instead of snapping instantly (True = 0.2s). While the view
    center is over empty space the last focus is held. Note
    that when rendering reactively something needs to keep
    triggering re-renders until a re-focus transition has
    settled (see `Viewer.set_depth_of_field`, which handles
    this).

TYPE: float | bool DEFAULT: 0.0

snap_radius
    Only relevant for autofocus (`focus=None`): search radius
    in physical pixels around the view center. The autofocus
    targets the object closest to the view center within that
    radius, instead of only what is exactly under the center
    pixel. 0 (default) disables snapping.

TYPE: float DEFAULT: 0.0

aperture property writable #

Blur strength (px of blur radius at 100% relative defocus).

focus property writable #

Focal distance in world units; None means autofocus.

max_radius property writable #

Upper limit for the blur radius in physical pixels.

num_taps property writable #

Number of samples in the blur kernel.

smooth property writable #

Approximate autofocus re-focus time in seconds; 0 = instant.

snap_radius property writable #

Autofocus search radius around the view center in px; 0 = off.

get_focus_position(renderer) #

Return the world position of the current focal point.

With a fixed focus this is the point at the focus distance along the view axis; with autofocus (focus=None) it is the surface point at the center of the view, read back from the depth buffer of the last rendered frame.

PARAMETER DESCRIPTION
renderer
    The renderer used to render the scene.

TYPE: pygfx.WgpuRenderer

RETURNS DESCRIPTION
(3,) array | None

None if the position cannot be determined - i.e. with autofocus when nothing has been rendered yet or there is no object under the center of the view.

octarine.shaders.NormalizedDepthPass #

Render normalized depth as shades of grey.

Unlike pygfx's DepthPass (which renders the raw - highly non-linear - depth buffer), this linearizes depth to view-space distance and stretches it over the depth range actually covered by the geometry on screen: the nearest visible surface renders black, the farthest light grey, and the (empty) background stays white.

PARAMETER DESCRIPTION
camera
    The camera used to render the scene; needed to linearize
    depth values. If None, the raw depth values are
    normalized instead - with a perspective camera this
    exaggerates depth differences close to the camera.

TYPE: pygfx.Camera DEFAULT: None

overlay
    If True, the scene's own colors are kept and darkened
    with distance (depth cueing) instead of being replaced
    by greyscale; the background is left untouched.

TYPE: bool DEFAULT: False

strength
    How dark the farthest geometry is rendered, from 0 (not
    at all) to 1 (black in greyscale mode; fully darkened in
    overlay mode). The default of 0.9 keeps the farthest
    geometry distinguishable from the (white) background in
    greyscale mode.

TYPE: float DEFAULT: 0.9

overlay property writable #

Whether to darken the scene's colors instead of rendering greyscale.

strength property writable #

How dark the farthest geometry is rendered (0-1).

octarine.shaders.AmbientOcclusionPass #

A screen-space ambient occlusion (SSAO) post-processing pass.

Estimates how much of the hemisphere above each pixel is blocked by nearby geometry and darkens the image accordingly, which brings out creases, cavities and the contact points between objects.

PARAMETER DESCRIPTION
camera
    The camera used to render the scene. Needed to map depth
    values back to view-space positions.

TYPE: pygfx.Camera

radius
    How far - in world units - to look for occluders. This is
    the one parameter that has to match the scene: too small
    and the effect disappears, too large and it turns into a
    dark haze. A good starting point is a few percent of the
    size of the scene (see `Viewer.set_ambient_occlusion`,
    which derives such a default from the scene bounds).

TYPE: float DEFAULT: 1.0

intensity
    Strength of the darkening, from 0 (no effect) to 1 (fully
    occluded pixels turn black).

TYPE: float DEFAULT: 1.0

bias
    Occluders closer to the surface than this - as a fraction
    of `radius` - are ignored. Raise it if flat surfaces show
    occlusion of their own ("self-occlusion", caused by depth
    buffer precision), lower it if fine detail is lost.

TYPE: float DEFAULT: 0.01

samples
    Number of hemisphere samples per pixel. More samples mean
    less noise at a higher rendering cost.

TYPE: int DEFAULT: 16

power
    Exponent applied to the occlusion; values > 1 restrict the
    effect to the darkest areas, values < 1 spread it out.

TYPE: float DEFAULT: 1.0

blur
    Radius (in pixels) of the bilateral blur that removes the
    sampling noise; the kernel spans twice as many taps. True
    (default) uses 2, i.e. exactly one tile of the 4x4 sampling
    pattern - other values leave some of the pattern visible.
    False (or 0) disables the blur, which is mostly useful for
    debugging.

TYPE: bool | int DEFAULT: True

debug
    If True, render the occlusion itself as greyscale instead
    of darkening the scene. Useful for tuning `radius`.

TYPE: bool DEFAULT: False

bias property writable #

Occluders nearer than this fraction of radius are ignored.

blur property writable #

Radius of the bilateral blur in pixels; 0 disables it.

debug property writable #

Whether to render the occlusion itself instead of the scene.

intensity property writable #

Strength of the darkening (0 = off, 1 = black where fully occluded).

power property writable #

Exponent applied to the occlusion.

radius property writable #

How far to look for occluders, in world units.

samples property writable #

Number of hemisphere samples per pixel.

octarine.shaders.OutlinePass #

An outline (edge detection) post-processing pass.

Finds silhouettes and creases in the depth buffer and draws them in color.

PARAMETER DESCRIPTION
camera
    The camera used to render the scene. Needed to map depth
    values back to view-space positions.

TYPE: pygfx.Camera

color
    Color of the outline. The alpha channel doubles as the
    strength of the effect, i.e. "#0004" gives a subtle line.

TYPE: str | tuple DEFAULT: '#000'

thickness
    Width of the outline in physical pixels. Values above ~4
    start to look chunky rather than drawn.

TYPE: float DEFAULT: 1.0

depth_threshold
    How far a neighbouring pixel has to lie off the tangent
    plane of the surface to count as a separate object,
    relative to its distance from the camera. Lower it to
    outline shallower steps, raise it if surfaces get outlined
    across their interior.

TYPE: float DEFAULT: 0.02

normal_threshold
    How sharply the surface has to fold to count as a crease,
    as `1 - cos(angle)`: 0.3 is roughly 45 degrees. Set to 0 to
    switch creases off and outline only silhouettes.

TYPE: float DEFAULT: 0.3

debug
    If True, render the edges themselves as white on black
    instead of drawing them over the scene.

TYPE: bool DEFAULT: False

color property writable #

Color of the outline; its alpha is the strength of the effect.

debug property writable #

Whether to render the edges themselves instead of the scene.

depth_threshold property writable #

Relative step in depth that counts as a separate object.

normal_threshold property writable #

How sharp a fold counts as a crease, as 1 - cos(angle); 0 = off.

thickness property writable #

Width of the outline in physical pixels.

octarine.shaders.ToneMappingPass #

A tone mapping (and exposure) post-processing pass.

Compresses the rendered high dynamic range image into the range the display can show, so that bright regions roll off smoothly instead of clipping to flat white.

PARAMETER DESCRIPTION
mode
    The tone mapping curve:
     - "aces" (default): a fit to the ACES filmic response.
       Contrasty and saturated; the usual choice.
     - "filmic": Hable's "Uncharted 2" curve. Like ACES but
       holds more shadow detail.
     - "reinhard": the gentlest option. Keeps colors closest to
       the original at the cost of looking flatter.
     - "none": clip only, i.e. exposure control on its own.

TYPE: str DEFAULT: 'aces'

exposure
    Scales the image before the curve is applied: 2 is one stop
    brighter, 0.5 one stop darker.

TYPE: float DEFAULT: 1.0

white_point
    The input value that maps to white. Only used by "reinhard"
    and "filmic"; raising it holds on to more highlight detail
    (and darkens the image overall).

TYPE: float DEFAULT: 4.0

exposure property writable #

Scales the image before the curve is applied.

mode property writable #

The tone mapping curve; one of TONEMAP_MODES.

stops property writable #

The exposure expressed in stops; 0 leaves the image unchanged.

white_point property writable #

The input value that maps to white ("reinhard" and "filmic" only).

octarine.shaders.procedural_env_map(preset='studio', *, resolution=128, rotation=0.0, **overrides) #

Build an environment cube map from the analytic model.

PARAMETER DESCRIPTION
preset
    Name of an entry in `ENVIRONMENT_PRESETS` (e.g. "studio",
    "soft", "sky", "sunset" or "neon"), or a dict of the
    properties below.

TYPE: str | dict DEFAULT: 'studio'

resolution
    Width/height of one cube face. 128 is plenty for the diffuse
    lighting; raise it if a mirror-like material shows the
    softboxes as visibly polygonal.

TYPE: int DEFAULT: 128

rotation
    Rotation about the vertical axis in degrees; moves the
    highlights without redefining the lights.

TYPE: float DEFAULT: 0.0

**overrides
    Individual `intensity`, `sky`, `horizon`, `ground`,
    `gradient` or `lights` values overriding the preset's.

DEFAULT: {}

RETURNS DESCRIPTION
pygfx.TextureMap

A mipmapped rgba16float cube map, ready to be assigned to scene.environment, material.env_map or a pygfx.BackgroundSkyboxMaterial.

octarine.shaders.environment_radiance(directions, preset='studio', *, rotation=0.0, **overrides) #

Evaluate the analytic environment model in the given directions.

This is what procedural_env_map bakes into a cube map; it is exposed separately because the matcap generator lights its sphere with the same model (see octarine.shaders.matcap).

PARAMETER DESCRIPTION
directions
    World-space directions. Must be normalized.

TYPE: (..., 3) array

preset
    Name of an entry in `ENVIRONMENT_PRESETS`, or a dict of the
    properties below.

TYPE: str | dict DEFAULT: 'studio'

rotation
    Rotation of the environment about the vertical axis, in
    degrees. Moves the highlights around without having to
    redefine the lights.

TYPE: float DEFAULT: 0.0

**overrides
    Individual `intensity`, `sky`, `horizon`, `ground`,
    `gradient` or `lights` values overriding the preset's.

DEFAULT: {}

RETURNS DESCRIPTION
(..., 3) array

Linear (physical) radiance. Values well above 1 are normal - that is what a light source looks like.

octarine.shaders.cube_directions(size) #

World-space direction of every texel of a cube map.

PARAMETER DESCRIPTION
size
Width/height of one cube face.

TYPE: int

RETURNS DESCRIPTION
(6, size, size, 3) array

Unit vectors, one per texel, in the face order wgpu expects (+X, -X, +Y, -Y, +Z, -Z).

Notes

Cube maps are specified in a left-handed coordinate system while pygfx is right-handed, so pygfx negates the x component when it samples one (both for the skybox background and for env_map lookups). The directions returned here have that flip applied already, i.e. they are the world direction that will end up sampling the corresponding texel.