Add UV Coordinates to Polygon



  • On 19/08/2017 at 09:06, xxxxxxxx wrote:

    Hi all

    I'm reading and parsing a file (glTF JSON). It contains:
    A bunch of points: p1, p2, p3, p4, p5, .... (3d-Vectors)
    A bunch of UV coordinates: uv1, uv2, uv3, ... (2d-Vectors with values between 0 and 1)
    A bunch of materials: mat1, mat2, ... (bitmaps)
    A list of indices on how to assemble everything: 1, 2, 3,  1, 2, 4,  2, 3, 5, ...

    I can easily create the triangles from the points and indices.
    I can easily create the materials and assign them to the right triangles.

    What I can't figure out is:

    How do I assign UV coordinates to each point of a triangle?



  • On 19/08/2017 at 09:54, xxxxxxxx wrote:

    I made this gist for this purpose.
    https://gist.github.com/gr4ph0s/ebecaabcf90bbdd73a54124544e0b532

    Then ,you can set uv with point id with this simple function.

    tag_uvw = doc.GetActiveTag()
    if not tag_uvw:
        return
      
    uv_coord = c4d.Vector()
    pt_id = 1
    poly_id = 0
      
    // se the uv of the pt_id 1 for the poly_id 0
    set_uv(tag, pt_id, uv_coord, poly_id)
      
      
    // se the uv of the pt_id 1 for all poly_id
    set_uv(tag, pt_id, uv_coord)
    

    If you have any issue or any missunderstand in my code, don't hesite to told it, I will take time to comment.



  • On 19/08/2017 at 10:10, xxxxxxxx wrote:

    Hm... I don't get that gist... I would expect that I have to:
    1. Add a texture tag to the object
    2. Add UV coordinates to the vertices of the object

    Probably something like:

      
    indices = <a list of integers>  
    coords  = <a list of 3d vectors>  
    uvs     = <a list of 2d vectors> # same amount as coords  
    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))  
                        
    # 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  
    for i, f in enumerate(faces) :  
      obj.SetPolygon(i, c4d.CPolygon(f[0], f[1], f[2]))  
      
    # fill uv tex coordinates  
    tag = c4d.BaseTag(c4d.Tuvw)  
    obj.InsertTag(tag)  
    # loop to set uv coords... <- this is what I'm looking for...  
    


  • On 19/08/2017 at 10:11, xxxxxxxx wrote:

    Just saw your extended comment... will dive into that :)



  • On 19/08/2017 at 10:31, xxxxxxxx wrote:

    Even if in other software it work like you said, where uv_pt_id = mesh_pt_id is not the case in c4d.

    Actually uv_pt_id for c4d belong to pt_id INSIDE a c4d.Cpolygon(wich is a representation of a polygon with the following pt_id 0 ,1, 2 or 3 if quad). About ngon, in c4d there is wrapper about it but they didn't exist, understand them as polygon of 3/4 side melt together. So in all cases a polygon is always made from 3 or 4 points.

    My script allow you to use directly mesh_pt_id to uv_pt_id for set an uv point.
    I made this script after this question, this can maybe help you to have a better understanding of how uv are handle in the uvwtag.
    https://plugincafe.maxon.net/topic/435/13576_continuous-uv-solved&KW=



  • On 19/08/2017 at 10:36, xxxxxxxx wrote:

    Hm... it doesn't work...

    My guess is, that since the UV tag doesn't exist yet (I create it), your proposed solution breaks when doing the

    buffer_uv = tag.GetSlow(data["poly_id"])
    

    with an index out of bounds error...

    Here's what my code looks like right now:

      
    # add a texture tag to the object  
    tag = c4d.BaseTag(c4d.Tuvw)  
    obj.InsertTag(tag)  
      
      
    # 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]))  
      set_uv(tag, f[0], i, c4d.Vector(uvs[f[0]][0], uvs[f[0]][1], 0))  
      set_uv(tag, f[1], i, c4d.Vector(uvs[f[1]][0], uvs[f[1]][1], 0))  
      set_uv(tag, f[2], i, c4d.Vector(uvs[f[2]][0], uvs[f[2]][1], 0))  
      
    #print mesh["name"], len(coords), len(faces), len(uvs), len(indices)  
                    
    doc.InsertObject(obj)  
    obj.InsertUnder(root)  
    


  • On 19/08/2017 at 10:39, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Actually uv_pt_id for c4d belong to pt_id INSIDE a c4d.Cpolygon(wich is a representation of a polygon with the following pt_id 0 ,1, 2 or 3 if quad).

    So, since I know the point which are used to create the poly and the correct UV for them, I should basically be able to just set the UV coordinates of points 0-2, right?

    Question would then be, how do I do that ;)



  • On 19/08/2017 at 10:49, xxxxxxxx wrote:

    Ok, got it :)

    1. Make sure to create a UV Tag with enough "entries" to hold all polys
    2. Use SetSlow to directly set the UVs...

      
                      # add a texture tag to the object  
                      tag = c4d.UVWTag(len(faces))  
                      obj.InsertTag(tag)  
      
                      # 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]))  
                          tag.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())  
    


  • On 19/08/2017 at 11:34, xxxxxxxx wrote:

    Since I use neighboor to know which point id are shared with wich polygon id, my script is more a way for dealing with mesh that already exist. At least I think in this way when I builded it. So rry about that and forget it since you are in the creation.

    But regarding your question here is a litlle exemple wich create, 2 polygons with uv wich I hope will make more sense.

    import c4d
      
    #pt_id are correctly ordered
    points = [
        c4d.Vector(0, 0, 0),
        c4d.Vector(200, 0, 0),
        c4d.Vector(200, 0, 200),
        c4d.Vector(0, 0, 200),
        c4d.Vector(200, 100, 0),
        c4d.Vector(200, 100, 200)
    ]
      
    #uv_id are ordered like points and get same count than points
    uvs = [
        c4d.Vector(1, 1, 1),
        c4d.Vector(0.6, 1, 1),
        c4d.Vector(0.6, 0, 1),
        c4d.Vector(1, 0, 1),
        c4d.Vector(0, 1, 1),
        c4d.Vector(0, 0, 1)
    ]
      
    #hold pt_id
    polys = [
        [0 ,1, 2 ,3],
        [1, 2, 5 ,4]
    ]
        
    def main() :
        doc.StartUndo()
        
        nb_pts = len(points)
        nb_polys = len(polys)
        obj  = c4d.BaseObject(c4d.Opolygon)
        uv_tag = c4d.UVWTag(nb_polys)
      
        #Firstly we prepare our polygon object to store this amount of value
        obj.ResizeObject(nb_pts, nb_polys)
        
        #Then we build point I could use objet.SetAllPoints(points) 
        #    since my points list is already ordered
        for pt_id, pos in enumerate(points) :
            obj.SetPoint(pt_id, pos)
        
        #Then we define our polygon and our uv. 
        # UV belong to pt_id FROM polygon. That mean we need polygon ;)
        for poly_id, pt_ids in enumerate(polys) :
            poly = None
            #Handle triangle
            if len(pt_ids) > 3:
                poly = c4d.CPolygon(
                            pt_ids[0],
                            pt_ids[1],
                            pt_ids[2],
                            pt_ids[3]
                        )
            else:
                poly = c4d.CPolygon(
                            pt_ids[0],
                            pt_ids[1],
                            pt_ids[2],
                            pt_ids[2]
                        )
            
            obj.SetPolygon(poly_id, poly)
            
            #remember poly.a is pt_id. We use poly data since we already managed triangle before
            uv_tag.SetSlow(poly_id, uvs[poly.a], uvs[poly.b], uvs[poly.c], uvs[poly.d])
                
        
        obj.Message(c4d.MSG_UPDATE)
        
        doc.InsertObject(obj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, obj)
        
        obj.InsertTag(uv_tag)
        doc.AddUndo(c4d.UNDOTYPE_NEW, uv_tag)
        
        c4d.EventAdd()
        
        doc.EndUndo()
      
    if __name__=='__main__':
        main()
    


  • On 21/08/2017 at 03:26, xxxxxxxx wrote:

    Hi,

    For more information on UVWTag class see the UVWTag Manual of the C++ SDK docs and its documentation in the Python SDK docs.


Log in to reply