Code Vonc

ProjUV

v 1.2

R13+ OSX Win

TéléchargerDownload
Faire un donMake a donation
Comment installer ?How to install ?
CommentairesComments

Projette le dépliage UV d'un objet sur un autre.

L'outil se présente sous la forme d'une propriété à appliquer sur l'objet à texturer.

L'utilisation d'une même projection sur deux modèles différents permet de les texturer de la même façon malgré leur différence de maillage.

v 1.2 :
- Correction de l'absence de rafraîchissement sous l'OpenGL.

v 1.1.5 :
- Modèle de projection d'exemple modifié.

v 1.1 :
- Les polygones affectés par la projection sont enregistrés.
- Correction d'une faute de frappe dans le menu.


Fichier d'exemple : Télécharger

Copier le dossier « vonc_projuv » dans le dossier « plugins » du répertoire de Cinéma 4D.

Projects the UV layout of an object to another.

The tool is a tag to apply on the object to texture.

The use of a single UV projection on two different models allows texturing in the same way despite their difference mesh.

v 1.2 :
- Fixed the lack of refreshment on OpenGL.

v 1.15 :
- Modified example of projection model.

v 1.1 :
- Polygons affected by the projection are saved to a selection.
- Fixed a typo in the menu.


Example file : Télécharger

Copy the « vonc_projuv » folder to the « plugins » folder of Cinema 4D.









Codes sourcesSources code

res/c4d_symbols.h

enum
{
    // End of symbol definition
    _DUMMY_ELEMENT_
};

res/description/vonc_projuv.h

#ifndef _vonc_projuv_H_
#define _vonc_projuv_H_

enum
{
	VONCPROJUV_MAJAUTO	= 1000,
	VONCPROJUV_OBJ		= 1001,
	VONCPROJUV_UVW		= 1002,
	VONCPROJUV_SEL		= 1003,
	VONCPROJUV_ACTU		= 1004,
	VONCPROJUV_PLAN		= 1005,
	VONCPROJUV_INVNOR	= 1006,
	VONCPROJUV_INFO		= 1007,
	VONCPROJUV_AFF		= 1008
}

#endif

res/description/vonc_projuv.res

CONTAINER vonc_projuv
{
	NAME VONCPROJUV_TITRE;
	INCLUDE Texpression;
	
	GROUP ID_TAGPROPERTIES
	{
		GROUP {
			BUTTON VONCPROJUV_PLAN { }
		}
		SEPARATOR { LINE; }
		GROUP {
			LINK VONCPROJUV_OBJ { ACCEPT { Obase; } }
			LINK VONCPROJUV_UVW { ACCEPT { Tuvw; } }
			LINK VONCPROJUV_AFF { ACCEPT { Tpolygonselection; } }
			LINK VONCPROJUV_SEL { ACCEPT { Tpolygonselection; } }
			BOOL VONCPROJUV_INVNOR { }
		}
		SEPARATOR { LINE; }
		GROUP {
			COLUMNS 2;
			BOOL VONCPROJUV_MAJAUTO { }
			BUTTON VONCPROJUV_ACTU { }
		}
		SEPARATOR { LINE; }
		GROUP {
			STATICTEXT VONCPROJUV_INFO { }
		}
	}
}

res/strings_fr/description/vonc_projuv.str

STRINGTABLE vonc_projuv
{
	VONCPROJUV_TITRE		"ProjUV";
	VONCPROJUV_MAJAUTO		"Mise \u00E0 jour auto";
	VONCPROJUV_ACTU			"Actualiser";
	VONCPROJUV_OBJ			"Projection";
	VONCPROJUV_UVW			"UVW";
	VONCPROJUV_SEL			"Limiter \u00E0 la s\u00E9lection";
	VONCPROJUV_AFF			"Polygones affect\u00E9s";
	VONCPROJUV_PLAN			"Cr\u00E9er une projection planaire modifiable";
	VONCPROJUV_INVNOR		"Inverser la direction";
	VONCPROJUV_INFO			"v 1.2 - C\u00E9sar Vonc - http://code.vonc.fr";
}

res/strings_us/description/vonc_projuv.str

STRINGTABLE vonc_projuv
{
	VONCPROJUV_TITRE		"ProjUV";
	VONCPROJUV_MAJAUTO		"Auto-update";
	VONCPROJUV_ACTU			"Refresh";
	VONCPROJUV_OBJ			"Projection";
	VONCPROJUV_UVW			"UVW";
	VONCPROJUV_SEL			"Limit to the selection";
	VONCPROJUV_AFF			"Polygons affected";
	VONCPROJUV_PLAN			"Create an editable planar projection";
	VONCPROJUV_INVNOR		"Invert the direction";
	VONCPROJUV_INFO			"v 1.2 - C\u00E9sar Vonc - http://code.vonc.fr";
}

