Liste der Anhänge anzeigen (Anzahl: 1)
Topologie vereinheitlichen
Hallo,
vielleicht hat mir ja einer von euch einen passenden Tipp.
Folgendes Problem:
[Only registered and activated users can see links. Click Here To Register...]
Ich habe hier drei Meshes von Köpfen vorliegen, welche rein optisch identische Topologien aufweisen. Leider stimmen aber deren Punkt-, resp. Polygonstrukturen nicht überrein. Punkt x liegt nicht bei allen Meshes an der gleichen 'Stelle' in bezug auf das Mesh, Polygon y besteht je nach Kopf aus unterschiedlichen Punktindices.
Das wäre aber mein Ziel, denn nur so können die Köpfe z.B. untereinander gemorpht werden.
Gibt es in C4D einen Funktion/einen Workflow, um dies zu erreichen?
Nur ungern würde ich dies manuell durch 'snappen' der Punkte eines Meshes auf die anderen erreichen, da es durchaus vorkommen könnte, dies noch öfters machen zu müssen.
Grüße
Peter
Liste der Anhänge anzeigen (Anzahl: 1)
So, dann melde ich mich mal wieder zurück.
Habe mir in der Zwischenzeit ein Skript zusammengestrickt, welches mir die Punkt- und Polygonreihenfolgen eines Objektes an ein topologisch identes Objekt anpasst.
[Only registered and activated users can see links. Click Here To Register...]
Bei den im eingefügten Bild sichtbaren Meshs übernimmt Mesh 'A' z.B. die Nummerierung der Punkte und Polygone von Mesh 'B'.
Auch wenn das Skript für den 'Hausgebrauch' erstellt wurde, so hänge ich trotzdem hier mal den Code an.
Beschreibung und Bedienungsanleitung ist im Skript zu finden.
Vielleicht probiert der Eine oder Andere das Skript ja netterweise aus und gibt eine kurze Rückmeldung, ob es auch erwartungsgemäß funktioniert.
Code:
import c4d
from c4d import gui
polygons_calculated = 0
"""
--------------------------------------------------------------------------------------
Skript zum Synchronisieren der Punkt- und Polygonindizes
von zwei Polygonobjekten mit identischer Topologie aber unterschiedlicher Punkt- und
Polygonreihenfolgen.
--------------------------------------------------------------------------------------
v01-01:
Korrektur im Algorithmus für die Markierung der abzuarbeitenden Polygone. Fälschlicherweise
wurden Polygone mehrfach markiert. Nach einer entsprechenden Anpassung ist das Skript nun
um ein vielfaches schneller.
Peter Notz (nophoto)
2017-10-16
Nach dem Ausführen des Skripten sind die Punkt- und Polygonstrukturen der beiden
Objekte identisch.
Bedienung:
----------
Sowohl im zu bearbeitenden, als auch im Referenzobjekt muss jeweils genau ein Polygon
und ein Punkt ausgewählt sein.
Wobei im Referenzobjekt das dem im zu bearbeitenden Objekte selektierten Polygon topo-
logisch entsprechende Polygon selektiert sein muss.
Die selektierten Punkte müssen sich ebenfalls topologisch entsprechen und zusätzlich zu
den selektierten Polygonen gehören.
Zusätzlich müssen beide Objekte im Objektmanager ausgewählt sein. Die Reihenfolge der
Auswahl bestimmt, welches der Objekte bearbeitet wird und welches als Referenzobjekt
dient. Das als erstes ausgewählte Objekt wird bearbeitet, das zweite dient als Referenz.
Bedingungen:
------------
Die Polygonobjekte dürfen keine Ngons enthälten. Dreiecke sind jedoch erlaubt.
Die Normalen müssen ausgerichtet und bei beiden Objekten in die gleiche Richtung zeigen.
Die Objekte sollten 'Optimiert' sein.
Die Objekte dürfen nur aus einem zusammenhängenden Bereich bestehen.
Bemerkung:
----------
Die Übereinstimmung der Topologie der beiden Objekte wird durch das Skript nicht überprüft.
Ebenso wird auch die Plausibilität der nötigen Punkt-, Polygon- und Objektauswahlen nicht
geprüft.
Der Code ist nicht optimiert und soll auch keineswegs als Beispiel für einen guten Programmier-
stil dienen.
Es ging lediglich darum, ein funktionierendes Skript zu erstellen. Ebenso ist die Kommentierung
noch sehr lückenhaft.
"""
def GetRefPolypoints(o_src, i_srcpoly, i_srcpoint, o_ref, i_refpoly, i_refpoint):
srcpoly = o_src.GetPolygon(i_srcpoly)
src_vertexnum = srcpoly.Find(i_srcpoint)
refpoly = o_ref.GetPolygon(i_refpoly)
ref_vertexnum = refpoly.Find(i_refpoint)
polygonvertices = [refpoly.a, refpoly.b, refpoly.c, refpoly.d]
if refpoly.c != refpoly.d: # Es handelt sich um ein Quad
offset = (ref_vertexnum - src_vertexnum)%4
if offset == 0:
return refpoly.a, refpoly.b, refpoly.c, refpoly.d
elif offset == 1:
return refpoly.b, refpoly.c, refpoly.d, refpoly.a
elif offset == 2:
return refpoly.c, refpoly.d, refpoly.a, refpoly.b
elif offset == 3:
return refpoly.d, refpoly.a, refpoly.b, refpoly.c
else: # Es handelt sich um ein Tri
if src_vertexnum == 0:
if ref_vertexnum == 0:
return refpoly.a, refpoly.b, refpoly.c, refpoly.c
elif ref_vertexnum == 1:
return refpoly.b, refpoly.c, refpoly.a, refpoly.a
else:
return refpoly.c, refpoly.a, refpoly.b, refpoly.b
elif src_vertexnum == 1:
if ref_vertexnum == 0:
return refpoly.c, refpoly.a, refpoly.b, refpoly.b
elif ref_vertexnum == 1:
return refpoly.a, refpoly.b, refpoly.c, refpoly.c
else:
return refpoly.b, refpoly.c, refpoly.a, refpoly.a
else:
if ref_vertexnum == 0:
return refpoly.b, refpoly.c, refpoly.a, refpoly.a
elif ref_vertexnum == 1:
return refpoly.c, refpoly.a, refpoly.b, refpoly.b
else:
return refpoly.a, refpoly.b, refpoly.c, refpoly.c
def main():
global polygons_calculated
#c4d.CallCommand(13957, 13957) # Clear Console
osel = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER | c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if len(osel) != 2: return
o_src = osel[0] # Objekt
o_ref = osel[1] # Referenz-Objekt
#print "Objekte definiert"
src_pointcount = o_src.GetPointCount()
src_polygoncount = o_src.GetPolygonCount()
ref_pointcount = o_ref.GetPointCount()
ref_polygoncount = o_ref.GetPolygonCount()
point_map = [-1]*src_pointcount
polygon_map = [-1]*src_polygoncount
""" Vorbereiten der Startauswahl """
src_bs_point = o_src.GetPointS()
if src_bs_point.GetCount() != 1: return
src_pointsel = src_bs_point.GetAll(src_pointcount)
i_src_point = src_pointsel.index(1)
#print "src_pointsel:", i_src_point
src_bs_polygon = o_src.GetPolygonS()
if src_bs_polygon.GetCount() != 1: return
src_polygonsel = src_bs_polygon.GetAll(src_polygoncount)
i_src_polygon = src_polygonsel.index(1)
#print "src_polygonsel:", i_src_polygon
ref_bs_point = o_ref.GetPointS()
if ref_bs_point.GetCount() != 1: return
ref_pointsel = ref_bs_point.GetAll(ref_pointcount)
i_ref_point = ref_pointsel.index(1)
#print "ref_pointsel:", i_ref_point
ref_bs_polygon = o_ref.GetPolygonS()
if ref_bs_polygon.GetCount() != 1: return
ref_polygonsel = ref_bs_polygon.GetAll(ref_polygoncount)
i_ref_polygon = ref_polygonsel.index(1)
#print "ref_polygonsel:", i_ref_polygon
""" Definieren der Liste mit den markierten Polygonen """
mark = []
mark.append({"src_pt": i_src_point, "src_pg": i_src_polygon, "ref_pt": i_ref_point, "ref_pg": i_ref_polygon})
""" Anlegen der Neighbor-Klassen """
src_nbr = c4d.utils.Neighbor()
src_nbr.Init(o_src)
ref_nbr = c4d.utils.Neighbor()
ref_nbr.Init(o_ref)
""" Abarbeiten der Topologie """
while len(mark) > 0:
#print "Anzahl der markierten Polygone:", len(mark)
#print mark
# Bestimmen der korrespondierenden Punktvertices des aktuellen Polygons...
m = mark.pop(0)
res = GetRefPolypoints(o_src, m["src_pg"], m["src_pt"], o_ref, m["ref_pg"], m["ref_pt"])
vadr = o_src.GetPolygon(m["src_pg"])
point_map[vadr.a] = res[0]
point_map[vadr.b] = res[1]
point_map[vadr.c] = res[2]
point_map[vadr.d] = res[3]
polygon_map[m["src_pg"]] = m["ref_pg"]
polygons_calculated += 1
# Bestimmen der benachbarten Polygone und ablegen dieser in der 'mark'-Liste...
if vadr.c != vadr.d: # Quad...
src = src_nbr.GetNeighbor(vadr.a, vadr.b, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.a], point_map[vadr.b], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.a, "src_pg": src, "ref_pt": point_map[vadr.a], "ref_pg": ref})
src = src_nbr.GetNeighbor(vadr.b, vadr.c, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.b], point_map[vadr.c], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.b, "src_pg": src, "ref_pt": point_map[vadr.b], "ref_pg": ref})
src = src_nbr.GetNeighbor(vadr.c, vadr.d, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.c], point_map[vadr.d], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.c, "src_pg": src, "ref_pt": point_map[vadr.c], "ref_pg": ref})
src = src_nbr.GetNeighbor(vadr.d, vadr.a, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.d], point_map[vadr.a], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.d, "src_pg": src, "ref_pt": point_map[vadr.d], "ref_pg": ref})
else: # Tri...
src = src_nbr.GetNeighbor(vadr.a, vadr.b, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.a], point_map[vadr.b], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.a, "src_pg": src, "ref_pt": point_map[vadr.a], "ref_pg": ref})
src = src_nbr.GetNeighbor(vadr.b, vadr.c, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.b], point_map[vadr.c], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.b, "src_pg": src, "ref_pt": point_map[vadr.b], "ref_pg": ref})
src = src_nbr.GetNeighbor(vadr.c, vadr.a, m["src_pg"])
ref = ref_nbr.GetNeighbor(point_map[vadr.c], point_map[vadr.a], m["ref_pg"])
if src >= 0 and polygon_map[src] == -1:
polygon_map[src] = -2
mark.append({"src_pt": vadr.c, "src_pg": src, "ref_pt": point_map[vadr.c], "ref_pg": ref})
#print point_map
#print polygon_map
doc.StartUndo()
doc.AddUndo(c4d.UNDOTYPE_CHANGE, o_src)
points = o_src.GetAllPoints()
ref_tpolygon = o_ref.GetTag(c4d.Tpolygon)
if ref_tpolygon:
src_tpolygon = ref_tpolygon.GetClone()
for i in xrange(o_src.GetPointCount()):
o_src.SetPoint(point_map[i], points[i])
o_src.InsertTag(src_tpolygon)
o_src.Message(c4d.MSG_UPDATE)
doc.EndUndo()
c4d.EventAdd()
#print "polygons_calculated", polygons_calculated
if __name__=='__main__':
main()
Grüße
Peter