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 CPolygonTo 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 - 6So 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