Best way to get vertices from a point



  • On 05/12/2017 at 03:04, xxxxxxxx wrote:

    I'm looking for a "best-practice" approach to this problem. I need to read out an object and convert it to its vertex positions (not point positions! vertices.). As for the why: this appears to be the only way to retain UV coordinates for each vertex (using points' UVs will cause issues because a point is shared between multiple polygons, usually). So far it looks like making it editable and calling Disconnect on it seems like the only way to do this - however I was wondering whether there might be a more elegant solution whereby I could get the vertices per point?

    Cheers
    Michael



  • On 05/12/2017 at 04:10, xxxxxxxx wrote:

    For some understanding purpose, and to be sure we talk about the same.

    Polygon is define by his edge.

    Edge is 2 Vertexs.

    c4d.CPolygon actually represent a polygon.
    c4d.CPolygon get in maximum 4 points (a, b, c, d) if it's triangle c and d are egual.
    c4d.CPolygon vertex (a,b,c,d presented in the last sentence) are VertexID
    c4d.PolygonObject inherite from c4d.PointObject
    VertexID are shared accross the PointObject
    UVVertexID are shared accross CPolygon

    To get position of a specific point you have to do

    #op is c4d.PolygonObject
    localPointPos = op.GetPoint(0) # Get the local position of the VertexID 0
    globalPointPos = op.GetPoint(0) * op.GetMg() # Get the world position of the VertexID 0
    

    If you want to go from PolygonID to VertexID

    #op is c4d.PolygonObject
    poly = op.GetPolygon(0) #Get the c4d.CPolygon with the polygonID 0
    localPointPos = op.GetPoint(poly.a) # Get the local position of the first VertexID inside CPolygon (called Cpolygon.a)
    

    About UV since they belong to CPolygon you have to use GetPointPolys to find all the shared CPolygon accross a given VertexID. Then for each CPolygon you have to iterate over (a,b,c,d) to get the desired VertexID. Then you have to move it using SetSlow.

    For more informations please read this script that allow you to set UVVertexID from VertexID (at least if I understand correctly your question).

    I hope it's andwerd your question.



  • On 05/12/2017 at 04:26, xxxxxxxx wrote:

    Hi,

    no, it's not quite it. I'm aware of all the steps to get UVs and Points from the geometry. The problem is that in Cinema all the points usually are treated as shared points. So if you have two polygons next to each other, their bordering points (on the same edge) are shared point IDs.

    1 - 2 - 3
    |    |    |
    4 - 5 - 6

    So you get CPolygon with 1245 and 2356. Now if you UV map a texture onto this, with a repeating UV for example, you end up with these UV coordinates for _each_ of the two polygons.

    (0,0) - (1,0)(0,0) - (1,0)
      |              |             |
    (0,1) - (1,1)(0,1) - (1,1)

    This results in point 2, for example, having two UVs: (1,0) (from the left polygon) and (0,0) from the right polygon.

    To properly handle this, you need to have two vertices (or more, depending on how many polygons share this point), where each vertex stores the position of the Point and also its individual UV (and normal).

    This is something that apparently is handled entirely internally in Cinema - my question now is, can I get this data through the means of the Python API somehow, without jumping through hoops for it (e.g. Make Editable, then Triangulate, the Disconnect (which may even screw up the normals?)).

    Michael



  • On 05/12/2017 at 05:04, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    To properly handle this, you need to have two vertices (or more, depending on how many polygons share this point), where each vertex stores the position of the Point and also its individual UV (and normal).

    It's actually the case since as said in my previous post, UVVertexID belong to CPolygon vertex(a,b,c,d). Maybe I missunderstand something about how you do your UV stuff but basicly here is a code that show you that you have 2 UVVertexID for VertexID 1 (2 in your schema, since ID start at 0 and not 1)

    import c4d
      
    def CreateObject() :
        obj  = c4d.BaseObject(c4d.Opolygon)
        
        points = [c4d.Vector(0, 0, -100), # Coordonnées des points
        c4d.Vector(0, 0, 0),
        c4d.Vector(0, 0, 100),
        c4d.Vector(100, 0, -100),
        c4d.Vector(100, 0, 0),
        c4d.Vector(100, 0, 100)]
        
        polys = [c4d.CPolygon(0, 1, 4, 3), # Points ABCD du polygone
        c4d.CPolygon(1, 2, 5, 4)]
        
        obj.ResizeObject(len(points), len(polys))
        
        obj.SetAllPoints(points)
        
        for i, p in enumerate(polys) :
            obj.SetPolygon(i, p)
        
        obj.Message(c4d.MSG_UPDATE)
        doc.InsertObject(obj)
        
        return obj
      
    def CreateUVTag(obj) :
        tag = c4d.UVWTag(obj.GetPolygonCount())
        obj.InsertTag(tag)
        
        return tag
        
    def main() :
        obj = CreateObject()
        if not obj: return
        
        uvTag = CreateUVTag(obj)
        if not uvTag: return
        
        # Now everything is setup, let's change VertexID 1 (2 in your schema, since ID start at 0 and not 1)
        nbr = c4d.utils.Neighbor()
        nbr.Init(obj)
        
        polys = nbr.GetPointPolys(1) # Get all the PolygonID shared with vertexID 1
        polys_data = obj.GetAllPolygons()
        
        # Loop for each CPolygon and add to list_id, the PolygonID["poly_id"], and the actual CPolygon vertex ID (a,b,c,d are mapped to 0,1,2,3)["pt_num"]
        list_id = list()
        for poly_id in polys:
            poly = polys_data[poly_id]
            found_id = poly.Find(1) # here we search for want VertexID 1
            
            if found_id != c4d.NOTOK:
                buffer_data = dict()
                buffer_data["poly_id"] = poly_id
                buffer_data["pt_num"] = found_id
                
                list_id.append(buffer_data)
      
        # Now we get list of all Cpolygon with the corresponding (a,b,c,d) that are equal to VertexID 1
        for pt in list_id:
            buffer_uv = uvTag.GetSlow(pt["poly_id"])
            
            list_uv = [buffer_uv["a"],
                       buffer_uv["b"],
                       buffer_uv["c"],
                       buffer_uv["d"]]
                    
            # change the value only for the corresponding CPolygon vertexID look comment at line 48
            list_uv[pt["pt_num"]] = c4d.Vector(0.5, 0.0, 0.0)
            
            # Set the point where you want
            uvTag.SetSlow(pt["poly_id"],
                        list_uv[0],
                        list_uv[1],
                        list_uv[2],
                        list_uv[3]
                        )
            
        c4d.EventAdd()
      
    if __name__=='__main__':
        main()
    

    Please take a look at my script linked in my previous post

    But maybe I complettly missunderstand your question and someone else get it ! ;)



  • On 05/12/2017 at 05:17, xxxxxxxx wrote:

    No, it's not a complete misunderstanding, but it's not the result I'm looking for :)

    What I am looking for is simply a simple way to say "for Point X, return an Array of Vertices and their UVs" but I think it's just not there and I'll write my own.

    Thanks anyway :)



  • On 07/12/2017 at 14:06, xxxxxxxx wrote:

    Hi Michael, thanks for writing us.

    if I correctly understood your request, the following code should satisfy your need.

      
    import c4d  
      
    def main() :  
      obj = doc.GetActiveObject()  
        
      # check something is active  
      if obj is None:  
          print "No object selected"  
          return  
        
      # check the object to be an editable polygon object  
      if obj.GetType() != c4d.Opolygon:  
          print "Selected object is a generator, please make it editable"  
          return  
        
      # attempt to retrive a UVWTag  
      uvwTag = obj.GetTag(c4d.Tuvw)  
      if uvwTag is None:  
          print "uvwTag doesn't exists"  
          return  
        
      # attempt to access points and polygons lists  
      points = obj.GetAllPoints()  
      polygons = obj.GetAllPolygons()  
      if polygons is None or points is None:  
          print "points or polygons don't exist"  
          return  
        
      # store the polygons count  
      polyCnt = len(polygons)  
        
      # preallocate the list containing the final pos and uvw data  
      alldata = [None] * polyCnt  
        
      # loop through the polygons  
      for i in xrange(polyCnt) :  
          polygon = polygons[i]  
          # access the UVW data for the current polygon  
          uvwPolygon = uvwTag.GetSlow(i)  
          # check whatever the polygon has three or four vertices  
          if polygon.IsTriangle() :  
              # cycle over all the poiygon data and store in alldata  
              pos = points[polygon.a]  
              uvw = uvwPolygon["a"]  
              data = [[pos, uvw]]  
              pos = points[polygon.b]  
              uvw = uvwPolygon["b"]  
              data.append([pos, uvw])  
              pos = points[polygon.c]  
              uvw = uvwPolygon["c"]  
              data.append([pos, uvw])  
              alldata[i] = data  
          else:  
              pos = points[polygon.a]  
              uvw = uvwPolygon["a"]  
              data = [[pos, uvw]]  
              pos = points[polygon.b]  
              uvw = uvwPolygon["b"]  
              data.append([pos, uvw])  
              pos = points[polygon.c]  
              uvw = uvwPolygon["c"]  
              data.append([pos, uvw])  
              pos = points[polygon.d]  
              uvw = uvwPolygon["d"]  
              data.append([pos, uvw])  
              alldata[i] = data  
                
      # just print out to check the result  
      for j in xrange(len(alldata)) :  
          data = alldata[j]  
          print "Polygon["+str(j) +"]"  
          for k in xrange(len(data)) :  
              spacer = " ---> vtx [" + str (k) + "]"  
              posString = " pos:[" + str(data[k][0].x) + ", " + str(data[k][0].y) +", "+ str(data[k][0].z) + "]"   
              uvwString = " uvw:[" + str(data[k][1].x) + ", " + str(data[k][1].y) +", "+ str(data[k][1].z) + "]"   
              print spacer, posString, uvwString  
      
    if __name__=='__main__':  
      main()  
    

    Best, Riccardo


Log in to reply