# 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, v, v))

# fill trangles into polygon object
for i, f in enumerate(faces) :
obj.SetPolygon(i, c4d.CPolygon(f, f, f))

# 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, v, v))

# fill trangles into polygon object and set UV coords
for i, f in enumerate(faces) :
obj.SetPolygon(i, c4d.CPolygon(f, f, f))
set_uv(tag, f, i, c4d.Vector(uvs[f], uvs[f], 0))
set_uv(tag, f, i, c4d.Vector(uvs[f], uvs[f], 0))
set_uv(tag, f, i, c4d.Vector(uvs[f], uvs[f], 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, v, v))

# fill trangles into polygon object and set UV coords
for i, f in enumerate(faces) :
obj.SetPolygon(i, c4d.CPolygon(f, f, f))
tag.SetSlow(i, c4d.Vector(uvs[f], uvs[f], 0),
c4d.Vector(uvs[f], uvs[f], 0),
c4d.Vector(uvs[f], uvs[f], 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,
pt_ids,
pt_ids,
pt_ids
)
else:
poly = c4d.CPolygon(
pt_ids,
pt_ids,
pt_ids,
pt_ids
)

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)

obj.InsertTag(uv_tag)