From cbf57c7b8e0edf24d94cc8c1e28bf7731f5b2c93 Mon Sep 17 00:00:00 2001 From: sp-droid <52839915+sp-droid@users.noreply.github.com> Date: Fri, 30 Jan 2026 21:28:19 +0100 Subject: [PATCH 1/2] add_mesh per-face coloring When not uniform, the class will expect colors to be as large as either the positions (per-vertex coloring with intermediate interpolation) or the indices (per-face coloring) --- fastplotlib/graphics/mesh.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/fastplotlib/graphics/mesh.py b/fastplotlib/graphics/mesh.py index 0e1ac42a3..dcb7d51cc 100644 --- a/fastplotlib/graphics/mesh.py +++ b/fastplotlib/graphics/mesh.py @@ -50,20 +50,19 @@ def __init__( The 3D positions of the vertices. indices: array-like - The indices into the positions that make up the triangles. Each 3 - subsequent indices form a triangle. + The indices into the positions that make up the triangles (3 indices per row) or quads (4 indices per row). Each row is a face. mode: one of "basic", "phong", "slice", default "phong" * basic: illuminate mesh with only ambient lighting * phong: phong lighting model, good for most use cases, see https://en.wikipedia.org/wiki/Phong_shading * slice: display a slice of the mesh at the specified ``plane`` - + plane: (float, float, float, float), default (0., 0., 1., 0.) Slice mesh at this plane. Sets (a, b, c, d) in the equation the defines a plane: ax + by + cz + d = 0. Used only if `mode` = "slice". The plane is defined in world space. colors: str, array, or iterable, default "w" - A uniform color, or the per-position colors. + A uniform color (name or RGBA tuple), per-vertex colors (length=positions), or per-face colors (length=indices). mapcoords: array-like The per-position coordinates to which to apply the colormap (a.k.a. texcoords). @@ -120,7 +119,7 @@ def __init__( self._clim = clim uniform_color = "w" - per_vertex_colors = False + non_uniform_colors = False if cmap is None: if colors is None: @@ -130,14 +129,15 @@ def __init__( uniform_color = colors self._colors = UniformColor(uniform_color) elif isinstance(colors, VertexColors): - per_vertex_colors = True + non_uniform_colors = True self._colors = colors else: - per_vertex_colors = True + non_uniform_colors = True self._colors = VertexColors( - colors, n_colors=self._positions.value.shape[0] + colors, n_colors=len(colors) ) + geometry = pygfx.Geometry( positions=self._positions.buffer, indices=self._indices._buffer ) @@ -164,7 +164,7 @@ def __init__( ) # Set all the data - if per_vertex_colors: + if non_uniform_colors: geometry.colors = self._colors.buffer if self._mapcoords is not None: geometry.texcoords = self._mapcoords @@ -179,8 +179,13 @@ def __init__( # face_map = None #: Use per-face texture coords (``geometry.texcoords``), and sample these in ``material.map``. if mapcoords is not None and cmap is not None: material.color_mode = "vertex_map" - elif per_vertex_colors: - material.color_mode = "vertex" + elif non_uniform_colors: + if self._colors.value.shape[0] == self._indices.value.shape[0]: + material.color_mode = "face" + elif self._colors.value.shape[0] == self._positions.value.shape[0]: + material.color_mode = "vertex" + else: + raise ValueError("colors length does not match number of vertices or faces") else: material.color_mode = "uniform" From 6a56506902c5ddc2fbe8318046dc0371797d700c Mon Sep 17 00:00:00 2001 From: sp-droid <52839915+sp-droid@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:21:23 +0100 Subject: [PATCH 2/2] Clarify color parameter description in mesh.py --- fastplotlib/graphics/mesh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastplotlib/graphics/mesh.py b/fastplotlib/graphics/mesh.py index dcb7d51cc..21fd71572 100644 --- a/fastplotlib/graphics/mesh.py +++ b/fastplotlib/graphics/mesh.py @@ -62,7 +62,7 @@ def __init__( Used only if `mode` = "slice". The plane is defined in world space. colors: str, array, or iterable, default "w" - A uniform color (name or RGBA tuple), per-vertex colors (length=positions), or per-face colors (length=indices). + A uniform color (name or linear-RGBA tuple), per-vertex colors (length=positions), or per-face colors (length=indices). The introduced color is assumed to be in linear RGB scale. Popular colormaps such as the ones from matplotlib give it in sRGB. Careful! mapcoords: array-like The per-position coordinates to which to apply the colormap (a.k.a. texcoords).