vonc_projuv.pyp

# ProjUV - v 1.2 - vonc.fr

import os
import c4d
from c4d import bitmaps, plugins, utils, Vector
from c4d.utils import GeRayCollider, Neighbor

MODULE_ID = 1029370
VONCPROJUV_MAJAUTO = 1000
VONCPROJUV_OBJ = 1001
VONCPROJUV_UVW = 1002
VONCPROJUV_SEL = 1003
VONCPROJUV_ACTU = 1004
VONCPROJUV_PLAN = 1005
VONCPROJUV_INVNOR = 1006
VONCPROJUV_INFO = 1007
VONCPROJUV_AFF = 1008

class ProjUV(plugins.TagData):
	lienObj = None
	lienUVW = None
	lienSel = None
	lienAff = None
	majauto = False
	actuprio = False
	creerplan = False
	invnor = False
	
	def InitDonneeAff(self, donnees, obj) :
		if self.lienAff : return
		propAff = c4d.BaseTag(c4d.Tpolygonselection)
		propAff[c4d.ID_BASELIST_NAME] = "ProjUV Sel"
		obj.InsertTag(propAff)
		donnees.SetLink(VONCPROJUV_AFF, propAff)
		self.lienAff = propAff
	
	def InitDonneeUVW(self, donnees, obj) :
		if self.lienUVW : return
		propUVW = obj.GetTag(c4d.Tuvw)
		if propUVW :
			donnees.SetLink(VONCPROJUV_UVW, propUVW)
			self.lienUVW = propUVW
	
	def RecupDonnees(self, donnees, doc) :
		self.lienObj = donnees.GetLink(VONCPROJUV_OBJ, doc)
		self.lienUVW = donnees.GetLink(VONCPROJUV_UVW, doc)
		self.lienSel = donnees.GetLink(VONCPROJUV_SEL, doc)
		self.lienAff = donnees.GetLink(VONCPROJUV_AFF, doc)
		self.majauto = donnees.GetBool(VONCPROJUV_MAJAUTO)
		self.invnor = donnees.GetBool(VONCPROJUV_INVNOR)
	
	def Verifieur(self, obj, uvw, tex) :
		if self.actuprio :
			self.actuprio = False
			return True
		if not self.majauto : return False
		if not uvw or not tex : return False
		if not obj.CheckType(c4d.Opolygon) : return False
		if obj.IsDirty(c4d.DIRTY_MATRIX) : return True
		if obj.IsDirty(c4d.DIRTY_DATA) : return True
		texEtGosses = [tex]
		for o in texEtGosses :
			if o.IsDirty(c4d.DIRTY_DATA) or o.IsDirty(c4d.DIRTY_MATRIX) :
				return True
			texEtGosses.extend(o.GetChildren())
		
		return False
	
	def Applatisseur(self, o, doc) :
		if not o : return
		obj = utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[o], doc=doc)
		if not obj : return
		neutre = c4d.BaseObject(c4d.Onull)
		obj[0].InsertUnder(neutre)
		obj = utils.SendModelingCommand(command=c4d.MCOMMAND_JOIN, list=[neutre], doc=doc)
		if not obj : return
		utils.SendModelingCommand(command=c4d.MCOMMAND_TRIANGULATE, list=obj, doc=doc)
		if self.invnor :
			utils.SendModelingCommand(command=c4d.MCOMMAND_REVERSENORMALS, list=obj, doc=doc)
		return obj[0]
	
	def CalculNormaleEtUVW(self, o) :
		uvw = o.GetTag(c4d.Tuvw)
		if not uvw : return None, None
		polygones = o.GetAllPolygons()
		nbPoints = o.GetPointCount()
		normales = [Vector()] * nbPoints
		uvws = [Vector()] * nbPoints
		i = 0
		
		for poly in polygones :
			a = poly.a
			b = poly.b
			c = poly.c
			d = poly.d
			ap = o.GetPoint(a)
			bp = o.GetPoint(b)
			cp = o.GetPoint(c)
			dp = o.GetPoint(d)
			n = (ap - cp).Cross(bp - dp)
			normales[a] += n
			normales[b] += n
			normales[c] += n
			normales[d] += n
			uvwdict = uvw.GetSlow(i)
			uvws[a] = uvwdict["a"]
			uvws[b] = uvwdict["b"]
			uvws[c] = uvwdict["c"]
			uvws[d] = uvwdict["d"]
			
			i += 1
			
		return normales, uvws
	
	def CompleteNormales(self, n, obj, objNbPts, objNor, objNorBol) :
		for ip in xrange(objNbPts) :
			ipolys = n.GetPointPolys(ip)
			if not objNorBol[ip] : continue
			direc = objNor[ip]
			for ipoly in ipolys :
				poly = obj.GetPolygon(ipoly)
				a = poly.a
				b = poly.b
				c = poly.c
				d = poly.d
				if objNor[a] == Vector() : objNor[a] = direc
				if objNor[b] == Vector() : objNor[b] = direc
				if objNor[c] == Vector() : objNor[c] = direc
				if objNor[d] == Vector() : objNor[d] = direc
				objNorBol[a] = True
				objNorBol[b] = True
				objNorBol[c] = True
				objNorBol[d] = True
	
	def CreerProjPlanaire(self, doc, donnees) :
		self.creerplan = False
		bd = doc.GetActiveBaseDraw()
		cam = bd.GetSceneCamera(doc)
		mg = cam.GetMg() * c4d.utils.MatrixMove(c4d.Vector(0,0,300))
		
		hn = c4d.BaseObject(c4d.Osds)
		hn[c4d.SDSOBJECT_SUBDIVIDE_UV] = c4d.SDSOBJECT_SUBDIVIDE_UV_EDGE
		hn[c4d.SDSOBJECT_SUBEDITOR_CM] = 2
		hn[c4d.SDSOBJECT_SUBRAY_CM] = 2
		hn.SetMg(mg)
		plan = c4d.BaseObject(c4d.Oplane)
		plan[c4d.PRIM_PLANE_WIDTH] = 200
		plan[c4d.PRIM_PLANE_HEIGHT] = 200
		plan[c4d.PRIM_PLANE_SUBW] = 3
		plan[c4d.PRIM_PLANE_SUBH] = 3
		plan[c4d.PRIM_AXIS] = 4
		plan[c4d.ID_BASEOBJECT_USECOLOR] = 2
		plan[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1.0, 0.8, 0.0)
		aff = c4d.BaseTag(c4d.Tdisplay)
		aff[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE] = True
		aff[c4d.DISPLAYTAG_SDISPLAYMODE] = c4d.DISPLAYTAG_SDISPLAY_NOSHADING
		aff[c4d.DISPLAYTAG_WDISPLAYMODE] = c4d.DISPLAYTAG_WDISPLAY_ISOPARMS
		hn.InsertTag(aff)
		plan.InsertUnder(hn)
		res = utils.SendModelingCommand(command = c4d.MCOMMAND_MAKEEDITABLE, list = [plan], doc = doc)
		res[0].InsertUnder(hn)
		doc.InsertObject(hn)
		donnees.SetLink(VONCPROJUV_OBJ, hn)
	
	def Init(self, node):
		donnees = node.GetDataInstance()
		donnees.SetBool(VONCPROJUV_MAJAUTO, True)
		return True
	
	def Execute(self, tag, doc, op, bt, priority, flags):
		donnees = tag.GetDataInstance()
		if not donnees : return c4d.EXECUTIONRESULT_OK
		
		if self.creerplan : self.CreerProjPlanaire(doc, donnees)
		
		self.RecupDonnees(donnees, doc)
		self.InitDonneeUVW(donnees, op)
		self.InitDonneeAff(donnees, op)
		
		obj = op
		objPropUVW = self.lienUVW
		tex = self.lienObj
		selPolys = self.lienSel
		
		verif = self.Verifieur(obj, objPropUVW, tex)
		if not verif : return c4d.EXECUTIONRESULT_OK
		
		tex = self.Applatisseur(tex, doc)
		if not tex : return c4d.EXECUTIONRESULT_OK
		
		texNor, texUVW = self.CalculNormaleEtUVW(tex)
		if not texUVW : return c4d.EXECUTIONRESULT_OK
		
		texPts = tex.GetAllPoints()
		texMg = tex.GetMg()
		
		objNbPolys = obj.GetPolygonCount()
		objNbPts = obj.GetPointCount()
		objPts = obj.GetAllPoints()
		objMg = obj.GetMg()
		objIMg = ~objMg
		objUVW = [None] * objNbPts
		objNor = [Vector()] * objNbPts
		objNorBol = [False] * objNbPts
		
		bs = None
		objPtsSel = [False] * objNbPts
		if selPolys :
			bs = selPolys.GetBaseSelect()
			for index, sele in enumerate(bs.GetAll(objNbPolys)) :
				if not sele : continue
				poly = obj.GetPolygon(index)
				objPtsSel[poly.a] = True
				objPtsSel[poly.b] = True
				objPtsSel[poly.c] = True
				objPtsSel[poly.d] = True
		
		distance = (obj.GetRad() + obj.GetMp() + objMg.off  + (tex.GetRad() + tex.GetMp() + texMg.off)).GetLength()
		distance *= 2
		
		rayon = GeRayCollider()
		rayon.Init(obj)
		i = 0
		for pt in texPts :
			depart = objIMg.Mul(pt) + 0.0001
			direc = objIMg.MulV(texNor[i])
			#ajVec(depart, direc)
			coll = rayon.Intersect(depart, direc, distance)
			inter = rayon.GetNearestIntersection()
			
			if inter :
				pos = inter["hitpos"]
				poly = inter["face_id"]
				poly = obj.GetPolygon(poly)
				nor = direc.GetNormalized() * -1
				#ajVec(pos, direc)
				objNor[poly.a] += nor
				objNor[poly.b] += nor
				objNor[poly.c] += nor
				objNor[poly.d] += nor
				objNorBol[poly.a] = True
				objNorBol[poly.b] = True
				objNorBol[poly.c] = True
				objNorBol[poly.d] = True
			i += 1
		
		n = Neighbor()
		n.Init(obj)
		somme = sum(objNorBol)
		while somme != objNbPts :
			sommeAns = somme
			self.CompleteNormales(n, obj, objNbPts, objNor, objNorBol)
			somme = sum(objNorBol)
			if sommeAns == somme : break
		
		rayon.Init(tex)
		i = 0
		for pt in objPts :
			if bs :
				if not objPtsSel[i] :
					i += 1
					continue
			depart = objMg.Mul(pt) + 0.0001
			direc = objMg.MulV(objNor[i].GetNormalized())
			#ajVec(depart, direc)
			coll = rayon.Intersect(depart, direc, distance)
			inter = rayon.GetNearestIntersection()
			
			if inter :
				bc = inter['barrycoords']
				poly = inter["face_id"]
				poly = tex.GetPolygon(poly)
				a = poly.a
				b = poly.b
				c = poly.c
				objUVW[i] = texUVW[a]*bc.x + texUVW[b]*bc.y + texUVW[c]*bc.z
				
			i += 1
		
		#doc.AddUndo(c4d.UNDOTYPE_CHANGE, objPropUVW)
		
		objPolAff = self.lienAff.GetBaseSelect()
		objPolAff.DeselectAll()
		
		if bs :
			for index, sele in enumerate(bs.GetAll(objNbPolys)):
				if not sele : continue
				poly = obj.GetPolygon(index)
				a = objUVW[poly.a]
				b = objUVW[poly.b]
				c = objUVW[poly.c]
				d = objUVW[poly.d]
				if not a or not b or not c or not d : continue
				objPolAff.Select(index)
				objPropUVW.SetSlow(index, a, b, c, d)
		
		else :
			for j in xrange(obj.GetPolygonCount()) :
				poly = obj.GetPolygon(j)
				a = objUVW[poly.a]
				b = objUVW[poly.b]
				c = objUVW[poly.c]
				d = objUVW[poly.d]
				if not a or not b or not c or not d : continue
				objPolAff.Select(j)
				objPropUVW.SetSlow(j, a, b, c, d)
		
		#doc.EndUndo()
		#c4d.EventAdd()
		
		obj.Message(c4d.MSG_UPDATE)
		
		return c4d.EXECUTIONRESULT_OK
	
	def Message(self, op, type, donnees) :
		if type == c4d.MSG_DESCRIPTION_COMMAND :
			id = donnees["id"][0].id
			if id == VONCPROJUV_ACTU :
				self.actuprio = True
			elif id == VONCPROJUV_PLAN :
				self.creerplan = True
		return True

if __name__ == "__main__":
	bmp = bitmaps.BaseBitmap()
	dir, file = os.path.split(__file__)
	fn = os.path.join(dir, "res", "vonc_projuv.tif")
	bmp.InitWith(fn)
	plugins.RegisterTagPlugin(id=MODULE_ID, str="ProjUV",
							  info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE, g=ProjUV,
							  description="vonc_projuv", icon=bmp)