Search code examples
pythonvtknormals

Why normals on a mesh in vtk are different acording to mesh color?


I'm trying to compute the normals of a mesh in vtk for each vertex. When I display them It seems normals vertex for green vertex have smaller length than vertex with white color. I don't understand why I get this result.

To color the mesh I used this function :

def update_colors(self,couleurs=None,Vertex_correspondance=None):
    Colors = vtk.vtkUnsignedCharArray()
    Colors.SetNumberOfComponents(3)
    Colors.SetName("Colors")
    for i in range(self.points.shape[0]):
        if not i in Vertex_correspondance :
            Colors.InsertNextTuple3(255,255,255)
        else:
            Colors.InsertNextTuple3(couleurs[0] ,  couleurs[1] , couleurs[2])
    self.GetOutput.GetPointData().SetScalars(Colors)
    self.GetOutput.Modified()

So I assign a green color to some vertices of the mesh (30 vertices).

To compute the normals, I use :

        poly_data = self.actor.GetMapper().GetInput()

        normalsCalc = vtk.vtkPolyDataNormals()

        normalsCalc.SetInputData(poly_data)
        normalsCalc.ComputePointNormalsOn()
        normalsCalc.ComputeCellNormalsOff()
        normalsCalc.SplittingOff()
        normalsCalc.FlipNormalsOff()
        normalsCalc.ConsistencyOn()
        normalsCalc.AutoOrientNormalsOn()
        normalsCalc.Update()

        arrowSource = vtk.vtkArrowSource()

        glyph3D = vtk.vtkGlyph3D()
        glyph3D.SetSourceConnection(arrowSource.GetOutputPort())
        glyph3D.SetVectorModeToUseNormal()
        glyph3D.SetInputData(normalsCalc.GetOutput())
        glyph3D.SetScaleFactor(0.02)
        glyph3D.OrientOn()
        glyph3D.Update()

        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(glyph3D.GetOutputPort())

        self.glyphActor = vtk.vtkActor()
        self.glyphActor.SetMapper(mapper)
        self.glyphActor.GetProperty().SetColor([0, 0, 1])

here is the display I get enter image description here

Also If I compute the normals length after with

    normals = []
    array = normalsCalc.GetOutput().GetPointData().GetNormals()
    for i in range(array.GetNumberOfTuples()):
        normals.append(array.GetTuple(i))
    self.Normals = np.array(normals)
    np.linalg.norm(self.Normals,axis=1)

I have number really close to 1. So the normals seems to have been computed well...


Solution

  • Maybe you need to use SetScaleModeToDataScalingOff(), this seems to work:

    from vedo import Ellipsoid, show
    import vtk
    
    s = Ellipsoid().computeNormals()
    arr = s.points()[:,2]
    s.cmap('jet_r', arr)
    
    arrowSource = vtk.vtkArrowSource()
    glyph3D = vtk.vtkGlyph3D()
    glyph3D.SetSourceConnection(arrowSource.GetOutputPort())
    glyph3D.SetVectorModeToUseNormal()
    glyph3D.SetInputData(s.polydata())
    glyph3D.SetScaleFactor(0.2)
    glyph3D.OrientOn()
    glyph3D.SetScaleModeToDataScalingOff() ###### <--
    glyph3D.Update()
    
    show(s, glyph3D, axes=1)
    

    enter image description here