Skip to content

Feat: Per-Index Color/Size Support with ImPlot3DSpec#182

Merged
brenocq merged 12 commits intomainfrom
feat/spec-colors
Apr 4, 2026
Merged

Feat: Per-Index Color/Size Support with ImPlot3DSpec#182
brenocq merged 12 commits intomainfrom
feat/spec-colors

Conversation

@brenocq
Copy link
Copy Markdown
Owner

@brenocq brenocq commented Apr 4, 2026

Per-Index Color/Size Support with ImPlot3DSpec

Closes #144

image image

image image

Summary

This PR introduces per-index color and size support across ImPlot3D plot types, just like implemented for ImPlot in epezent/implot#672. Users can now pass arrays of colors and sizes to apply a different color or size to each vertex, segment, or marker in their plots, enabling rich visualizations with color-coded spatial data.

It also overhauls PlotMesh with a new API matching the rest of the library, and adds per-index color support to meshes with a documented color indexing model.


New Properties

Five new ImPlot3DSpec properties have been added:

Property Type Description
ImPlot3DProp_LineColors ImU32* Per-segment/vertex colors for lines
ImPlot3DProp_FillColors ImU32* Per-vertex colors for filled surfaces
ImPlot3DProp_MarkerLineColors ImU32* Per-marker outline colors
ImPlot3DProp_MarkerFillColors ImU32* Per-marker fill colors
ImPlot3DProp_MarkerSizes float* Per-marker sizes

Supported Plot Types

Plot Type LineColors FillColors MarkerLineColors MarkerFillColors MarkerSizes
PlotScatter
PlotLine
PlotTriangle
PlotQuad
PlotSurface
PlotMesh

PlotMesh API Update

PlotMesh now accepts separate coordinate arrays, consistent with PlotLine, PlotScatter, and PlotTriangle. Spec.Offset and Spec.Stride apply to the vertex arrays only, not the index buffer. The old ImPlot3DPoint* overload is deprecated and will be removed in v1.0.

// Before (deprecated)
ImPlot3D::PlotMesh("Mesh", vtx, idxs, vtx_count, idx_count);

// After
ImPlot3D::PlotMesh("Mesh", vtx_xs, vtx_ys, vtx_zs, idxs, vtx_count, idx_count);

Color array semantics for PlotMesh

Array Size Indexed by
FillColors / LineColors idx_count Position in the index buffer (3 per triangle). Setting all 3 entries of a triangle to the same color gives flat shading; different values enable Gouraud shading (GPU-interpolated). To shade by vertex: FillColors[i] = vtx_colors[idxs[i]].
MarkerFillColors / MarkerLineColors vtx_count Vertex index (one marker per unique vertex).

Usage

// Scatter with per-marker colors and sizes
ImU32 fill_colors[100], line_colors[100];
float sizes[100];
// ... fill arrays ...
ImPlot3D::PlotScatter("Data", xs, ys, zs, 100, {
    ImPlot3DProp_MarkerFillColors, fill_colors,
    ImPlot3DProp_MarkerLineColors, line_colors,
    ImPlot3DProp_MarkerSizes,      sizes
});

// Line with per-segment colors
ImU32 line_colors[1001];
// ... fill array ...
ImPlot3D::PlotLine("f(x)", xs, ys, zs, 1001, {
    ImPlot3DProp_LineColors, line_colors
});

// Triangle mesh with per-vertex fill colors (Gouraud shading)
ImU32 fill_colors[18]; // one per vertex-in-order
// ... fill array ...
ImPlot3D::PlotTriangle("Mesh", xs, ys, zs, 18, {
    ImPlot3DProp_FillColors, fill_colors
});

// Indexed mesh with Gouraud shading (map vertex colors to index slots)
ImU32 idx_fill_colors[idx_count]; // one per index buffer slot
for (int i = 0; i < idx_count; i++)
    idx_fill_colors[i] = vtx_colors[idxs[i]];
ImPlot3D::PlotMesh("Duck", vtx_xs, vtx_ys, vtx_zs, idxs, vtx_count, idx_count, {
    ImPlot3DProp_Stride,     (int)sizeof(ImPlot3DPoint),
    ImPlot3DProp_FillColors, idx_fill_colors,
    ImPlot3DProp_Flags,      (int)ImPlot3DMeshFlags_NoLines
});

Implementation Details

  • Template-based getter system: GetterConstColor / GetterIdxColor for colors, GetterConstSize / GetterIdxSize for sizes. Lazy per-index fetching via operator()(int idx). GetterIdxColor applies an optional alpha multiplier.
  • RenderPrimitives / RenderPrimitives2 / RenderPrimitives3: convenience wrappers that dispatch templated renderers, matching ImPlot's pattern.
  • RenderColoredMarkers: dispatches on null checks of MarkerSizes, MarkerFillColors, MarkerLineColors to select const vs per-index getters, then calls the templated RenderMarkers.
  • Fill renderers (RendererTriangleFill, RendererQuadFill): call the color getter per vertex index (3*prim+v, 4*prim+v), enabling smooth GPU-interpolated color gradients across faces.
  • PlotMeshEx: new internal helper taking separate vertex and triangle getters, used by both the new templated PlotMesh overload and the deprecated ImPlot3DPoint* fallback.
  • GetterMeshTriangles: templated on three coordinate getters, replacing the old ImPlot3DPoint*-only struct.
  • Full backward compatibility: all existing single-color properties continue to work unchanged. The ImPlot3DPoint* overload still compiles (with a deprecation warning).
  • Alpha: per-index fill colors are multiplied by FillAlpha when applicable.

@brenocq brenocq self-assigned this Apr 4, 2026
@github-actions github-actions bot added status:review The task is under review prio:high High priority type:feat New feature or request labels Apr 4, 2026
@brenocq brenocq mentioned this pull request Apr 4, 2026
8 tasks
@brenocq brenocq merged commit 38a0c17 into main Apr 4, 2026
9 checks passed
@brenocq brenocq deleted the feat/spec-colors branch April 4, 2026 15:10
@github-actions github-actions bot added status:done Task completed successfully and removed status:review The task is under review labels Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

prio:high High priority status:done Task completed successfully type:feat New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Per-point custom colors

1 participant