marcomusy / vedo

A python module for scientific analysis of 3D data based on VTK and Numpy
https://vedo.embl.es
MIT License
2.05k stars 266 forks source link

compute_normals() unexpectedly changes the appearance of a Mesh #1174

Open jkunimune opened 3 months ago

jkunimune commented 3 months ago

The documentation for Mesh.compute_normals() has a warning that if feature_angle is set, the mesh may be modified. This implies that if it's not set, the user can expect the mesh to not be modified. However, unless points=False is specified, this function will change the display style to use the vertex normals to make the shading smoother.

This is especially an issue because functions like Mesh.boolean(), which don't say anything about modification, call compute_normals() with the default settings and thus also unexpectedly change the display style.

At the very least this should be noted in the documentation. However, ideally the display style should not change unless the user explicitly wills it. I think the best solution would be to check if this smooth lighting setting is enabled before computing the normals, then set it back to whatever it was after the normals are computed. Unfortunately, I'm not sure what this setting is called or if it's even settable. It's possible that VTK just always shows meshes differently depending on whether their point normals have been computed.

If that's the case, an alternative solution would be to change points to be False by default, so that compute_normals() at least usually doesn't modify the display style (and this behavior would then be noted in the documentation). Unfortunately I'm also not sure if that would work for boolean() because I'm not sure whether computing the point normals is necessary for the boolean algorithm. Maybe someone here who's more familiar with the code could weigh in on that?

MWE:

import vedo

a = vedo.Pyramid(pos=(0, 0, 0))
b = vedo.Pyramid(pos=(1, 1, 0))

a.compute_normals()

plotter = vedo.Plotter()
plotter.show(a, b)

imagen

marcomusy commented 3 months ago

This is tricky because the default is phong shading - which kind of looks nice - but VTK (as you suspected) automatically reverts to flat shading if normals are not available in the mesh. So a possiblity would be to change the default. Another is to call .flat() after computing normals:

a.compute_normals().flat()
jkunimune commented 3 months ago

Ah, good to know. I think flat being the default makes sense, since it's the simplest shading option. And then .phong() could automatically call .calculate_normals() so that the user doesn't have to worry about normals at all in most cases.