Setting Normals



  • On 21/08/2017 at 12:05, xxxxxxxx wrote:

    I got a list of normals and a bunch of polygons:

      
                     # get points, normals, faces, uvs  
                      indices = gltf_get_accessor(mesh["primitives"][0]["indices"], d, buffer)  
                      coords  = gltf_get_accessor(mesh["primitives"][0]["attributes"]["POSITION"], d, buffer)  
                      uvs     = gltf_get_accessor(mesh["primitives"][0]["attributes"]["TEXCOORD_0"], d, buffer)  
                      normals = gltf_get_accessor(mesh["primitives"][0]["attributes"]["NORMAL"], d, buffer)  
                      faces   = [tuple(indices[i:i + 3]) for i in range(0, len(indices), 3)]  
                        
                      # create object to hold points  
                      obj = c4d.BaseObject(c4d.Opolygon)  
                      obj.SetName(mesh["name"])  
                      obj.ResizeObject(len(coords), len(faces))  
      
                      # add a UV tag to the object  
                      uvtag = c4d.UVWTag(len(faces))  
                      obj.InsertTag(uvtag)  
      
                      # add a normal tag to the object  
                      ntag = c4d.NormalTag(len(faces))  
                      obj.InsertTag(ntag)  
                        
                      # fill points into polygon object  
                      for i, v in enumerate(coords) :  
                          obj.SetPoint(i, c4d.Vector(v[0], v[1], v[2]))  
      
                      # fill trangles into polygon object and set UV coords  
                      for i, f in enumerate(faces) :  
                          obj.SetPolygon(i, c4d.CPolygon(f[0], f[1], f[2]))  
                          uvtag.SetSlow(i, c4d.Vector(uvs[f[0]][0], uvs[f[0]][1], 0),  
                                         c4d.Vector(uvs[f[1]][0], uvs[f[1]][1], 0),  
                                         c4d.Vector(uvs[f[2]][0], uvs[f[2]][1], 0),  
                                         c4d.Vector())  
                            HOW DO I SET NORMALS?   
                    
                      doc.InsertObject(obj)  
    

    With generous help for people here, I got pretty much all of it working, except how to set the normal vector for a polygon. The normal tag doesn't seem to have a way to set the normal (unlike the uvtag which has SetSlow)?



  • On 21/08/2017 at 12:11, xxxxxxxx wrote:

    Found this after a loooooong search... might be the solution to my problem (nasty)...

    https://plugincafe.maxon.net/topic/7713/9752_modifiying-the-normaltag



  • On 21/08/2017 at 12:22, xxxxxxxx wrote:

    Ok, that works... even if a bit convoluted...



  • On 22/08/2017 at 05:27, xxxxxxxx wrote:

    Here's an old, unfinished script that creates face weighted vertex normals.
    You find the method how to set vertex normals inside the main method.

        
        
        import c4d
        import math
        from c4d import utils
        
        
        # Calculate a polygons' face normal
        def CalcFaceNormal(op, polyIndex) :
            poly = op.GetPolygon(polyIndex)
        
        
            v0 = op.GetPoint(poly.a)
            v1 = op.GetPoint(poly.b) 
            v3 = op.GetPoint(poly.d) # point c==d, only 3 points needed to calculate a face normal
            
            return (v1 - v0).Cross(v3 - v0) # return cross product of point vectors
            
        # Calculate face area
        def CalculateFaceArea(op, polyIndex) :
            poly = op.GetPolygon(polyIndex)
            v0 = op.GetPoint(poly.a)
            v1 = op.GetPoint(poly.b)
            v2 = op.GetPoint(poly.c)
            v3 = op.GetPoint(poly.d)
            
            if poly.IsTriangle() :
                return (0.5 * ((v1-v0) % (v2-v0)).GetLength())
            else: # if quad
                return (0.5 * ((v1-v0) % (v2-v0))).GetLength() + (0.5 * ((v3-v2) % (v0-v2)).GetLength())
          
        
        
        # Calculate the face angle of the corner and shared edges
        def CalculateFaceAngle(op, polyIndex, point) :
            poly = op.GetPolygon(polyIndex)
        
        
            v0 = op.GetPoint(poly.a)
            v1 = op.GetPoint(poly.b)
            v3 = op.GetPoint(poly.d)
            
            fv0, fv1, fv3 = v0, v1, v3
            
            # TODO: Assemble shared triangles to quads
            
            if poly.IsTriangle() :
                if point == poly.b:
                    fv0 = v1
                    fv1 = v0
                    fv3 = v3
                    
                if point == poly.d:
                    fv0 = v3
                    fv1 = v1
                    fv3 = v0
                
            return utils.VectorAngle((fv0-fv3), (fv0-fv1))  
        
        
        # Calculate a point's average vertex normal, based on neighboring face normals
        def CalculateVertexNormal(op, pointIndex, polyIndex, nbr) :
            normal = c4d.Vector()
            nPolys = nbr.GetPointPolys(pointIndex) #get neighbor poly array
            
            for neighborPolyIndex in nPolys:
                normal = normal + CalcFaceNormal(op, neighborPolyIndex) * CalculateFaceArea(op, neighborPolyIndex) * CalculateFaceAngle(op, neighborPolyIndex, pointIndex) # add up neighbors normals
            
            return normal.GetNormalized() # normalized arithmetic middle of neighbored normals
        
        
        def main() :
            doc.StartUndo()
            nbr = utils.Neighbor() # involve neighbors
            
            tag = c4d.VariableTag(c4d.Tnormal, op.GetPolygonCount()) # create/override tag
            normals = [] # the HighLevelData Container (sequentially written vectors for each point component)
            
            nbr.Init(op)
            for polyIndex in xrange(op.GetPolygonCount()) :
                poly = op.GetPolygon(polyIndex)
                
                # Calculate vertex normal for each point
                pointIndexArray = [poly.a, poly.b, poly.c, poly.d] 
                
                for pointIndex in pointIndexArray: # append vectors sequentially split
                    vNorms = CalculateVertexNormal(op, pointIndex, polyIndex, nbr)
                    normals.append(vNorms.x*32000)
                    normals.append(vNorms.y*32000)
                    normals.append(vNorms.z*32000)
                    
            op.InsertTag(tag) # Apply tag
            tag.SetAllHighlevelData(normals) # write normal container to tag
            
            c4d.EventAdd()
            doc.AddUndo(c4d.UNDOTYPE_NEW, tag)
            
        
        
        if __name__=='__main__':
            main()
    


  • On 22/08/2017 at 06:10, xxxxxxxx wrote:

    Hi,

    just chiming in to add we are aware it is a bit cumbersome to add normals via Python. In C++ the NormalTag has some Get()/Set()/Copy() functions to ease the job. Unfortunately these are not yet available in Python.But at least I can say, we added them to our ToDo list.


Log in to reply