link_containers.py 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850
  1. from .node_container_common import *
  2. from bpy.types import Node, Bone
  3. from .base_definitions import MantisNode, GraphError
  4. #TODO: get rid of this, it's unnecesary here, we always want to import
  5. # all classes in this file
  6. def TellClasses():
  7. return [
  8. # special
  9. LinkInherit,
  10. # copy
  11. LinkCopyLocation,
  12. LinkCopyRotation,
  13. LinkCopyScale,
  14. LinkCopyTransforms,
  15. LinkTransformation,
  16. # limit
  17. LinkLimitLocation,
  18. LinkLimitRotation,
  19. LinkLimitScale,
  20. LinkLimitDistance,
  21. # tracking
  22. LinkStretchTo,
  23. LinkDampedTrack,
  24. LinkLockedTrack,
  25. LinkTrackTo,
  26. #misc
  27. LinkInheritConstraint,
  28. LinkArmature,
  29. # IK
  30. LinkInverseKinematics,
  31. LinkSplineIK,
  32. # Drivers
  33. LinkDrivenParameter,
  34. ]
  35. def default_evaluate_input(nc, input_name):
  36. # should catch 'Target', 'Pole Target' and ArmatureConstraint targets, too
  37. if ('Target' in input_name) and input_name not in ["Target Space", "Use Target Z"]:
  38. socket = nc.inputs.get(input_name)
  39. if socket.is_linked:
  40. return socket.links[0].from_node
  41. return None
  42. else:
  43. return evaluate_input(nc, input_name)
  44. # def set_constraint_name(nc):
  45. # if name := nc.evaluate_input("Name"):
  46. # return name
  47. # return nc.__class__.__name__
  48. # set the name if it is available, otherwise just use the constraint's nice name
  49. set_constraint_name = lambda nc : nc.evaluate_input("Name") if nc.evaluate_input("Name") else nc.__class__.__name__
  50. #*#-------------------------------#++#-------------------------------#*#
  51. # L I N K N O D E S
  52. #*#-------------------------------#++#-------------------------------#*#
  53. def GetxForm(nc):
  54. trace = trace_single_line_up(nc, "Output Relationship")
  55. for node in trace[0]:
  56. if (node.node_type == 'XFORM'):
  57. return node
  58. raise GraphError("%s is not connected to a downstream xForm" % nc)
  59. class LinkInherit:
  60. '''A node representing inheritance'''
  61. def __init__(self, signature, base_tree):
  62. self.base_tree=base_tree
  63. self.signature = signature
  64. self.inputs = {
  65. "Parent" : NodeSocket(is_input = True, name = "Parent", node = self,),
  66. # bone only:
  67. "Inherit Rotation" : NodeSocket(is_input = True, name = "Inherit Rotation", node = self,),
  68. "Inherit Scale" : NodeSocket(is_input = True, name = "Inherit Scale", node = self,),
  69. "Connected" : NodeSocket(is_input = True, name = "Connected", node = self,),
  70. }
  71. self.outputs = { "Inheritance" : NodeSocket(name = "Inheritance", node = self) }
  72. self.parameters = {
  73. "Parent":None,
  74. # bone only:
  75. "Inherit Rotation":None,
  76. "Inherit Scale":None,
  77. "Connected":None,
  78. }
  79. self.links = {} # leave this empty for now!
  80. # now set up the traverse target...
  81. self.inputs["Parent"].set_traverse_target(self.outputs["Inheritance"])
  82. self.outputs["Inheritance"].set_traverse_target(self.inputs["Parent"])
  83. self.node_type = 'LINK'
  84. self.hierarchy_connections = []
  85. self.connections = []
  86. self.hierarchy_dependencies = []
  87. self.dependencies = []
  88. self.prepared = True
  89. self.executed = True
  90. def evaluate_input(self, input_name):
  91. return default_evaluate_input(self, input_name)
  92. def GetxForm(self): # DUPLICATED, TODO fix this
  93. # I think this is only run in display update.
  94. trace = trace_single_line_up(self, "Inheritance")
  95. for node in trace[0]:
  96. if (node.node_type == 'XFORM'):
  97. return node
  98. raise GraphError("%s is not connected to a downstream xForm" % self)
  99. class LinkCopyLocation:
  100. '''A node representing Copy Location'''
  101. def __init__(self, signature, base_tree):
  102. self.base_tree=base_tree
  103. self.signature = signature
  104. self.inputs = {
  105. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  106. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  107. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  108. "Axes" : NodeSocket(is_input = True, name = "Axes", node = self,),
  109. "Invert" : NodeSocket(is_input = True, name = "Invert", node = self,),
  110. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  111. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  112. "Offset" : NodeSocket(is_input = True, name = "Offset", node = self,),
  113. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  114. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  115. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  116. self.outputs = {
  117. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  118. self.parameters = {
  119. "Name":None,
  120. "Input Relationship":None,
  121. "Head/Tail":None,
  122. "UseBBone":None,
  123. "Axes":None,
  124. "Invert":None,
  125. "Target Space":None,
  126. "Owner Space":None,
  127. "Offset":None,
  128. "Influence":None,
  129. "Target":None,
  130. "Enable":None, }
  131. # now set up the traverse target...
  132. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  133. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  134. self.node_type = 'LINK'
  135. self.hierarchy_connections = []
  136. self.connections = []
  137. self.hierarchy_dependencies = []
  138. self.dependencies = []
  139. self.prepared = True
  140. self.executed = False
  141. def evaluate_input(self, input_name):
  142. return default_evaluate_input(self, input_name)
  143. def GetxForm(self):
  144. return GetxForm(self)
  145. def bExecute(self, context):
  146. prepare_parameters(self)
  147. c = self.GetxForm().bGetObject().constraints.new('COPY_LOCATION')
  148. get_target_and_subtarget(self, c)
  149. print(wrapGreen("Creating ")+wrapWhite("Copy Location")+
  150. wrapGreen(" Constraint for bone: ") +
  151. wrapOrange(self.GetxForm().bGetObject().name))
  152. if constraint_name := self.evaluate_input("Name"):
  153. c.name = constraint_name
  154. self.bObject = c
  155. custom_space_owner, custom_space_target = False, False
  156. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  157. custom_space_owner=True
  158. c.owner_space='CUSTOM'
  159. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  160. if isinstance(xf, Bone):
  161. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  162. else:
  163. c.space_object=xf
  164. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  165. custom_space_target=True
  166. c.target_space='CUSTOM'
  167. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  168. if isinstance(xf, Bone):
  169. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  170. else:
  171. c.space_object=xf
  172. props_sockets = {
  173. 'use_offset' : ("Offset", False),
  174. 'head_tail' : ("Head/Tail", 0),
  175. 'use_bbone_shape' : ("UseBBone", False),
  176. 'invert_x' : ( ("Invert", 0), False),
  177. 'invert_y' : ( ("Invert", 1), False),
  178. 'invert_z' : ( ("Invert", 2), False),
  179. 'use_x' : ( ("Axes", 0), False),
  180. 'use_y' : ( ("Axes", 1), False),
  181. 'use_z' : ( ("Axes", 2), False),
  182. 'owner_space' : ("Owner Space", 'WORLD'),
  183. 'target_space' : ("Target Space", 'WORLD'),
  184. 'influence' : ("Influence", 1),
  185. 'mute' : ("Enable", True),
  186. }
  187. if custom_space_owner: del props_sockets['owner_space']
  188. if custom_space_target: del props_sockets['target_space']
  189. #
  190. evaluate_sockets(self, c, props_sockets)
  191. self.executed = True
  192. def bFinalize(self, bContext = None):
  193. finish_drivers(self)
  194. class LinkCopyRotation:
  195. '''A node representing Copy Rotation'''
  196. def __init__(self, signature, base_tree):
  197. self.base_tree=base_tree
  198. self.signature = signature
  199. self.inputs = {
  200. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  201. "RotationOrder" : NodeSocket(is_input = True, name = "RotationOrder", node = self,),
  202. "Rotation Mix" : NodeSocket(is_input = True, name = "Rotation Mix", node = self,),
  203. "Axes" : NodeSocket(is_input = True, name = "Axes", node = self,),
  204. "Invert" : NodeSocket(is_input = True, name = "Invert", node = self,),
  205. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  206. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  207. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  208. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  209. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  210. self.outputs = {
  211. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  212. self.parameters = {
  213. "Name":None,
  214. "Input Relationship":None,
  215. "RotationOrder":None,
  216. "Rotation Mix":None,
  217. "Axes":None,
  218. "Invert":None,
  219. "Target Space":None,
  220. "Owner Space":None,
  221. "Influence":None,
  222. "Target":None,
  223. "Enable":None, }
  224. # now set up the traverse target...
  225. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  226. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  227. self.node_type = 'LINK'
  228. self.hierarchy_connections = []
  229. self.connections = []
  230. self.hierarchy_dependencies = []
  231. self.dependencies = []
  232. self.prepared = True
  233. self.executed = False
  234. def evaluate_input(self, input_name):
  235. return default_evaluate_input(self, input_name)
  236. def GetxForm(self):
  237. return GetxForm(self)
  238. def bExecute(self, context):
  239. prepare_parameters(self)
  240. c = self.GetxForm().bGetObject().constraints.new('COPY_ROTATION')
  241. get_target_and_subtarget(self, c)
  242. print(wrapGreen("Creating ")+wrapWhite("Copy Rotation")+
  243. wrapGreen(" Constraint for bone: ") +
  244. wrapOrange(self.GetxForm().bGetObject().name))
  245. rotation_order = self.evaluate_input("RotationOrder")
  246. if ((rotation_order == 'QUATERNION') or (rotation_order == 'AXIS_ANGLE')):
  247. c.euler_order = 'AUTO'
  248. else:
  249. try:
  250. c.euler_order = rotation_order
  251. except TypeError: # it's a driver or incorrect
  252. c.euler_order = 'AUTO'
  253. if constraint_name := self.evaluate_input("Name"):
  254. c.name = constraint_name
  255. self.bObject = c
  256. custom_space_owner, custom_space_target = False, False
  257. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  258. custom_space_owner=True
  259. c.owner_space='CUSTOM'
  260. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  261. if isinstance(xf, Bone):
  262. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  263. else:
  264. c.space_object=xf
  265. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  266. custom_space_target=True
  267. c.target_space='CUSTOM'
  268. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  269. if isinstance(xf, Bone):
  270. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  271. else:
  272. c.space_object=xf
  273. props_sockets = {
  274. 'euler_order' : ("RotationOrder", 'AUTO'),
  275. 'mix_mode' : ("Rotation Mix", 'REPLACE'),
  276. 'invert_x' : ( ("Invert", 0), False),
  277. 'invert_y' : ( ("Invert", 1), False),
  278. 'invert_z' : ( ("Invert", 2), False),
  279. 'use_x' : ( ("Axes", 0), False),
  280. 'use_y' : ( ("Axes", 1), False),
  281. 'use_z' : ( ("Axes", 2), False),
  282. 'owner_space' : ("Owner Space", 'WORLD'),
  283. 'target_space' : ("Target Space", 'WORLD'),
  284. 'influence' : ("Influence", 1),
  285. 'mute' : ("Enable", True),
  286. }
  287. if custom_space_owner: del props_sockets['owner_space']
  288. if custom_space_target: del props_sockets['target_space']
  289. #
  290. evaluate_sockets(self, c, props_sockets)
  291. self.executed = True
  292. def bFinalize(self, bContext = None):
  293. finish_drivers(self)
  294. class LinkCopyScale:
  295. '''A node representing Copy Scale'''
  296. def __init__(self, signature, base_tree):
  297. self.base_tree=base_tree
  298. self.signature = signature
  299. self.inputs = {
  300. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  301. "Offset" : NodeSocket(is_input = True, name = "Offset", node = self,),
  302. "Average" : NodeSocket(is_input = True, name = "Average", node = self,),
  303. "Additive" : NodeSocket(is_input = True, name = "Additive", node = self,),
  304. "Axes" : NodeSocket(is_input = True, name = "Axes", node = self,),
  305. #"Invert" : NodeSocket(is_input = True, name = "Invert", node = self,),
  306. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  307. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  308. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  309. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  310. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  311. self.outputs = {
  312. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  313. self.parameters = {
  314. "Name":None,
  315. "Input Relationship":None,
  316. "Offset":None,
  317. "Average":None,
  318. "Axes":None,
  319. #"Invert":None,
  320. "Target Space":None,
  321. "Owner Space":None,
  322. "Influence":None,
  323. "Target":None,
  324. "Enable":None,}
  325. # now set up the traverse target...
  326. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  327. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  328. self.node_type = 'LINK'
  329. self.hierarchy_connections = []
  330. self.connections = []
  331. self.hierarchy_dependencies = []
  332. self.dependencies = []
  333. self.prepared = True
  334. self.executed = False
  335. def evaluate_input(self, input_name):
  336. return default_evaluate_input(self, input_name)
  337. def GetxForm(self):
  338. return GetxForm(self)
  339. def bExecute(self, context):
  340. prepare_parameters(self)
  341. c = self.GetxForm().bGetObject().constraints.new('COPY_SCALE')
  342. get_target_and_subtarget(self, c)
  343. print(wrapGreen("Creating ")+wrapWhite("Copy Scale")+
  344. wrapGreen(" Constraint for bone: ") +
  345. wrapOrange(self.GetxForm().bGetObject().name))
  346. if constraint_name := self.evaluate_input("Name"):
  347. c.name = constraint_name
  348. self.bObject = c
  349. custom_space_owner, custom_space_target = False, False
  350. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  351. custom_space_owner=True
  352. c.owner_space='CUSTOM'
  353. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  354. if isinstance(xf, Bone):
  355. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  356. else:
  357. c.space_object=xf
  358. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  359. custom_space_target=True
  360. c.target_space='CUSTOM'
  361. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  362. if isinstance(xf, Bone):
  363. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  364. else:
  365. c.space_object=xf
  366. props_sockets = {
  367. 'use_offset' : ("Offset", False),
  368. 'use_make_uniform' : ("Average", False),
  369. 'owner_space' : ("Owner Space", 'WORLD'),
  370. 'target_space' : ("Target Space", 'WORLD'),
  371. 'use_x' : ( ("Axes", 0), False),
  372. 'use_y' : ( ("Axes", 1), False),
  373. 'use_z' : ( ("Axes", 2), False),
  374. 'influence' : ("Influence", 1),
  375. 'mute' : ("Enable", True),
  376. }
  377. if custom_space_owner: del props_sockets['owner_space']
  378. if custom_space_target: del props_sockets['target_space']
  379. #
  380. evaluate_sockets(self, c, props_sockets)
  381. self.executed = True
  382. def bFinalize(self, bContext = None):
  383. finish_drivers(self)
  384. class LinkCopyTransforms:
  385. '''A node representing Copy Transfoms'''
  386. def __init__(self, signature, base_tree):
  387. self.base_tree=base_tree
  388. self.signature = signature
  389. self.inputs = {
  390. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  391. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  392. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  393. "Additive" : NodeSocket(is_input = True, name = "Additive", node = self,),
  394. "Mix" : NodeSocket(is_input = True, name = "Mix", node = self,),
  395. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  396. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  397. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  398. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  399. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  400. self.outputs = {
  401. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  402. self.parameters = {
  403. "Name":None,
  404. "Input Relationship":None,
  405. "Head/Tail":None,
  406. "UseBBone":None,
  407. "Mix":None,
  408. "Target Space":None,
  409. "Owner Space":None,
  410. "Influence":None,
  411. "Target":None,
  412. "Enable":None,}
  413. # now set up the traverse target...
  414. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  415. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  416. self.node_type = 'LINK'
  417. self.hierarchy_connections = []
  418. self.connections = []
  419. self.hierarchy_dependencies = []
  420. self.dependencies = []
  421. self.prepared = True
  422. self.executed = False
  423. def evaluate_input(self, input_name):
  424. return default_evaluate_input(self, input_name)
  425. def GetxForm(self):
  426. return GetxForm(self)
  427. def bExecute(self, context):
  428. prepare_parameters(self)
  429. c = self.GetxForm().bGetObject().constraints.new('COPY_TRANSFORMS')
  430. get_target_and_subtarget(self, c)
  431. print(wrapGreen("Creating ")+wrapWhite("Copy Transforms")+
  432. wrapGreen(" Constraint for bone: ") +
  433. wrapOrange(self.GetxForm().bGetObject().name))
  434. if constraint_name := self.evaluate_input("Name"):
  435. c.name = constraint_name
  436. self.bObject = c
  437. custom_space_owner, custom_space_target = False, False
  438. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  439. custom_space_owner=True
  440. c.owner_space='CUSTOM'
  441. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  442. if isinstance(xf, Bone):
  443. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  444. else:
  445. c.space_object=xf
  446. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  447. custom_space_target=True
  448. c.target_space='CUSTOM'
  449. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  450. if isinstance(xf, Bone):
  451. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  452. else:
  453. c.space_object=xf
  454. props_sockets = {
  455. 'head_tail' : ("Head/Tail", 0),
  456. 'use_bbone_shape' : ("UseBBone", False),
  457. 'mix_mode' : ("Mix", 'REPLACE'),
  458. 'owner_space' : ("Owner Space", 'WORLD'),
  459. 'target_space' : ("Target Space", 'WORLD'),
  460. 'influence' : ("Influence", 1),
  461. 'mute' : ("Enable", False)
  462. }
  463. if custom_space_owner: del props_sockets['owner_space']
  464. if custom_space_target: del props_sockets['target_space']
  465. #
  466. evaluate_sockets(self, c, props_sockets)
  467. self.executed = True
  468. def bFinalize(self, bContext = None):
  469. finish_drivers(self)
  470. transformation_props_sockets = {
  471. 'use_motion_extrapolate' : ("Extrapolate", False),
  472. 'map_from' : ("Map From", 'LOCATION'),
  473. 'from_rotation_mode' : ("Rotation Mode", 'AUTO'),
  474. 'from_min_x' : ("X Min From", 0.0),
  475. 'from_max_x' : ("X Max From", 0.0),
  476. 'from_min_y' : ("Y Min From", 0.0),
  477. 'from_max_y' : ("Y Max From", 0.0),
  478. 'from_min_z' : ("Z Min From", 0.0),
  479. 'from_max_z' : ("Z Max From", 0.0),
  480. 'from_min_x_rot' : ("X Min From", 0.0),
  481. 'from_max_x_rot' : ("X Max From", 0.0),
  482. 'from_min_y_rot' : ("Y Min From", 0.0),
  483. 'from_max_y_rot' : ("Y Max From", 0.0),
  484. 'from_min_z_rot' : ("Z Min From", 0.0),
  485. 'from_max_z_rot' : ("Z Max From", 0.0),
  486. 'from_min_x_scale' : ("X Min From", 0.0),
  487. 'from_max_x_scale' : ("X Max From", 0.0),
  488. 'from_min_y_scale' : ("Y Min From", 0.0),
  489. 'from_max_y_scale' : ("Y Max From", 0.0),
  490. 'from_min_z_scale' : ("Z Min From", 0.0),
  491. 'from_max_z_scale' : ("Z Max From", 0.0),
  492. 'map_to' : ("Map To", "LOCATION"),
  493. 'map_to_x_from' : ("X Source Axis", "X"),
  494. 'map_to_y_from' : ("Y Source Axis", "Y"),
  495. 'map_to_z_from' : ("Z Source Axis", "Z"),
  496. 'to_min_x' : ("X Min To", 0.0),
  497. 'to_max_x' : ("X Max To", 0.0),
  498. 'to_min_y' : ("Y Min To", 0.0),
  499. 'to_max_y' : ("Y Max To", 0.0),
  500. 'to_min_z' : ("Z Min To", 0.0),
  501. 'to_max_z' : ("Z Max To", 0.0),
  502. 'to_min_x_rot' : ("X Min To", 0.0),
  503. 'to_max_x_rot' : ("X Max To", 0.0),
  504. 'to_min_y_rot' : ("Y Min To", 0.0),
  505. 'to_max_y_rot' : ("Y Max To", 0.0),
  506. 'to_min_z_rot' : ("Z Min To", 0.0),
  507. 'to_max_z_rot' : ("Z Max To", 0.0),
  508. 'to_min_x_scale' : ("X Min To", 0.0),
  509. 'to_max_x_scale' : ("X Max To", 0.0),
  510. 'to_min_y_scale' : ("Y Min To", 0.0),
  511. 'to_max_y_scale' : ("Y Max To", 0.0),
  512. 'to_min_z_scale' : ("Z Min To", 0.0),
  513. 'to_max_z_scale' : ("Z Max To", 0.0),
  514. 'to_euler_order' : ("Rotation Mode", "AUTO"),
  515. 'mix_mode' : ("Mix Mode (Translation)", "ADD"),
  516. 'mix_mode_rot' : ("Mix Mode (Rotation)", "ADD"),
  517. 'mix_mode_scale' : ("Mix Mode (Scale)", "MULTIPLY"),
  518. 'owner_space' : ("Owner Space", 'WORLD'),
  519. 'target_space' : ("Target Space", 'WORLD'),
  520. 'influence' : ("Influence", 1),
  521. 'mute' : ("Enable", False),
  522. }
  523. class LinkTransformation:
  524. '''A node representing Copy Transfoms'''
  525. def __init__(self, signature, base_tree):
  526. self.base_tree=base_tree
  527. self.signature = signature
  528. self.inputs = {
  529. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  530. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  531. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  532. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  533. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  534. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,),
  535. "Extrapolate" : NodeSocket(is_input = True, name = "Extrapolate", node = self,),
  536. "Map From" : NodeSocket(is_input = True, name = "Map From", node = self,),
  537. "Rotation Mode" : NodeSocket(is_input = True, name = "Rotation Mode", node = self,),
  538. "X Min From" : NodeSocket(is_input = True, name = "X Min From", node = self,),
  539. "X Max From" : NodeSocket(is_input = True, name = "X Max From", node = self,),
  540. "Y Min From" : NodeSocket(is_input = True, name = "Y Min From", node = self,),
  541. "Y Max From" : NodeSocket(is_input = True, name = "Y Max From", node = self,),
  542. "Z Min From" : NodeSocket(is_input = True, name = "Z Min From", node = self,),
  543. "Z Max From" : NodeSocket(is_input = True, name = "Z Max From", node = self,),
  544. "Map To" : NodeSocket(is_input = True, name = "Map To", node = self,),
  545. "X Source Axis" : NodeSocket(is_input = True, name = "X Source Axis", node = self,),
  546. "X Min To" : NodeSocket(is_input = True, name = "X Min To", node = self,),
  547. "X Max To" : NodeSocket(is_input = True, name = "X Max To", node = self,),
  548. "Y Source Axis" : NodeSocket(is_input = True, name = "Y Source Axis", node = self,),
  549. "Y Min To" : NodeSocket(is_input = True, name = "Y Min To", node = self,),
  550. "Y Max To" : NodeSocket(is_input = True, name = "Y Max To", node = self,),
  551. "Z Source Axis" : NodeSocket(is_input = True, name = "Z Source Axis", node = self,),
  552. "Z Min To" : NodeSocket(is_input = True, name = "Z Min To", node = self,),
  553. "Z Max To" : NodeSocket(is_input = True, name = "Z Max To", node = self,),
  554. "Rotation Mode" : NodeSocket(is_input = True, name = "Rotation Mode", node = self,),
  555. "Mix Mode (Translation)" : NodeSocket(is_input = True, name = "Mix Mode (Translation)", node = self,),
  556. "Mix Mode (Rotation)" : NodeSocket(is_input = True, name = "Mix Mode (Rotation)", node = self,),
  557. "Mix Mode (Scale)" : NodeSocket(is_input = True, name = "Mix Mode (Scale)", node = self,),
  558. }
  559. self.outputs = {
  560. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  561. self.parameters = {
  562. "Name" : None,
  563. "Input Relationship" : None,
  564. "Target Space" : None,
  565. "Owner Space" : None,
  566. "Influence" : None,
  567. "Target" : None,
  568. "Enable" : None,
  569. "Extrapolate" : None,
  570. "Map From" : None,
  571. "Rotation Mode" : None,
  572. "X Min From" : None,
  573. "X Max From" : None,
  574. "Y Min From" : None,
  575. "Y Max From" : None,
  576. "Z Min From" : None,
  577. "Z Max From" : None,
  578. "Map To" : None,
  579. "X Source Axis" : None,
  580. "X Min To" : None,
  581. "X Max To" : None,
  582. "Y Source Axis" : None,
  583. "Y Min To" : None,
  584. "Y Max To" : None,
  585. "Z Source Axis" : None,
  586. "Z Min To" : None,
  587. "Z Max To" : None,
  588. "Rotation Order" : None,
  589. "Mix Mode (Translation)" : None,
  590. "Mix Mode (Rotation)" : None,
  591. "Mix Mode (Scale)" : None,}
  592. # now set up the traverse target...
  593. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  594. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  595. self.node_type = 'LINK'
  596. self.hierarchy_connections = []
  597. self.connections = []
  598. self.hierarchy_dependencies = []
  599. self.dependencies = []
  600. self.prepared = True
  601. self.executed = False
  602. def evaluate_input(self, input_name):
  603. return default_evaluate_input(self, input_name)
  604. def GetxForm(self):
  605. return GetxForm(self)
  606. def bExecute(self, context):
  607. prepare_parameters(self)
  608. c = self.GetxForm().bGetObject().constraints.new('TRANSFORM')
  609. get_target_and_subtarget(self, c)
  610. print(wrapGreen("Creating ")+wrapWhite("Transformation")+
  611. wrapGreen(" Constraint for bone: ") +
  612. wrapOrange(self.GetxForm().bGetObject().name))
  613. if constraint_name := self.evaluate_input("Name"):
  614. c.name = constraint_name
  615. self.bObject = c
  616. custom_space_owner, custom_space_target = False, False
  617. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  618. custom_space_owner=True
  619. c.owner_space='CUSTOM'
  620. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  621. if isinstance(xf, Bone):
  622. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  623. else:
  624. c.space_object=xf
  625. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  626. custom_space_target=True
  627. c.target_space='CUSTOM'
  628. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  629. if isinstance(xf, Bone):
  630. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  631. else:
  632. c.space_object=xf
  633. props_sockets = transformation_props_sockets.copy()
  634. if custom_space_owner: del props_sockets['owner_space']
  635. if custom_space_target: del props_sockets['target_space']
  636. #
  637. evaluate_sockets(self, c, props_sockets)
  638. self.executed = True
  639. def bFinalize(self, bContext = None):
  640. finish_drivers(self)
  641. class LinkLimitLocation:
  642. def __init__(self, signature, base_tree):
  643. self.base_tree=base_tree
  644. self.signature = signature
  645. self.inputs = {
  646. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  647. "Use Max X" : NodeSocket(is_input = True, name = "Use Max X", node = self,),
  648. "Max X" : NodeSocket(is_input = True, name = "Max X", node = self,),
  649. "Use Max Y" : NodeSocket(is_input = True, name = "Use Max Y", node = self,),
  650. "Max Y" : NodeSocket(is_input = True, name = "Max Y", node = self,),
  651. "Use Max Z" : NodeSocket(is_input = True, name = "Use Max Z", node = self,),
  652. "Max Z" : NodeSocket(is_input = True, name = "Max Z", node = self,),
  653. "Use Min X" : NodeSocket(is_input = True, name = "Use Min X", node = self,),
  654. "Min X" : NodeSocket(is_input = True, name = "Min X", node = self,),
  655. "Use Min Y" : NodeSocket(is_input = True, name = "Use Min Y", node = self,),
  656. "Min Y" : NodeSocket(is_input = True, name = "Min Y", node = self,),
  657. "Use Min Z" : NodeSocket(is_input = True, name = "Use Min Z", node = self,),
  658. "Min Z" : NodeSocket(is_input = True, name = "Min Z", node = self,),
  659. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  660. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  661. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  662. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  663. self.outputs = {
  664. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  665. self.parameters = {
  666. "Name":None,
  667. "Input Relationship":None,
  668. "Use Max X":None,
  669. "Max X":None,
  670. "Use Max Y":None,
  671. "Max Y":None,
  672. "Use Max Z":None,
  673. "Max Z":None,
  674. "Use Min X":None,
  675. "Min X":None,
  676. "Use Min Y":None,
  677. "Min Y":None,
  678. "Use Min Z":None,
  679. "Min Z":None,
  680. "Affect Transform":None,
  681. "Owner Space":None,
  682. "Influence":None,
  683. "Enable":None,}
  684. # now set up the traverse target...
  685. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  686. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  687. self.node_type = 'LINK'
  688. self.hierarchy_connections = []
  689. self.connections = []
  690. self.hierarchy_dependencies = []
  691. self.dependencies = []
  692. self.prepared = True
  693. self.executed = False
  694. def evaluate_input(self, input_name):
  695. return default_evaluate_input(self, input_name)
  696. def GetxForm(self):
  697. return GetxForm(self)
  698. def bExecute(self, context):
  699. prepare_parameters(self)
  700. c = self.GetxForm().bGetObject().constraints.new('LIMIT_LOCATION')
  701. #
  702. print(wrapGreen("Creating ")+wrapWhite("Limit Location")+
  703. wrapGreen(" Constraint for bone: ") +
  704. wrapOrange(self.GetxForm().bGetObject().name))
  705. if constraint_name := self.evaluate_input("Name"):
  706. c.name = constraint_name
  707. self.bObject = c
  708. custom_space_owner = False
  709. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  710. custom_space_owner=True
  711. c.owner_space='CUSTOM'
  712. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  713. if isinstance(xf, Bone):
  714. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  715. else:
  716. c.space_object=xf
  717. props_sockets = {
  718. 'use_transform_limit' : ("Affect Transform", False),
  719. 'use_max_x' : ("Use Max X", False),
  720. 'use_max_y' : ("Use Max Y", False),
  721. 'use_max_z' : ("Use Max Z", False),
  722. 'use_min_x' : ("Use Min X", False),
  723. 'use_min_y' : ("Use Min Y", False),
  724. 'use_min_z' : ("Use Min Z", False),
  725. 'max_x' : ("Max X", 0),
  726. 'max_y' : ("Max Y", 0),
  727. 'max_z' : ("Max Z", 0),
  728. 'min_x' : ("Min X", 0),
  729. 'min_y' : ("Min Y", 0),
  730. 'min_z' : ("Min Z", 0),
  731. 'owner_space' : ("Owner Space", 'WORLD'),
  732. 'influence' : ("Influence", 1),
  733. 'mute' : ("Enable", True),
  734. }
  735. if custom_space_owner: del props_sockets['owner_space']
  736. #
  737. evaluate_sockets(self, c, props_sockets)
  738. self.executed = True
  739. def bFinalize(self, bContext = None):
  740. finish_drivers(self)
  741. class LinkLimitRotation:
  742. def __init__(self, signature, base_tree):
  743. self.base_tree=base_tree
  744. self.signature = signature
  745. self.inputs = {
  746. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  747. "Use X" : NodeSocket(is_input = True, name = "Use X", node = self,),
  748. "Use Y" : NodeSocket(is_input = True, name = "Use Y", node = self,),
  749. "Use Z" : NodeSocket(is_input = True, name = "Use Z", node = self,),
  750. "Max X" : NodeSocket(is_input = True, name = "Max X", node = self,),
  751. "Max Y" : NodeSocket(is_input = True, name = "Max Y", node = self,),
  752. "Max Z" : NodeSocket(is_input = True, name = "Max Z", node = self,),
  753. "Min X" : NodeSocket(is_input = True, name = "Min X", node = self,),
  754. "Min Y" : NodeSocket(is_input = True, name = "Min Y", node = self,),
  755. "Min Z" : NodeSocket(is_input = True, name = "Min Z", node = self,),
  756. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  757. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  758. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  759. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  760. self.outputs = {
  761. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  762. self.parameters = {
  763. "Name":None,
  764. "Input Relationship":None,
  765. "Use X":None,
  766. "Use Y":None,
  767. "Use Z":None,
  768. "Max X":None,
  769. "Max Y":None,
  770. "Max Z":None,
  771. "Min X":None,
  772. "Min Y":None,
  773. "Min Z":None,
  774. "Affect Transform":None,
  775. "Owner Space":None,
  776. "Influence":None,
  777. "Enable":None,}
  778. # now set up the traverse target...
  779. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  780. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  781. self.node_type = 'LINK'
  782. self.hierarchy_connections = []
  783. self.connections = []
  784. self.hierarchy_dependencies = []
  785. self.dependencies = []
  786. self.prepared = True
  787. self.executed = False
  788. def evaluate_input(self, input_name):
  789. return default_evaluate_input(self, input_name)
  790. def GetxForm(self):
  791. return GetxForm(self)
  792. def bExecute(self, context):
  793. prepare_parameters(self)
  794. c = self.GetxForm().bGetObject().constraints.new('LIMIT_ROTATION')
  795. print(wrapGreen("Creating ")+wrapWhite("Limit Rotation")+
  796. wrapGreen(" Constraint for bone: ") +
  797. wrapOrange(self.GetxForm().bGetObject().name))
  798. if constraint_name := self.evaluate_input("Name"):
  799. c.name = constraint_name
  800. self.bObject = c
  801. custom_space_owner = False
  802. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  803. custom_space_owner=True
  804. c.owner_space='CUSTOM'
  805. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  806. if isinstance(xf, Bone):
  807. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  808. else:
  809. c.space_object=xf
  810. props_sockets = {
  811. 'use_transform_limit' : ("Affect Transform", False),
  812. 'use_limit_x' : ("Use X", False),
  813. 'use_limit_y' : ("Use Y", False),
  814. 'use_limit_z' : ("Use Z", False),
  815. 'max_x' : ("Max X", 0),
  816. 'max_y' : ("Max Y", 0),
  817. 'max_z' : ("Max Z", 0),
  818. 'min_x' : ("Min X", 0),
  819. 'min_y' : ("Min Y", 0),
  820. 'min_z' : ("Min Z", 0),
  821. 'owner_space' : ("Owner Space", 'WORLD'),
  822. 'influence' : ("Influence", 1),
  823. 'mute' : ("Enable", True),
  824. }
  825. if custom_space_owner: del props_sockets['owner_space']
  826. #
  827. evaluate_sockets(self, c, props_sockets)
  828. self.executed = True
  829. def bFinalize(self, bContext = None):
  830. finish_drivers(self)
  831. class LinkLimitScale:
  832. def __init__(self, signature, base_tree):
  833. self.base_tree=base_tree
  834. self.signature = signature
  835. self.inputs = {
  836. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  837. "Use Max X" : NodeSocket(is_input = True, name = "Use Max X", node = self,),
  838. "Max X" : NodeSocket(is_input = True, name = "Max X", node = self,),
  839. "Use Max Y" : NodeSocket(is_input = True, name = "Use Max Y", node = self,),
  840. "Max Y" : NodeSocket(is_input = True, name = "Max Y", node = self,),
  841. "Use Max Z" : NodeSocket(is_input = True, name = "Use Max Z", node = self,),
  842. "Max Z" : NodeSocket(is_input = True, name = "Max Z", node = self,),
  843. "Use Min X" : NodeSocket(is_input = True, name = "Use Min X", node = self,),
  844. "Min X" : NodeSocket(is_input = True, name = "Min X", node = self,),
  845. "Use Min Y" : NodeSocket(is_input = True, name = "Use Min Y", node = self,),
  846. "Min Y" : NodeSocket(is_input = True, name = "Min Y", node = self,),
  847. "Use Min Z" : NodeSocket(is_input = True, name = "Use Min Z", node = self,),
  848. "Min Z" : NodeSocket(is_input = True, name = "Min Z", node = self,),
  849. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  850. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  851. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  852. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  853. self.outputs = {
  854. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  855. self.parameters = {
  856. "Name":None,
  857. "Input Relationship":None,
  858. "Use Max X":None,
  859. "Max X":None,
  860. "Use Max Y":None,
  861. "Max Y":None,
  862. "Use Max Z":None,
  863. "Max Z":None,
  864. "Use Min X":None,
  865. "Min X":None,
  866. "Use Min Y":None,
  867. "Min Y":None,
  868. "Use Min Z":None,
  869. "Min Z":None,
  870. "Affect Transform":None,
  871. "Owner Space":None,
  872. "Influence":None,
  873. "Enable":None,}
  874. # now set up the traverse target...
  875. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  876. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  877. self.node_type = 'LINK'
  878. self.hierarchy_connections = []
  879. self.connections = []
  880. self.hierarchy_dependencies = []
  881. self.dependencies = []
  882. self.prepared = True
  883. self.executed = False
  884. def evaluate_input(self, input_name):
  885. return default_evaluate_input(self, input_name)
  886. def GetxForm(self):
  887. return GetxForm(self)
  888. def bExecute(self, context):
  889. prepare_parameters(self)
  890. c = self.GetxForm().bGetObject().constraints.new('LIMIT_SCALE')
  891. print(wrapGreen("Creating ")+wrapWhite("Limit Scale")+
  892. wrapGreen(" Constraint for bone: ") +
  893. wrapOrange(self.GetxForm().bGetObject().name))
  894. if constraint_name := self.evaluate_input("Name"):
  895. c.name = constraint_name
  896. self.bObject = c
  897. custom_space_owner = False
  898. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  899. custom_space_owner=True
  900. c.owner_space='CUSTOM'
  901. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  902. if isinstance(xf, Bone):
  903. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  904. else:
  905. c.space_object=xf
  906. props_sockets = {
  907. 'use_transform_limit' : ("Affect Transform", False),
  908. 'use_max_x' : ("Use Max X", False),
  909. 'use_max_y' : ("Use Max Y", False),
  910. 'use_max_z' : ("Use Max Z", False),
  911. 'use_min_x' : ("Use Min X", False),
  912. 'use_min_y' : ("Use Min Y", False),
  913. 'use_min_z' : ("Use Min Z", False),
  914. 'max_x' : ("Max X", 0),
  915. 'max_y' : ("Max Y", 0),
  916. 'max_z' : ("Max Z", 0),
  917. 'min_x' : ("Min X", 0),
  918. 'min_y' : ("Min Y", 0),
  919. 'min_z' : ("Min Z", 0),
  920. 'owner_space' : ("Owner Space", 'WORLD'),
  921. 'influence' : ("Influence", 1),
  922. 'mute' : ("Enable", True),
  923. }
  924. if custom_space_owner: del props_sockets['owner_space']
  925. #
  926. evaluate_sockets(self, c, props_sockets)
  927. self.executed = True
  928. def bFinalize(self, bContext = None):
  929. finish_drivers(self)
  930. class LinkLimitDistance:
  931. def __init__(self, signature, base_tree):
  932. self.base_tree=base_tree
  933. self.signature = signature
  934. self.inputs = {
  935. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  936. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  937. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  938. "Distance" : NodeSocket(is_input = True, name = "Distance", node = self,),
  939. "Clamp Region" : NodeSocket(is_input = True, name = "Clamp Region", node = self,),
  940. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  941. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  942. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  943. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  944. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  945. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  946. self.outputs = {
  947. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  948. self.parameters = {
  949. "Name":None,
  950. "Input Relationship":None,
  951. "Head/Tail":None,
  952. "UseBBone":None,
  953. "Distance":None,
  954. "Clamp Region":None,
  955. "Affect Transform":None,
  956. "Owner Space":None,
  957. "Target Space":None,
  958. "Influence":None,
  959. "Target":None,
  960. "Enable":None,}
  961. # now set up the traverse target...
  962. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  963. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  964. self.node_type = 'LINK'
  965. self.hierarchy_connections = []
  966. self.connections = []
  967. self.hierarchy_dependencies = []
  968. self.dependencies = []
  969. self.prepared = True
  970. self.executed = False
  971. def evaluate_input(self, input_name):
  972. return default_evaluate_input(self, input_name)
  973. def GetxForm(self):
  974. return GetxForm(self)
  975. def bExecute(self, context):
  976. prepare_parameters(self)
  977. print(wrapGreen("Creating ")+wrapWhite("Limit Distance")+
  978. wrapGreen(" Constraint for bone: ") +
  979. wrapOrange(self.GetxForm().bGetObject().name))
  980. c = self.GetxForm().bGetObject().constraints.new('LIMIT_DISTANCE')
  981. get_target_and_subtarget(self, c)
  982. if constraint_name := self.evaluate_input("Name"):
  983. c.name = constraint_name
  984. self.bObject = c
  985. #
  986. # TODO: set distance automagically
  987. # IMPORTANT TODO BUG
  988. custom_space_owner, custom_space_target = False, False
  989. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  990. custom_space_owner=True
  991. c.owner_space='CUSTOM'
  992. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  993. if isinstance(xf, Bone):
  994. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  995. else:
  996. c.space_object=xf
  997. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  998. custom_space_target=True
  999. c.target_space='CUSTOM'
  1000. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  1001. if isinstance(xf, Bone):
  1002. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  1003. else:
  1004. c.space_object=xf
  1005. props_sockets = {
  1006. 'distance' : ("Distance", 0),
  1007. 'head_tail' : ("Head/Tail", 0),
  1008. 'limit_mode' : ("Clamp Region", "LIMITDIST_INSIDE"),
  1009. 'use_bbone_shape' : ("UseBBone", False),
  1010. 'use_transform_limit' : ("Affect Transform", 1),
  1011. 'owner_space' : ("Owner Space", 1),
  1012. 'target_space' : ("Target Space", 1),
  1013. 'influence' : ("Influence", 1),
  1014. 'mute' : ("Enable", True),
  1015. }
  1016. if custom_space_owner: del props_sockets['owner_space']
  1017. if custom_space_target: del props_sockets['target_space']
  1018. #
  1019. evaluate_sockets(self, c, props_sockets)
  1020. self.executed = True
  1021. def bFinalize(self, bContext = None):
  1022. finish_drivers(self)
  1023. # Tracking
  1024. class LinkStretchTo:
  1025. def __init__(self, signature, base_tree):
  1026. self.base_tree=base_tree
  1027. self.signature = signature
  1028. self.inputs = {
  1029. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1030. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1031. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1032. "Original Length" : NodeSocket(is_input = True, name = "Original Length", node = self,),
  1033. "Volume Variation" : NodeSocket(is_input = True, name = "Volume Variation", node = self,),
  1034. "Use Volume Min" : NodeSocket(is_input = True, name = "Use Volume Min", node = self,),
  1035. "Volume Min" : NodeSocket(is_input = True, name = "Volume Min", node = self,),
  1036. "Use Volume Max" : NodeSocket(is_input = True, name = "Use Volume Max", node = self,),
  1037. "Volume Max" : NodeSocket(is_input = True, name = "Volume Max", node = self,),
  1038. "Smooth" : NodeSocket(is_input = True, name = "Smooth", node = self,),
  1039. "Maintain Volume" : NodeSocket(is_input = True, name = "Maintain Volume", node = self,),
  1040. "Rotation" : NodeSocket(is_input = True, name = "Rotation", node = self,),
  1041. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1042. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1043. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1044. self.outputs = {
  1045. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1046. self.parameters = {
  1047. "Name":None,
  1048. "Input Relationship":None,
  1049. "Head/Tail":None,
  1050. "UseBBone":None,
  1051. "Original Length":None,
  1052. "Volume Variation":None,
  1053. "Use Volume Min":None,
  1054. "Volume Min":None,
  1055. "Use Volume Max":None,
  1056. "Volume Max":None,
  1057. "Smooth":None,
  1058. "Maintain Volume":None,
  1059. "Rotation":None,
  1060. "Influence":None,
  1061. "Target":None,
  1062. "Enable":None,}
  1063. # now set up the traverse target...
  1064. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1065. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1066. self.node_type = 'LINK'
  1067. self.hierarchy_connections = []
  1068. self.connections = []
  1069. self.hierarchy_dependencies = []
  1070. self.dependencies = []
  1071. self.prepared = True
  1072. self.executed = False
  1073. def evaluate_input(self, input_name):
  1074. return default_evaluate_input(self, input_name)
  1075. def GetxForm(self):
  1076. return GetxForm(self)
  1077. def bExecute(self, context):
  1078. prepare_parameters(self)
  1079. print(wrapGreen("Creating ")+wrapWhite("Stretch-To")+
  1080. wrapGreen(" Constraint for bone: ") +
  1081. wrapOrange(self.GetxForm().bGetObject().name))
  1082. c = self.GetxForm().bGetObject().constraints.new('STRETCH_TO')
  1083. get_target_and_subtarget(self, c)
  1084. if constraint_name := self.evaluate_input("Name"):
  1085. c.name = constraint_name
  1086. self.bObject = c
  1087. props_sockets = {
  1088. 'head_tail' : ("Head/Tail", 0),
  1089. 'use_bbone_shape' : ("UseBBone", False),
  1090. 'bulge' : ("Volume Variation", 0),
  1091. 'use_bulge_min' : ("Use Volume Min", False),
  1092. 'bulge_min' : ("Volume Min", 0),
  1093. 'use_bulge_max' : ("Use Volume Max", False),
  1094. 'bulge_max' : ("Volume Max", 0),
  1095. 'bulge_smooth' : ("Smooth", 0),
  1096. 'volume' : ("Maintain Volume", 'VOLUME_XZX'),
  1097. 'keep_axis' : ("Rotation", 'PLANE_X'),
  1098. 'rest_length' : ("Original Length", self.GetxForm().bGetObject().bone.length),
  1099. 'influence' : ("Influence", 1),
  1100. 'mute' : ("Enable", True),
  1101. }
  1102. evaluate_sockets(self, c, props_sockets)
  1103. if (self.evaluate_input("Original Length") == 0):
  1104. # this is meant to be set automatically.
  1105. c.rest_length = self.GetxForm().bGetObject().bone.length
  1106. self.executed = True
  1107. def bFinalize(self, bContext = None):
  1108. finish_drivers(self)
  1109. class LinkDampedTrack:
  1110. def __init__(self, signature, base_tree):
  1111. self.base_tree=base_tree
  1112. self.signature = signature
  1113. self.inputs = {
  1114. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1115. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1116. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1117. "Track Axis" : NodeSocket(is_input = True, name = "Track Axis", node = self,),
  1118. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1119. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1120. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1121. self.outputs = {
  1122. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1123. self.parameters = {
  1124. "Name":None,
  1125. "Input Relationship":None,
  1126. "Head/Tail":None,
  1127. "UseBBone":None,
  1128. "Track Axis":None,
  1129. "Influence":None,
  1130. "Target":None,
  1131. "Enable":None,}
  1132. # now set up the traverse target...
  1133. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1134. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1135. self.node_type = 'LINK'
  1136. self.hierarchy_connections = []
  1137. self.connections = []
  1138. self.hierarchy_dependencies = []
  1139. self.dependencies = []
  1140. self.prepared = True
  1141. self.executed = False
  1142. def evaluate_input(self, input_name):
  1143. return default_evaluate_input(self, input_name)
  1144. def GetxForm(self):
  1145. return GetxForm(self)
  1146. def bExecute(self, context):
  1147. prepare_parameters(self)
  1148. print(wrapGreen("Creating ")+wrapWhite("Damped Track")+
  1149. wrapGreen(" Constraint for bone: ") +
  1150. wrapOrange(self.GetxForm().bGetObject().name))
  1151. c = self.GetxForm().bGetObject().constraints.new('DAMPED_TRACK')
  1152. get_target_and_subtarget(self, c)
  1153. if constraint_name := self.evaluate_input("Name"):
  1154. c.name = constraint_name
  1155. self.bObject = c
  1156. props_sockets = {
  1157. 'head_tail' : ("Head/Tail", 0),
  1158. 'use_bbone_shape' : ("UseBBone", False),
  1159. 'track_axis' : ("Track Axis", 'TRACK_Y'),
  1160. 'influence' : ("Influence", 1),
  1161. 'mute' : ("Enable", True),
  1162. }
  1163. evaluate_sockets(self, c, props_sockets)
  1164. self.executed = True
  1165. def bFinalize(self, bContext = None):
  1166. finish_drivers(self)
  1167. class LinkLockedTrack:
  1168. def __init__(self, signature, base_tree):
  1169. self.base_tree=base_tree
  1170. self.signature = signature
  1171. self.inputs = {
  1172. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1173. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1174. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1175. "Track Axis" : NodeSocket(is_input = True, name = "Track Axis", node = self,),
  1176. "Lock Axis" : NodeSocket(is_input = True, name = "Lock Axis", node = self,),
  1177. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1178. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1179. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1180. self.outputs = {
  1181. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1182. self.parameters = {
  1183. "Name":None,
  1184. "Input Relationship":None,
  1185. "Head/Tail":None,
  1186. "UseBBone":None,
  1187. "Track Axis":None,
  1188. "Lock Axis":None,
  1189. "Influence":None,
  1190. "Target":None,
  1191. "Enable":None,}
  1192. # now set up the traverse target...
  1193. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1194. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1195. self.node_type = 'LINK'
  1196. self.hierarchy_connections = []
  1197. self.connections = []
  1198. self.hierarchy_dependencies = []
  1199. self.dependencies = []
  1200. self.prepared = True
  1201. self.executed = False
  1202. def evaluate_input(self, input_name):
  1203. return default_evaluate_input(self, input_name)
  1204. def GetxForm(self):
  1205. return GetxForm(self)
  1206. def bExecute(self, context):
  1207. prepare_parameters(self)
  1208. print(wrapGreen("Creating ")+wrapWhite("Locked Track")+
  1209. wrapGreen(" Constraint for bone: ") +
  1210. wrapOrange(self.GetxForm().bGetObject().name))
  1211. c = self.GetxForm().bGetObject().constraints.new('LOCKED_TRACK')
  1212. get_target_and_subtarget(self, c)
  1213. if constraint_name := self.evaluate_input("Name"):
  1214. c.name = constraint_name
  1215. self.bObject = c
  1216. props_sockets = {
  1217. 'head_tail' : ("Head/Tail", 0),
  1218. 'use_bbone_shape' : ("UseBBone", False),
  1219. 'track_axis' : ("Track Axis", 'TRACK_Y'),
  1220. 'lock_axis' : ("Lock Axis", 'UP_X'),
  1221. 'influence' : ("Influence", 1),
  1222. 'mute' : ("Enable", True),
  1223. }
  1224. evaluate_sockets(self, c, props_sockets)
  1225. self.executed = True
  1226. def bFinalize(self, bContext = None):
  1227. finish_drivers(self)
  1228. class LinkTrackTo:
  1229. def __init__(self, signature, base_tree):
  1230. self.base_tree=base_tree
  1231. self.signature = signature
  1232. self.inputs = {
  1233. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1234. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1235. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1236. "Track Axis" : NodeSocket(is_input = True, name = "Track Axis", node = self,),
  1237. "Up Axis" : NodeSocket(is_input = True, name = "Up Axis", node = self,),
  1238. "Use Target Z" : NodeSocket(is_input = True, name = "Use Target Z", node = self,),
  1239. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1240. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1241. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1242. self.outputs = {
  1243. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1244. self.parameters = {
  1245. "Name":None,
  1246. "Input Relationship":None,
  1247. "Head/Tail":None,
  1248. "UseBBone":None,
  1249. "Track Axis":None,
  1250. "Up Axis":None,
  1251. "Use Target Z":None,
  1252. "Influence":None,
  1253. "Target":None,
  1254. "Enable":None,}
  1255. # now set up the traverse target...
  1256. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1257. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1258. self.node_type = 'LINK'
  1259. self.hierarchy_connections = []
  1260. self.connections = []
  1261. self.hierarchy_dependencies = []
  1262. self.dependencies = []
  1263. self.prepared = True
  1264. self.executed = False
  1265. def evaluate_input(self, input_name):
  1266. return default_evaluate_input(self, input_name)
  1267. def GetxForm(self):
  1268. return GetxForm(self)
  1269. def bExecute(self, context):
  1270. prepare_parameters(self)
  1271. print(wrapGreen("Creating ")+wrapWhite("Track-To")+
  1272. wrapGreen(" Constraint for bone: ") +
  1273. wrapOrange(self.GetxForm().bGetObject().name))
  1274. c = self.GetxForm().bGetObject().constraints.new('TRACK_TO')
  1275. get_target_and_subtarget(self, c)
  1276. if constraint_name := self.evaluate_input("Name"):
  1277. c.name = constraint_name
  1278. self.bObject = c
  1279. props_sockets = {
  1280. 'head_tail' : ("Head/Tail", 0),
  1281. 'use_bbone_shape' : ("UseBBone", False),
  1282. 'track_axis' : ("Track Axis", "TRACK_Y"),
  1283. 'up_axis' : ("Up Axis", "UP_Z"),
  1284. 'use_target_z' : ("Use Target Z", False),
  1285. 'influence' : ("Influence", 1),
  1286. 'mute' : ("Enable", True),
  1287. }
  1288. evaluate_sockets(self, c, props_sockets)
  1289. self.executed = True
  1290. def bFinalize(self, bContext = None):
  1291. finish_drivers(self)
  1292. # relationships & misc.
  1293. class LinkInheritConstraint:
  1294. def __init__(self, signature, base_tree):
  1295. self.base_tree=base_tree
  1296. self.signature = signature
  1297. self.inputs = {
  1298. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1299. "Location" : NodeSocket(is_input = True, name = "Location", node = self,),
  1300. "Rotation" : NodeSocket(is_input = True, name = "Rotation", node = self,),
  1301. "Scale" : NodeSocket(is_input = True, name = "Scale", node = self,),
  1302. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1303. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1304. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1305. self.outputs = {
  1306. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1307. self.parameters = {
  1308. "Name":None,
  1309. "Input Relationship":None,
  1310. "Location":None,
  1311. "Rotation":None,
  1312. "Scale":None,
  1313. "Influence":None,
  1314. "Target":None,
  1315. "Enable":None,}
  1316. self.drivers = {}
  1317. # now set up the traverse target...
  1318. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1319. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1320. self.node_type = 'LINK'
  1321. self.hierarchy_connections = []
  1322. self.connections = []
  1323. self.hierarchy_dependencies = []
  1324. self.dependencies = []
  1325. self.prepared = True
  1326. self.executed = False
  1327. def evaluate_input(self, input_name):
  1328. return default_evaluate_input(self, input_name)
  1329. def GetxForm(self):
  1330. return GetxForm(self)
  1331. def bExecute(self, context):
  1332. prepare_parameters(self)
  1333. print(wrapGreen("Creating ")+wrapWhite("Child-Of")+
  1334. wrapGreen(" Constraint for bone: ") +
  1335. wrapOrange(self.GetxForm().bGetObject().name))
  1336. c = self.GetxForm().bGetObject().constraints.new('CHILD_OF')
  1337. get_target_and_subtarget(self, c)
  1338. if constraint_name := self.evaluate_input("Name"):
  1339. c.name = constraint_name
  1340. self.bObject = c
  1341. props_sockets = {
  1342. 'use_location_x' : (("Location", 0) , 1),
  1343. 'use_location_y' : (("Location", 1) , 1),
  1344. 'use_location_z' : (("Location", 2) , 1),
  1345. 'use_rotation_x' : (("Rotation", 0) , 1),
  1346. 'use_rotation_y' : (("Rotation", 1) , 1),
  1347. 'use_rotation_z' : (("Rotation", 2) , 1),
  1348. 'use_scale_x' : (("Scale" , 0) , 1),
  1349. 'use_scale_y' : (("Scale" , 1) , 1),
  1350. 'use_scale_z' : (("Scale" , 2) , 1),
  1351. 'influence' : ( "Influence" , 1),
  1352. 'mute' : ("Enable", True),
  1353. }
  1354. evaluate_sockets(self, c, props_sockets)
  1355. c.set_inverse_pending
  1356. self.executed = True
  1357. def bFinalize(self, bContext = None):
  1358. finish_drivers(self)
  1359. class LinkInverseKinematics:
  1360. def __init__(self, signature, base_tree):
  1361. self.base_tree=base_tree
  1362. self.signature = signature
  1363. self.inputs = {
  1364. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1365. "Chain Length" : NodeSocket(is_input = True, name = "Chain Length", node = self,),
  1366. "Use Tail" : NodeSocket(is_input = True, name = "Use Tail", node = self,),
  1367. "Stretch" : NodeSocket(is_input = True, name = "Stretch", node = self,),
  1368. "Position" : NodeSocket(is_input = True, name = "Position", node = self,),
  1369. "Rotation" : NodeSocket(is_input = True, name = "Rotation", node = self,),
  1370. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1371. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1372. "Pole Target" : NodeSocket(is_input = True, name = "Pole Target", node = self,),
  1373. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1374. self.outputs = {
  1375. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1376. self.parameters = {
  1377. "Name":None,
  1378. "Connected":None,
  1379. "Chain Length":None,
  1380. "Use Tail":None,
  1381. "Stretch":None,
  1382. "Position":None,
  1383. "Rotation":None,
  1384. "Influence":None,
  1385. "Target":None,
  1386. "Pole Target":None,
  1387. "Enable":None,}
  1388. # now set up the traverse target...
  1389. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1390. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1391. self.node_type = 'LINK'
  1392. self.bObject = None
  1393. self.drivers = {}
  1394. self.hierarchy_connections = []
  1395. self.connections = []
  1396. self.hierarchy_dependencies = []
  1397. self.dependencies = []
  1398. self.prepared = True
  1399. self.executed = False
  1400. def evaluate_input(self, input_name):
  1401. return default_evaluate_input(self, input_name)
  1402. def GetxForm(self):
  1403. return GetxForm(self)
  1404. def bExecute(self, context):
  1405. prepare_parameters(self)
  1406. print(wrapGreen("Creating ")+wrapOrange("Inverse Kinematics")+
  1407. wrapGreen(" Constraint for bone: ") +
  1408. wrapOrange(self.GetxForm().bGetObject().name))
  1409. myOb = self.GetxForm().bGetObject()
  1410. c = self.GetxForm().bGetObject().constraints.new('IK')
  1411. get_target_and_subtarget(self, c)
  1412. get_target_and_subtarget(self, c, input_name = 'Pole Target')
  1413. if constraint_name := self.evaluate_input("Name"):
  1414. c.name = constraint_name
  1415. self.bObject = c
  1416. c.chain_count = 1 # so that, if there are errors, this doesn't print a whole bunch of circular dependency crap from having infinite chain length
  1417. if (c.pole_target): # Calculate the pole angle, the user shouldn't have to.
  1418. pole_object = c.pole_target
  1419. pole_location = pole_object.matrix_world.decompose()[0]
  1420. if (c.pole_subtarget):
  1421. pole_object = c.pole_target.pose.bones[c.pole_subtarget]
  1422. pole_location += pole_object.bone.head_local
  1423. #HACK HACK
  1424. handle_location = myOb.bone.tail_local if (self.evaluate_input("Use Tail")) else myOb.bone.head_local
  1425. counter = 0
  1426. parent = myOb
  1427. base_bone = myOb
  1428. while (parent is not None):
  1429. if ((self.evaluate_input("Chain Length") != 0) and (counter > self.evaluate_input("Chain Length"))):
  1430. break
  1431. base_bone = parent
  1432. parent = parent.parent
  1433. counter+=1
  1434. head_location = base_bone.bone.head_local
  1435. # modified from https://blender.stackexchange.com/questions/19754/how-to-set-calculate-pole-angle-of-ik-constraint-so-the-chain-does-not-move
  1436. from mathutils import Vector
  1437. def signed_angle(vector_u, vector_v, normal):
  1438. # Normal specifies orientation
  1439. angle = vector_u.angle(vector_v)
  1440. if vector_u.cross(vector_v).angle(normal) < 1:
  1441. angle = -angle
  1442. return angle
  1443. def get_pole_angle(base_bone, ik_bone, pole_location):
  1444. pole_normal = (ik_bone.bone.tail_local - base_bone.bone.head_local).cross(pole_location - base_bone.bone.head_local)
  1445. projected_pole_axis = pole_normal.cross(base_bone.bone.tail_local - base_bone.bone.head_local)
  1446. x_axis= base_bone.bone.matrix_local.to_3x3() @ Vector((1,0,0))
  1447. return signed_angle(x_axis, projected_pole_axis, base_bone.bone.tail_local - base_bone.bone.head_local)
  1448. pole_angle_in_radians = get_pole_angle(base_bone,
  1449. myOb,
  1450. pole_location)
  1451. c.pole_angle = pole_angle_in_radians
  1452. props_sockets = {
  1453. 'chain_count' : ("Chain Length", 1),
  1454. 'use_tail' : ("Use Tail", True),
  1455. 'use_stretch' : ("Stretch", True),
  1456. "weight" : ("Position", 1.0),
  1457. "orient_weight" : ("Rotation", 0.0),
  1458. "influence" : ("Influence", 1.0),
  1459. 'mute' : ("Enable", True),
  1460. }
  1461. evaluate_sockets(self, c, props_sockets)
  1462. # TODO: handle drivers
  1463. # (it should be assumed we want it on if it's plugged
  1464. # into a driver).
  1465. c.use_location = self.evaluate_input("Position") > 0
  1466. c.use_rotation = self.evaluate_input("Rotation") > 0
  1467. self.executed = True
  1468. def bFinalize(self, bContext = None):
  1469. finish_drivers(self)
  1470. # This is kinda a weird design decision?
  1471. class LinkDrivenParameter:
  1472. '''A node representing an armature object'''
  1473. def __init__(self, signature, base_tree):
  1474. self.base_tree=base_tree
  1475. self.executed = False
  1476. self.signature = signature
  1477. self.inputs = {
  1478. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1479. "Driver" : NodeSocket(is_input = True, name = "Driver", node = self),
  1480. "Parameter" : NodeSocket(is_input = True, name = "Parameter", node = self),
  1481. "Index" : NodeSocket(is_input = True, name = "Index", node = self),
  1482. }
  1483. self.outputs = {
  1484. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self), }
  1485. self.parameters = {
  1486. "Input Relationship":None,
  1487. "Driver":None,
  1488. "Parameter":None,
  1489. "Index":None,
  1490. }
  1491. # now set up the traverse target...
  1492. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1493. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1494. self.node_type = "LINK"
  1495. self.hierarchy_connections = []
  1496. self.connections = []
  1497. self.hierarchy_dependencies = []
  1498. self.dependencies = []
  1499. self.prepared = True
  1500. self.executed = False
  1501. def GetxForm(self):
  1502. return GetxForm(self)
  1503. def evaluate_input(self, input_name):
  1504. return default_evaluate_input(self, input_name)
  1505. def bExecute(self, bContext = None,):
  1506. prepare_parameters(self)
  1507. prGreen("Executing Driven Parameter node")
  1508. # example_ driver ={
  1509. # "owner":None,
  1510. # "prop":None, # will be filled out in the node that uses the driver
  1511. # "ind":-1, # same here
  1512. # "type": self.evaluate_input("Driver Type"),
  1513. # "vars": my_vars,
  1514. # "keys": self.evaluate_input("fCurve"),}
  1515. driver = self.evaluate_input("Driver")
  1516. driver["owner"] = self.GetxForm().bGetObject()
  1517. driver["prop"] = self.evaluate_input("Parameter")
  1518. driver["ind"] = self.evaluate_input("Index")
  1519. self.parameters["Driver"] = driver
  1520. self.executed = True
  1521. def bFinalize(self, bContext = None):
  1522. # TODO HACK BUG
  1523. # This probably no longer works
  1524. from .drivers import CreateDrivers
  1525. CreateDrivers( [ self.parameters["Driver"] ] )
  1526. class LinkArmature:
  1527. '''A node representing an armature object'''
  1528. def __init__(self, signature, base_tree,):
  1529. self.base_tree=base_tree
  1530. self.signature = signature
  1531. self.inputs = {
  1532. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1533. "Preserve Volume" : NodeSocket(is_input = True, name = "Preserve Volume", node = self),
  1534. "Use Envelopes" : NodeSocket(is_input = True, name = "Use Envelopes", node = self),
  1535. "Use Current Location" : NodeSocket(is_input = True, name = "Use Current Location", node = self),
  1536. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self),
  1537. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self),
  1538. }
  1539. self.outputs = {
  1540. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self), }
  1541. self.parameters = {
  1542. "Name":None,
  1543. "Input Relationship":None,
  1544. "Preserve Volume":None,
  1545. "Use Envelopes":None,
  1546. "Use Current Location":None,
  1547. "Influence":None,
  1548. "Enable":None,
  1549. }
  1550. # now set up the traverse target...
  1551. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1552. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1553. self.node_type = "LINK"
  1554. setup_custom_props(self)
  1555. self.hierarchy_connections = []
  1556. self.connections = []
  1557. self.hierarchy_dependencies = []
  1558. self.dependencies = []
  1559. self.prepared = True
  1560. self.executed = False
  1561. def GetxForm(self):
  1562. return GetxForm(self)
  1563. def evaluate_input(self, input_name):
  1564. return default_evaluate_input(self, input_name)
  1565. def bExecute(self, bContext = None,):
  1566. prGreen("Creating Armature Constraint for bone: \""+ self.GetxForm().bGetObject().name + "\"")
  1567. prepare_parameters(self)
  1568. c = self.GetxForm().bGetObject().constraints.new('ARMATURE')
  1569. if constraint_name := self.evaluate_input("Name"):
  1570. c.name = constraint_name
  1571. self.bObject = c
  1572. # get number of targets
  1573. num_targets = len( list(self.inputs.values())[6:] )//2
  1574. props_sockets = {
  1575. 'use_deform_preserve_volume' : ("Preserve Volume", 0),
  1576. 'use_bone_envelopes' : ("Use Envelopes", 0),
  1577. 'use_current_location' : ("Use Current Location", 0),
  1578. 'influence' : ( "Influence" , 1),
  1579. 'mute' : ("Enable", True),
  1580. }
  1581. targets_weights = {}
  1582. for i in range(num_targets):
  1583. target = c.targets.new()
  1584. target_input_name = list(self.inputs.keys())[i*2+6 ]
  1585. weight_input_name = list(self.inputs.keys())[i*2+6+1]
  1586. get_target_and_subtarget(self, target, target_input_name)
  1587. weight_value=self.evaluate_input(weight_input_name)
  1588. if not isinstance(weight_value, float):
  1589. weight_value=0
  1590. targets_weights[i]=weight_value
  1591. props_sockets["targets[%d].weight" % i] = (weight_input_name, 0)
  1592. # targets_weights.append({"weight":(weight_input_name, 0)})
  1593. evaluate_sockets(self, c, props_sockets)
  1594. for target, value in targets_weights.items():
  1595. c.targets[target].weight=value
  1596. # for i, (target, weight) in enumerate(zip(c.targets, targets_weights)):
  1597. # evaluate_sockets(self, target, weight)
  1598. self.executed = True
  1599. def bFinalize(self, bContext = None):
  1600. finish_drivers(self)
  1601. class LinkSplineIK:
  1602. '''A node representing an armature object'''
  1603. def __init__(self, signature, base_tree):
  1604. self.base_tree=base_tree
  1605. self.signature = signature
  1606. self.inputs = {
  1607. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1608. "Target" : NodeSocket(is_input = True, name = "Target", node = self),
  1609. "Chain Length" : NodeSocket(is_input = True, name = "Chain Length", node = self),
  1610. "Even Divisions" : NodeSocket(is_input = True, name = "Even Divisions", node = self),
  1611. "Chain Offset" : NodeSocket(is_input = True, name = "Chain Offset", node = self),
  1612. "Use Curve Radius" : NodeSocket(is_input = True, name = "Use Curve Radius", node = self),
  1613. "Y Scale Mode" : NodeSocket(is_input = True, name = "Y Scale Mode", node = self),
  1614. "XZ Scale Mode" : NodeSocket(is_input = True, name = "XZ Scale Mode", node = self),
  1615. "Use Original Scale" : NodeSocket(is_input = True, name = "Use Original Scale", node = self),
  1616. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self),
  1617. }
  1618. self.outputs = {
  1619. "Output Relationship" : NodeSocket(is_input = False, name = "Output Relationship", node=self), }
  1620. self.parameters = {
  1621. "Name":None,
  1622. "Input Relationship":None,
  1623. "Target":None,
  1624. "Chain Length":None,
  1625. "Even Divisions":None,
  1626. "Chain Offset":None,
  1627. "Use Curve Radius":None,
  1628. "Y Scale Mode":None,
  1629. "XZ Scale Mode":None,
  1630. "Use Original Scale":None,
  1631. "Influence":None,
  1632. }
  1633. # now set up the traverse target...
  1634. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1635. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1636. self.node_type = "LINK"
  1637. self.hierarchy_connections = []
  1638. self.connections = []
  1639. self.hierarchy_dependencies = []
  1640. self.dependencies = []
  1641. self.prepared = True
  1642. self.executed = False
  1643. def evaluate_input(self, input_name):
  1644. return default_evaluate_input(self, input_name)
  1645. def GetxForm(self):
  1646. return GetxForm(self)
  1647. def bExecute(self, bContext = None,):
  1648. prepare_parameters(self)
  1649. prGreen("Creating Spline-IK Constraint for bone: \""+ self.GetxForm().bGetObject().name + "\"")
  1650. c = self.GetxForm().bGetObject().constraints.new('SPLINE_IK')
  1651. get_target_and_subtarget(self, c)
  1652. if constraint_name := self.evaluate_input("Name"):
  1653. c.name = constraint_name
  1654. self.bObject = c
  1655. props_sockets = {
  1656. 'chain_count' : ("Chain Length", 0),
  1657. 'use_even_divisions' : ("Even Divisions", False),
  1658. 'use_chain_offset' : ("Chain Offset", False),
  1659. 'use_curve_radius' : ("Use Curve Radius", False),
  1660. 'y_scale_mode' : ("Y Scale Mode", "FIT_CURVE"),
  1661. 'xz_scale_mode' : ("XZ Scale Mode", "NONE"),
  1662. 'use_original_scale' : ("Use Original Scale", False),
  1663. 'influence' : ("Influence", 1),
  1664. }
  1665. evaluate_sockets(self, c, props_sockets)
  1666. self.executed = True
  1667. for c in TellClasses():
  1668. setup_container(c)