Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Setting Normals

    PYTHON Development
    0
    5
    851
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      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)?

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

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

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

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

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

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

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

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            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()
            
            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              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.

              1 Reply Last reply Reply Quote 0
              • First post
                Last post