C4D逆向细分插件:Python : Subdivision inverse(原版+汉化版)
Calcule une approximation de l'objet original subdivisé selon la méthode Catmull-Clark.
经测试,支持WIN/MAC r13-r16
v 1.1 :
- Correction d'un problème de rafraîchissement.
Copier le dossier « vonc_subdinv » dans le dossier « plugins » du répertoire de Cinéma 4D.
Le module utilise un point de départ pour traiter l'objet. Ce point doit être commun entre le modèle original et subdivisé. Par défaut, ce point est celui d'indice 0, mais il est possible de le changer manuellement, ou de sélectionner le ou les points de départ puis de cocher la case « Sélection » dans les paramètres du module. Cliquez sur le bouton « Act. » pour actualiser la sélection. à utiliser si vous obtenez des résultats bizarres.
Fichier vonc_subdinv.PYP :
- # Subdivision inverse - César Vonc - code.vonc.fr
- # v 1.1
- import os
- import c4d
- import webbrowser
- from c4d import plugins, utils, bitmaps, Vector
- from c4d.utils import Neighbor, VectorAngle
- MODULE_ID = 1029594
- VONC_SUBDINV_NOM = 1000
- VONC_SUBDINV_TYPE = 1000
- VONC_SUBDINV_TYPE_CC1 = 0
- VONC_SUBDINV_TYPE_CC2 = 1
- VONC_SUBDINV_TYPE_CC3 = 3
- VONC_SUBDINV_TYPE_CCA = 2
- VONC_SUBDINV_SUBD = 1002
- VONC_SUBDINV_DEPA = 1003
- VONC_SUBDINV_INFO = 1004
- VONC_SUBDINV_SELP = 1005
- VONC_SUBDINV_INVN = 1006
- VONC_SUBDINV_DON = 1007
- VONC_SUBDINV_ACTU = 1008
- class SubdivisionInverse() :
- obj = None
- doc = None
- obj_nbpts = 0
- obj_nbpol = 0
- obj_n = None
- pts_traites = []
- pol_traites = []
- nouv_polys = []
- pts_orig = []
- nouv_pts = []
- nouv_pts_inv = []
- nouv_coor = []
- pts_corres = []
- pol_corres = []
- cor_poly_polynet = [] # Correspondance [id nouv_polys] = id nouv_polys nettoyé
- cor_polynet_poly = [] # Correspondance [id nouv_polys nettoyé] = id nouv_polys
- _GetAllPolygons = []
- _GetPointPolys = []
-
- def _NettoieTab(self, tab) :
- tab_net = []
- j = 0
- i = 0
- for val in tab :
- if val and len(val) > 2 :
- tab_net.append(val)
- self.cor_poly_polynet.append(j)
- self.cor_polynet_poly.append(i)
- j += 1
- else : self.cor_poly_polynet.append(-1)
- i += 1
- return tab_net
-
- def _SommeVecteur(self, obj, vecs) :
- if not vecs : return Vector()
- s = Vector()
- for v in vecs :
- s += obj.GetPoint(v)
- return s
-
- def _MoyenneVecteur(self, obj, vecs) :
- q = len(vecs)
- if not q : return Vector()
- m = Vector()
- for v in vecs :
- m += obj.GetPoint(v)
- m /= float(q)
- return m
-
- def _RempliCoorArete(self, i, pa, ps, nb) :
- obj = self.obj
- n = self.obj_n
-
- for arete in pa :
- pass
-
- def _RempliCoor(self, i, pa, ps, nb, mode) :
- obj = self.obj
- Po = obj.GetPoint(i)
-
- if mode == 2 :
- self.nouv_coor[i] = Po
- return
-
- if nb < len(pa) : # Bordure
- n = self.obj_n
- pa_bor = []
- pa_nb = 0
- for arete in pa :
- if pa_nb == 2 : break
- a, b = n.GetEdgePolys(i, arete)
- if a == -1 or b == -1 :
- pa_bor.append(arete)
- pa_nb += 1
-
- Mpa = self._MoyenneVecteur(obj, pa_bor)
- pos = 2.0 * Po - Mpa
-
- elif nb == 3 :
- if mode == 0 :
- Mps = self._MoyenneVecteur(obj, ps)
- pos = Po + (Po - Mps) * 2.0
-
- elif mode == 1 or mode == 3 :
- # Calcul des coordonnées PA fictives
- Mpa = Vector()
- Mps = self._MoyenneVecteur(obj, ps)
- for arete in pa :
- if not self.nouv_coor[arete] :
- paA, psA, nbA = self._RecupPaPs(arete, False)
- if nbA == 3 : continue
- self._RempliCoor(arete, paA, psA, nbA, mode)
- Mpa += self.nouv_coor[arete]
- Mpa /= float(len(pa))
-
- pos = (Mpa-Po) * 2.0 + Po - (Po-Mps) * 0.75 #0.58335
-
- if mode == 3 :
- pos = (pos + Po + (Po - Mps) * 2.0) * 0.5
- #return (i, pa, ps, nb)
-
- else :
- Spa = self._SommeVecteur(obj, pa)
- Sps = self._SommeVecteur(obj, ps)
- pos = (Po*nb)/(nb-3.0) + (-4.0*Spa)/(nb*(nb-3.0)) + Sps/(nb*(nb-3.0))
-
- self.nouv_coor[i] = pos
-
-
- def _RempliPolys(self, i, pts_surf) :
- for p in pts_surf :
- poly = self.nouv_polys[p]
- if not poly : self.nouv_polys[p] = [i]
- else : self.nouv_polys[p].append(i)
-
- # Correspondance polys subdivisés > nouv polys
- pointpolys = self._GetPointPolys[p] #self.obj_n.GetPointPolys(p)
- for pointpoly in pointpolys :
- self.pol_corres[pointpoly] = p
-
- def _RecupPo(self, po, pa) :
- obj = self.obj
- n = self.obj_n
- pts_traites = self.pts_traites
- pol_traites = self.pol_traites
- pos = []
-
- for a in pa :
- polys = self._GetPointPolys[a] #n.GetPointPolys(a)
- points = []
-
- for pol in polys :
- if pol_traites[pol] : continue
- p = self._GetAllPolygons[pol] #obj.GetPolygon(pol)
- points.extend([p.a, p.b, p.c, p.d])
- pol_traites[pol] = True
- points = list(set(points))
-
- for pt in points :
- if pts_traites[pt] : continue
- arete = n.GetEdgePolys(a, pt)
- if arete != (-1, -1) :
- pos.append(pt)
- break
-
- return pos
-
- def _RecupPaPs(self, po, traiteur=True) :
- obj = self.obj
- n = self.obj_n
- pts_traites = self.pts_traites
- pol_traites = self.pol_traites
-
- polys = self._GetPointPolys[po] #n.GetPointPolys(po)
- nb = len(polys)
- points = []
- ps = []
- pa = []
-
- for p in polys :
- if traiteur : pol_traites[p] = True
- p = self._GetAllPolygons[p] #obj.GetPolygon(p)
- points.extend([p.a, p.b, p.c, p.d])
- points = list(set(points))
-
- for pt in points :
- if traiteur :
- self.pts_corres[pt].append(po)
- pts_traites[pt] = True
- if pt == po : continue
- arete = n.GetEdgePolys(po, pt)
- if arete == (-1, -1) :
- ps.append(pt)
- else :
- pa.append(pt)
-
- return pa, ps, nb
-
- def Execute(self, mode, depart, selp, invn) :
- if not self.Initialise(depart) : return
- obj = self.obj
- doc = self.doc
- n = self.obj_n
- pts_traites = self.pts_traites
- pts_orig = self.pts_orig
- nouv_pts = self.nouv_pts
- nouv_pts_inv = self.nouv_pts_inv
- nouv_polys = self.nouv_polys
- nouv_coor = self.nouv_coor
- _RecupPaPs = self._RecupPaPs
- _RecupPo = self._RecupPo
- _RempliPolys = self._RempliPolys
- _RempliCoor = self._RempliCoor
-
- bs = obj.GetPointS()
- pts_a_calc = []
-
- j = 0
- i_n = 0
- i_tot = 1
- for i in pts_orig : # Points de départ pour la recherche des Points Originaux
- i_n += 1
- i_p = 0
- if not pts_traites[i] : # Si le point n'a pas été traité
- pts_traites[i] = True
- # Récupère les points d'arête, de surface et le nombre de polys autour du point original
- pts_arete, pts_surf, nb_poly_cote = _RecupPaPs(i)
-
- # Calcule les nouvelles coordonnées du PO # ou renvoie a_calc pour les calculer plus tard
- _RempliCoor(i, pts_arete, pts_surf, nb_poly_cote, mode)
- # a_calc = _RempliCoor(i, pts_arete, pts_surf, nb_poly_cote, mode)
- # if a_calc : pts_a_calc.append(a_calc)
-
- # Ajoute PO aux futurs nouveaux polys
- _RempliPolys(i, pts_surf)
-
- # Récupère les points originaux aux alentours des points d'arête
- pts_orig_tour = _RecupPo(i, pts_arete)
- pts_orig.extend(pts_orig_tour)
-
- nouv_pts_inv[i] = j # Tableau [PO sur l'obj. subdivisé] = PO de l'obj. non subd.
- nouv_pts.append(i) # Liste des PO sur l'obj. subdivisé
-
- i_tot += len(pts_orig_tour)
- i_p = 1
- j += 1
-
- if i_n+i_p >= i_tot : # Si on atteint le bout de pts_orig
- if 0 in pts_traites : # S'il reste des points à traiter
- nouv_depart = pts_traites.index(0)
- pts_orig.append(nouv_depart) # Ajouter le non traité à traiter
- i_tot += 1
-
-
- ### -- Création de l'objet -- ###
-
- ### -- Récupération des propriétés et sélections -- ###
- proprietes = obj.GetTags()
- _Spolsels = []
- _Npolsels = []
- _Sptnsels = []
- _Nptnsels = []
- _Suvws = []
- _Nuvws = []
- for prop in proprietes :
- if prop.CheckType(c4d.Tpolygonselection) :
- _Npolsels.append(prop)
- _Spolsels.append(prop.GetClone())
- elif prop.CheckType(c4d.Tpointselection) :
- _Nptnsels.append(prop)
- _Sptnsels.append(prop.GetClone())
- elif prop.CheckType(c4d.Tuvw) :
- _Nuvws.append(prop)
- _Suvws.append(prop.GetClone())
- _ASptnsel = obj.GetPointS().GetClone()
- _ANptnsel = obj.GetPointS()
- _ASpolsel = obj.GetPolygonS().GetClone()
- _ANpolsel = obj.GetPolygonS()
-
- ### -- Création de l'objet -- ###
-
- nouv_polys_sale = nouv_polys[:]
- nouv_polys = self._NettoieTab(nouv_polys)
- nouv_nbpts = len(nouv_pts)
- nouv_nbpolys = len(nouv_polys)
-
- # objet = c4d.BaseObject(c4d.Opolygon)
- obj.ResizeObject(nouv_nbpts, nouv_nbpolys)
-
- for pti in xrange(nouv_nbpts) :
- ans_id = nouv_pts[pti]
- nouv_id = nouv_pts_inv[ans_id]
- position = nouv_coor[ans_id]
- obj.SetPoint(pti, position)
-
- posi = obj.GetPoint
- for poli in xrange(nouv_nbpolys) :
- poly = nouv_polys[poli]
- pa = nouv_pts_inv[poly[0]]
- pb = nouv_pts_inv[poly[1]]
- pd = nouv_pts_inv[poly[2]]
- if len(poly) != 3 :
- pc = nouv_pts_inv[poly[3]]
- posa = posi(pa)
- posb = posi(pb)
- posc = posi(pc)
- posd = posi(pd)
- vAB = posa - posb
- vAC = posa - posc
- vAD = posa - posd
- vBA = posb - posa
- vBC = posb - posc
- vCA = posc - posa
- vCD = posc - posd
- # Dénoue les polys si le point D est à l'ouest
- if VectorAngle(vCA, -vAD) < VectorAngle(vCA, -vAB) :
- if VectorAngle(vBA, -vAD) < VectorAngle(vBA, -vAC) :
- pc, pd = pd, pc
- else :
- if VectorAngle(vBC, -vCD) < VectorAngle(vBC, -vCA) :
- pa, pd = pd, pa
- else : pc = pd
-
- cpoly = c4d.CPolygon(pa, pb, pc, pd)
- obj.SetPolygon(poli, cpoly)
-
- obj.Message(c4d.MSG_UPDATE)
- commande = utils.SendModelingCommand(command = c4d.MCOMMAND_ALIGNNORMALS, list = [obj], doc = doc)
-
- if invn : commande = utils.SendModelingCommand(command = c4d.MCOMMAND_REVERSENORMALS, list = [obj], doc = doc)
-
- ### -- Modifs des propriétés -- #
-
- cor_polyS_polyN = [] # Correspondance [polys subdivisés] = nouveaux polys NETTOYé
- for _p in self.pol_corres : cor_polyS_polyN.append(self.cor_poly_polynet[_p])
-
- for _i, _Npolsel in enumerate(_Npolsels) : # Sélection de polygones
- _Spolsel = _Spolsels[_i]
- _Sbs = _Spolsel.GetBaseSelect()
- _Nbs = _Npolsel.GetBaseSelect()
- _Nbs.DeselectAll()
- for i, sel in enumerate(_Sbs.GetAll(self.obj_nbpol)) :
- if not sel : continue
- _p = cor_polyS_polyN[i]
- if _p != -1 : _Nbs.Select(_p)
-
- for _i, _Nptnsel in enumerate(_Nptnsels) : # Sélection de points
- _Sptnsel = _Sptnsels[_i]
- _Sbs = _Sptnsel.GetBaseSelect()
- _Nbs = _Nptnsel.GetBaseSelect()
- _Nbs.DeselectAll()
- for i, sel in enumerate(_Sbs.GetAll(self.obj_nbpts)) :
- if not sel : continue
- _p = nouv_pts_inv[i]
- if _p != -1 and _p < self.obj_nbpts : _Nbs.Select(_p)
-
- _ANpolsel.DeselectAll() # Sélection de polygones active
- for i, sel in enumerate(_ASpolsel.GetAll(self.obj_nbpol)) :
- if not sel : continue
- _p = cor_polyS_polyN[i]
- if _p != -1 : _ANpolsel.Select(_p)
-
- _ANptnsel.DeselectAll() # Sélection de points active
- for i, sel in enumerate(_ASptnsel.GetAll(self.obj_nbpts)) :
- if not sel : continue
- _p = nouv_pts_inv[i]
- if _p != -1 and _p < self.obj_nbpts : _ANptnsel.Select(_p)
-
-
- for _i, _Nuvw in enumerate(_Nuvws) : # UVW
- _Suvw = _Suvws[_i]
- for i in xrange(_Nuvw.GetDataCount()):
-
- k = self.cor_polynet_poly[i]
- polys = self._GetPointPolys[k]
- # points = nouv_polys[i]
- points = []
- Npoly = obj.GetPolygon(i)
- points.append(nouv_pts[Npoly.a])
- points.append(nouv_pts[Npoly.b])
- points.append(nouv_pts[Npoly.c])
- points.append(nouv_pts[Npoly.d])
-
- abcd = [Vector(), Vector(), Vector(), Vector()]
- for poly in polys :
- pol = self._GetAllPolygons[poly]
- for j, pt in enumerate(points) :
- if pol.a == pt :
- abcd[j] = _Suvw.GetSlow(poly)["a"]
- break
- elif pol.b == pt :
- abcd[j] = _Suvw.GetSlow(poly)["b"]
- break
- elif pol.c == pt :
- abcd[j] = _Suvw.GetSlow(poly)["c"]
- break
- elif pol.d == pt :
- abcd[j] = _Suvw.GetSlow(poly)["d"]
- break
-
- _Nuvw.SetSlow(i, abcd[0], abcd[1], abcd[2], abcd[3])
-
- # c4d.EventAdd()
-
- def Initialise(self, depart) :
- if not self.obj : return
- if not self.doc : return
- obj = self.obj
- if not obj.CheckType(c4d.Opolygon) : return
- self.obj_nbpts = obj.GetPointCount()
- self.obj_nbpol = obj.GetPolygonCount()
- if not self.obj_nbpts or not self.obj_nbpol : return
- self.obj_n = Neighbor()
- self.obj_n.Init(obj)
- self.pts_orig = depart
- self.pts_traites = [False] * self.obj_nbpts
- self.pol_traites = [False] * self.obj_nbpol
- self.nouv_polys = [0] * self.obj_nbpts
- self.nouv_pts = []
- self.nouv_pts_inv = [-1] * self.obj_nbpts
- self.nouv_coor = [0] * self.obj_nbpts
- self.pol_corres = [0] * self.obj_nbpol
- self.pts_corres = [[] for a in range(self.obj_nbpts)]
- self.cor_poly_polynet = []
- self.cor_polynet_poly = []
- self._GetAllPolygons = obj.GetAllPolygons()
- self._GetPointPolys = []
- for i in xrange(self.obj_nbpts) : self._GetPointPolys.append(self.obj_n.GetPointPolys(i))
- return True
-
- def __init__(self, doc, obj) :
- self.obj = obj
- self.doc = doc
- class SubdivisionInverseObjet(c4d.plugins.ObjectData):
- subdinv = None
- type = 0
- subd = 1
- depa = 0
- selp = False
- invn = False
-
- def Message(self, node, type, data) :
- if type == c4d.MSG_MENUPREPARE :
- node.SetDeformMode(True)
-
- if type == c4d.MSG_DESCRIPTION_COMMAND :
- id = data['id'][0].id
- if id == VONC_SUBDINV_DON : webbrowser.open("http://code.vonc.fr/", 2, True)
- elif id == VONC_SUBDINV_ACTU : node.SetDirty(c4d.DIRTY_DATA)
-
- return True
-
-
- def Init(self, op) :
- donnees = op.GetDataInstance()
- self.InitAttr(op, int, [VONC_SUBDINV_TYPE])
- self.InitAttr(op, int, [VONC_SUBDINV_SUBD])
- self.InitAttr(op, int, [VONC_SUBDINV_DEPA])
- self.InitAttr(op, bool, [VONC_SUBDINV_SELP])
- self.InitAttr(op, bool, [VONC_SUBDINV_INVN])
- op[VONC_SUBDINV_TYPE] = self.type
- op[VONC_SUBDINV_SUBD] = self.subd
- op[VONC_SUBDINV_DEPA] = self.depa
- op[VONC_SUBDINV_SELP] = self.selp
- op[VONC_SUBDINV_INVN] = self.invn
- return True
-
- def ModifyObject(self, mod, doc, op, op_mg, mod_mg, lod, flags, thread):
- if not op.CheckType(c4d.Opolygon) : return True
- if not op.GetPointCount() : return True
- if not op.GetPolygonCount() : return True
-
- self.type = mod[VONC_SUBDINV_TYPE]
- self.subd = mod[VONC_SUBDINV_SUBD]
- self.depa = mod[VONC_SUBDINV_DEPA]
- self.selp = mod[VONC_SUBDINV_SELP]
- self.invn = mod[VONC_SUBDINV_INVN]
- self.subdinv = SubdivisionInverse(doc, op)
-
- for k in xrange(self.subd) :
- nbp = op.GetPointCount()
- depart = [self.depa % nbp]
- if self.selp :
- depart = []
- bs = op.GetPointS()
- for i, sel in enumerate(bs.GetAll(nbp)) :
- if not sel : continue
- depart.append(i)
- if not depart : depart = [0]
-
- self.subdinv.Execute(self.type, depart, self.selp, self.invn)
-
- return True
-
- if __name__ == "__main__":
- bmp = bitmaps.BaseBitmap()
- dir, f = os.path.split(__file__)
- fn = os.path.join(dir, "res", "vonc_subdinv.tif")
- bmp.InitWith(fn)
- c4d.plugins.RegisterObjectPlugin(id=MODULE_ID, str=c4d.plugins.GeLoadString(VONC_SUBDINV_NOM),
- g=SubdivisionInverseObjet,
- description="vonc_subdinv",
- icon=bmp,
- info=c4d.OBJECT_MODIFIER)
复制代码 Fichier c4d_symbols.H :
- enum
- {
- VONC_SUBDINV_NOM = 1000,
-
- _DUMMY_ELEMENT_
- };
复制代码 Fichier vonc_subdinv.H :
- #ifndef _vonc_subdinv_H_
- #define _vonc_subdinv_H_
- enum
- {
- VONC_SUBDINV_TYPE = 1000,
- VONC_SUBDINV_TYPE_CC1 = 0,
- VONC_SUBDINV_TYPE_CC2 = 1,
- VONC_SUBDINV_TYPE_CC3 = 3,
- VONC_SUBDINV_TYPE_CCA = 2,
- VONC_SUBDINV_SUBD = 1002,
- VONC_SUBDINV_DEPA = 1003,
- VONC_SUBDINV_INFO = 1004,
- VONC_SUBDINV_SELP = 1005,
- VONC_SUBDINV_INVN = 1006,
- VONC_SUBDINV_DON = 1007,
- VONC_SUBDINV_ACTU = 1008
- };
- #endif
复制代码
Fichier vonc_subdinv.RES :
- CONTAINER vonc_subdinv
- {
- NAME vonc_subdinv;
- INCLUDE Obase;
- GROUP ID_OBJECTPROPERTIES
- {
- LONG VONC_SUBDINV_TYPE
- {
- CYCLE
- {
- VONC_SUBDINV_TYPE_CC1;
- VONC_SUBDINV_TYPE_CC2;
- VONC_SUBDINV_TYPE_CC3;
- VONC_SUBDINV_TYPE_CCA;
- }
- FIT_H;
- }
- LONG VONC_SUBDINV_SUBD { MIN 0; }
-
- GROUP {
- COLUMNS 3;
- LONG VONC_SUBDINV_DEPA { MIN 0; }
- BOOL VONC_SUBDINV_SELP { }
- BUTTON VONC_SUBDINV_ACTU { }
- }
- BOOL VONC_SUBDINV_INVN { }
-
- SEPARATOR { LINE; }
-
- GROUP {
- STATICTEXT VONC_SUBDINV_INFO { }
- BUTTON VONC_SUBDINV_DON { }
- }
- }
- }
复制代码 Fichier c4d_strings.STR :
- STRINGTABLE
- {
- VONC_SUBDINV_NOM "Subdivision inverse";
- }
复制代码 Fichier vonc_subdinv.STR :
- STRINGTABLE vonc_subdinv
- {
- vonc_subdinv "Subdivision inverse";
-
- VONC_SUBDINV_TYPE "Type";
- VONC_SUBDINV_TYPE_CC1 "Catmull-Clark (estimation 1)";
- VONC_SUBDINV_TYPE_CC2 "Catmull-Clark (estimation 2)";
- VONC_SUBDINV_TYPE_CC3 "Catmull-Clark (estimation 3)";
- VONC_SUBDINV_TYPE_CCA "Catmull-Clark (adoucie)";
- VONC_SUBDINV_SUBD "Subdivisions";
- VONC_SUBDINV_DEPA "Point de d\u00E9part";
- VONC_SUBDINV_INFO "v 1.1 - C\u00E9sar Vonc - http://code.vonc.fr";
- VONC_SUBDINV_SELP "S\u00E9lection";
- VONC_SUBDINV_INVN "Inverser les normales";
- VONC_SUBDINV_DON "Faire un don";
- VONC_SUBDINV_ACTU "Act.";
- }
复制代码
|
|