Reputation: 381
I added a mesh to a pyvista.Plotter()
with
p.add_mesh(mesh, show_edges=True, color='linen', pbr=True, metallic=0.8, roughness=0.1, diffuse=1)
but it displays with a discontinuity (where the mesh started and ended)
Why is this junction of cells different from similar ones around this toroid?
Upvotes: 1
Views: 185
Reputation: 381
Good Answer. The first and last groups of points were not exactly the same due to floating point errors:-
[[ 4.8000000e+01 0.0000000e+00 0.0000000e+00]
[ ... ... ... ]
[ 4.8000000e+01 -3.9188699e-15 1.1756609e-14]]
I fixed it by rounding the coordinates when they were generated (to create an STL file):-
return (x.round(5), y.round(5), z.round(5))
Not sure why such tiny differences had such a noticeable visible effect...
Upvotes: 0
Reputation: 35175
It's probably due to how surface normals are computed, and that your mesh connectivity is off along that edge.
The way you often generate such closed surfaces is to parametrise with respect to some generalised coordinates, one of which in this case is the azimuthal angle. Where your azimuthal angle sweep starts (following the physics convention: phi = 0
corresponds to the +x
axis) and ends (phi = 2*pi
, again the +x
axis) overlaps, but if you don't take care to ensure connectivity across this boundary then you don't have a closed toroid, but rather an open tube turned back on itself that has a seam where the two open ends meet. This affects how surface normals are estimated on the boundary faces.
If you check mesh.extract_feature_edges(boundary_edges=True, non_manifold_edges=True, feature_edges=False, manifold_edges=False).plot()
you will likely get a vertical ring right where the artifact happens. Depending on your mesh it's probably enough to call mesh = mesh.clean()
with a small tolerance
value, because if your points at the seam properly overlap then this can merge your boundary points and fuse your boundary faces to remove the spurious edge. (You might also have to recompute the normals yourself, but probably not; I'm not entirely sure.)
Case in point: here's a concrete example using an extruded polygon (which is what your mesh seems to be, or close enough):
import pyvista as pv
# generate toroid
square = pv.Polygon(n_sides=4).translate((0, -2, 0))
toroid = square.extrude_rotate(resolution=8, rotation_axis=(1, 0, 0), capping=False)
# let's see what we've got
plotter = pv.Plotter()
plotter.add_mesh(toroid, color='lightblue', smooth_shading=True)
plotter.view_yz()
plotter.show()
From the shading it's obvious that something's amiss. It's the hidden boundary edge(s):
print(toroid.n_open_edges)
# 8
open_edges = toroid.extract_feature_edges(
boundary_edges=True,
non_manifold_edges=True,
feature_edges=False,
manifold_edges=False,
)
plotter = pv.Plotter()
plotter.add_mesh(toroid, color='lightblue', smooth_shading=True)
plotter.add_mesh(open_edges, color='red', line_width=5, render_lines_as_tubes=True)
plotter.view_yz()
plotter.show()
And cleaning with a small tolerance (to allow for floating-point errors) solves the problem:
cleaned = toroid.clean(tolerance=1e-12)
print(cleaned.n_open_edges)
# 0
plotter = pv.Plotter()
plotter.add_mesh(cleaned, color='lightblue', smooth_shading=True)
plotter.view_yz()
plotter.show()
Upvotes: 2