Matplotlib mesh renderer: walkthrough & observations
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 35/100
- Issue type
- Documentation
- Clarity
- Needs clarification
- Activity status
- Quiet
- Tech stack
- matplotlib, python
- Domain
- computer-graphics, documentation
Research direction
Start with src/gsp_matplotlib/renderer/matplotlib_renderer_mesh.py, especially the linked render pipeline sections, and compare the walkthrough with the implementation at commit 6f3b86c. The issue does not specify a documentation destination or acceptance criteria, so confirm the intended format and location before editing; done should mean the agreed walkthrough is placed there and matches the code.
Written by the indexing model from the issue text.
Description
How the matplotlib mesh renderer works — src/gsp_matplotlib/renderer/matplotlib_renderer_mesh.py.
Pipeline
RendererMesh.render(renderer, viewport, mesh, model_matrix, camera) returns a list of matplotlib Artists.
-
Pull buffers (matplotlib_renderer_mesh.py:45-71) —
TransBufUtils.to_bufferthenBufferx.to_numpyon positions, indices, model/view/projection matrices, face colors, edge colors, edge widths. Colors are normalized from0-255→0-1(/ 255.0). -
Per-vertex → per-face broadcast (matplotlib_renderer_mesh.py:79-95) — matplotlib's
PolyCollectionwants one color/width per face. A local_to_per_facehelper handles three cases:- already per-face → leave alone
- per-vertex → pick the value at the first vertex of each triangle (
array[indices[:, 0]]) - length-1 → broadcast to face_count
-
MVP transform (matplotlib_renderer_mesh.py:110-113) —
MathUtils.compute_mvp_matrix(...)thenapply_transform_matrix(vertices, mvp)→ NDC. Reshape into(face_count, 3, 3)triangles. -
Drop Z (matplotlib_renderer_mesh.py:120) —
faces_vertices_2d = faces_vertices_ndc[..., :2]. Z is kept around for sorting only. -
Painter's sort (matplotlib_renderer_mesh.py:146-156) — when
face_sorting=True, sort faces by mean NDC z descending (far → near), and re-indexcolors/edge_colors/edge_widthswith the same permutation. Comment notes the limitation: this works within the artist; cross-object ordering would needset_zorderand is currently disabled. -
Face culling (matplotlib_renderer_mesh.py:162-168) — delegates to
RendererUtils.compute_faces_visiblewhich uses the 2D cross product of edges. Sign decides CCW vs CW; magnitude <1e-6is treated as degenerate.FrontSide/BackSide/BothSideseach pick a different predicate. Filter mask is applied to all per-face arrays. -
Artist cache (matplotlib_renderer_mesh.py:173-185) — one
PolyCollectionper mesh uuid, stored inrenderer._artists. Created hidden on first render, thenset_visible(True). -
Update artist (matplotlib_renderer_mesh.py:199-202) —
set_verts,set_facecolor,set_edgecolor,set_linewidth.
Things to notice
uvsandnormalsare completely ignored — the matplotlib path is "flat triangles in screen space"; no shading, no texturing. That fitsMeshBasicMaterial's name, but reinforces the open question from #18 about whether those buffers should be required at construction.- Per-vertex color collapses to the first vertex of each triangle — no per-face averaging, no gouraud interpolation. So an OBJ with per-vertex colors will look blocky and asymmetric (rotating the index order changes the look).
- Culling uses the screen-space cross product, not a real normal. This is correct for triangles after a perspective divide (the sign of the 2D cross product matches the front-facing orientation), but it diverges from any culling that would use
geometry.normals. Mesh.sanity_check_attributes_bufferis called at matplotlib_renderer_mesh.py:101, but that method is apass— so the call is currently free, but also free of safety. Same observation as #18.- Z-order across objects is commented out (matplotlib_renderer_mesh.py:187-192) —
RendererUtils.update_single_artist_zorderexists but is disabled, so two overlapping meshes will paint in registration order, not depth order. - Camera position is never directly used — culling depends only on post-MVP geometry, so the camera enters only through the view/projection matrices.
Links pinned to commit 6f3b86c.
- Dominant language
- Python
- Stars
- 2
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from vispy/GSP_API
-
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
Difficulty 3/5 1-2 days Newbie friendliness 65/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 45/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
syfoud/Simulated_Scepter#172 ·
-
A cancelled tests run makes the coverage comment workflow fail and reports it as a red check on main Openarea: ci bug perceived difficulty: 3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Nitjsefnie-Harness-Commons/daedalus#921 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
EleutherAI/lm-evaluation-harness#4207 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 92/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
ClickHouse/clickhouse-connect#1057 ·