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.