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.