deformer_nodes.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. from .node_common import *
  2. from .xForm_nodes import xFormGeometryObject, xFormObjectInstance
  3. from .misc_nodes import InputExistingGeometryObject
  4. from .base_definitions import MantisNode
  5. from .mantis_dataclasses import MantisSocketTemplate
  6. from .utilities import (prRed, prGreen, prPurple, prWhite, prOrange,
  7. wrapRed, wrapGreen, wrapPurple, wrapWhite,
  8. wrapOrange,)
  9. from .deformer_socket_templates import *
  10. from bpy.types import NodeTree
  11. def TellClasses():
  12. return [
  13. DeformerArmature,
  14. DeformerHook,
  15. DeformerMorphTarget,
  16. DeformerMorphTargetDeform,
  17. DeformerSurfaceDeform,
  18. DeformerMeshDeform,
  19. DeformerLatticeDeform,
  20. DeformerSmoothCorrectiveDeform,
  21. ]
  22. # object instance probably can't use the deformer but it doesn't hurt to try.
  23. deformable_types= (xFormGeometryObject, InputExistingGeometryObject, xFormObjectInstance)
  24. def trace_xForm_back(mantis_node, socket):
  25. if (trace := trace_single_line(mantis_node, socket)[0] ) :
  26. for i in range(len(trace)): # have to look in reverse, actually
  27. if ( isinstance(trace[ i ], deformable_types ) ):
  28. return trace[ i ].bGetObject()
  29. raise GraphError(wrapRed(f"No other object found for {mantis_node}."))
  30. class MantisDeformerNode(MantisNode):
  31. def __init__(self, signature : tuple,
  32. base_tree : NodeTree,
  33. socket_templates : list[MantisSocketTemplate]=[]):
  34. super().__init__(signature, base_tree, socket_templates)
  35. self.node_type = 'LINK'
  36. self.prepared = True
  37. self.bObject=[]
  38. # we need evaluate_input to have the same behaviour as links.
  39. def evaluate_input(self, input_name, index=0):
  40. if (input_name in ['Target', 'Object', 'Hook Target']):
  41. socket = self.inputs.get(input_name)
  42. if socket.is_linked:
  43. return socket.links[0].from_node
  44. return None
  45. else:
  46. return super().evaluate_input(input_name, index)
  47. def GetxForm(mantis_node, output_name="Deformer"):
  48. break_condition= lambda node : node.__class__ in deformable_types
  49. xforms = trace_line_up_branching(mantis_node, output_name, break_condition)
  50. return_me=[]
  51. for xf in xforms:
  52. if xf.node_type != 'XFORM':
  53. continue
  54. if xf in return_me:
  55. continue
  56. return_me.append(xf)
  57. return return_me
  58. def reset_execution(self):
  59. super().reset_execution()
  60. self.bObject=[]; self.prepared=True
  61. def standard_modifier_bind(self, bContext=None, operator=None):
  62. for d in self.bObject:
  63. # we'll only bind it if it is un-muted.
  64. if self.evaluate_input("Enable in Viewport") == False:
  65. continue
  66. from .utilities import bind_modifier_operator
  67. bind_modifier_operator(d, operator)
  68. class DeformerArmature(MantisDeformerNode):
  69. '''A node representing an armature deformer'''
  70. def __init__(self, signature, base_tree):
  71. super().__init__(signature, base_tree)
  72. inputs = [
  73. "Input Relationship",
  74. "Armature Object",
  75. "Blend Vertex Group",
  76. "Invert Vertex Group",
  77. "Preserve Volume",
  78. "Use Multi Modifier",
  79. "Use Envelopes",
  80. "Use Vertex Groups",
  81. "Skinning Method",
  82. "Deformer",
  83. "Copy Skin Weights From"
  84. ]
  85. outputs = [
  86. "Deformer"
  87. ]
  88. self.outputs.init_sockets(outputs)
  89. self.inputs.init_sockets(inputs)
  90. self.init_parameters(additional_parameters={"Name":None})
  91. self.set_traverse([("Deformer", "Deformer")])
  92. self.node_type = "LINK"
  93. self.prepared = True
  94. def GetxForm(self, socket="Deformer"):
  95. if socket == "Deformer":
  96. return super().GetxForm()
  97. else:
  98. trace_xForm_back(self, socket)
  99. # DUPLICATED FROM xForm_nodes::xFormBone
  100. # DEDUP HACK HACK HACK HACK HACK
  101. def bGetParentArmature(self):
  102. from .xForm_nodes import xFormArmature
  103. from .misc_nodes import InputExistingGeometryObject
  104. from bpy.types import Object
  105. if (trace := trace_single_line(self, "Armature Object")[0] ) :
  106. for i in range(len(trace)):
  107. # have to look in reverse, actually
  108. if ( isinstance(trace[ i ], xFormArmature ) ):
  109. return trace[ i ].bGetObject()
  110. elif ( isinstance(trace[i], InputExistingGeometryObject)):
  111. if (ob := trace[i].bGetObject()).type == "ARMATURE":
  112. return ob
  113. raise RuntimeError(f"Cannot find armature for node {self}")
  114. return None
  115. #should do the trick...
  116. def bRelationshipPass(self, bContext = None,):
  117. self.executed = True
  118. def initialize_vgroups(self, xf):
  119. ob = xf.bGetObject()
  120. armOb = self.bGetParentArmature()
  121. for b in armOb.data.bones:
  122. if b.use_deform == False:
  123. continue
  124. vg = ob.vertex_groups.get(b.name)
  125. if not vg:
  126. vg = ob.vertex_groups.new(name=b.name)
  127. if ob.type == 'MESH':
  128. num_verts = len(ob.data.vertices)
  129. elif ob.type == 'LATTICE':
  130. num_verts = len(ob.data.points)
  131. vg.add(range(num_verts), 0, 'REPLACE')
  132. def copy_weights(self, xf):
  133. # we'll use modifiers for this, maybe use GN for it in the future tho
  134. import bpy
  135. ob = xf.bGetObject()
  136. try:
  137. copy_from = self.GetxForm(socket="Copy Skin Weights From")
  138. except GraphError:
  139. copy_from = None
  140. prRed(f"No object found for copying weights in {self}, continuing anyway.")
  141. m = ob.modifiers.new(type="DATA_TRANSFER", name="Mantis_temp_data_transfer")
  142. m.object = None; m.use_vert_data = True
  143. m.data_types_verts = {'VGROUP_WEIGHTS'}
  144. m.vert_mapping = 'POLYINTERP_NEAREST'
  145. m.layers_vgroup_select_src = 'ALL'
  146. m.layers_vgroup_select_dst = 'NAME'
  147. m.object = copy_from
  148. # m.use_object_transform = False # testing reveals that this is undesirable - since the objects may not have their transforms applied.
  149. ob.modifiers.move(len(ob.modifiers)-1, 0)
  150. # ob.data = ob.data.copy()
  151. if False: #MAYBE the mouse needs to be in the 3D viewport, no idea how to set this in an override
  152. # TODO: figure out how to apply this, context is incorrect because armature is still in pose mode
  153. original_active = bpy.context.active_object
  154. original_mode = original_active.mode
  155. bpy.ops.object.mode_set(mode='OBJECT')
  156. with bpy.context.temp_override(**{'active_object':ob, 'selected_objects':[ob, copy_from]}):
  157. # bpy.ops.object.datalayout_transfer(modifier=m.name) # note: this operator is used by the modifier or stand-alone in the UI
  158. # the poll for this operator is defined in blender/source/blender/editors/object/object_data_transfer.cc
  159. # and blender/source/blender/editors/object/object_modifier.cc
  160. # bpy.ops.object.modifier_apply(modifier=m.name, single_user=True)
  161. bpy.ops.object.datalayout_transfer(data_type='VGROUP_WEIGHTS')
  162. bpy.ops.object.data_transfer(data_type='VGROUP_WEIGHTS')
  163. bpy.ops.object.mode_set(mode=original_mode)
  164. def do_automatic_skinning_mesh(self, ob, xf, bContext):
  165. # This is bad and leads to somewhat unpredictable
  166. # behaviour, e.g. what object will be selected? What mode?
  167. # also bpy.ops is ugly and prone to error when used in
  168. # scripts. I don't intend to use bpy.ops when I can avoid it.
  169. import bpy
  170. self.initialize_vgroups(xf)
  171. armOb = self.bGetParentArmature()
  172. armOb.data.pose_position = 'REST'
  173. bContext.view_layer.depsgraph.update()
  174. deform_bones = []
  175. for pb in armOb.pose.bones:
  176. if pb.bone.use_deform == True:
  177. deform_bones.append(pb)
  178. if not deform_bones:
  179. prPurple("Warning: No deform bones in armature. Cancelling.")
  180. return
  181. context_override = {
  182. 'active_object':ob,
  183. 'selected_objects':[ob, armOb],
  184. 'active_pose_bone':deform_bones[0],
  185. 'selected_pose_bones':deform_bones,}
  186. for b in armOb.data.bones:
  187. b.select = True
  188. with bContext.temp_override(**context_override):
  189. bpy.ops.paint.weight_paint_toggle()
  190. bpy.ops.paint.weight_from_bones(type='AUTOMATIC')
  191. bpy.ops.paint.weight_paint_toggle()
  192. for b in armOb.data.bones:
  193. b.select = False
  194. armOb.data.pose_position = 'POSE'
  195. # TODO: modify Blender to make this available as a Python API function.
  196. def do_automatic_skinning_lattice(self, ob, xf, bContext):
  197. # Temporarily, I am making a very simple and ugly automatic skinning algo for lattice points
  198. import bpy
  199. from mathutils.geometry import intersect_point_line
  200. self.initialize_vgroups(xf)
  201. armOb = self.bGetParentArmature()
  202. armOb.data.pose_position = 'REST'
  203. bContext.view_layer.depsgraph.update()
  204. deform_bones = []
  205. for pb in armOb.pose.bones:
  206. if pb.bone.use_deform == True: deform_bones.append(pb)
  207. # How this works:
  208. # - Calculates the weights based on proximity and angle
  209. # - we'll make a vector of the point and the nearest point on the bone
  210. # - dot (point_displacement, bone_y_axis) to get the angle
  211. # - weight the bone's value by this dot product and distance
  212. # - distance should prevail when both bones are within the angle
  213. mat = ob.matrix_world; mat_arm = armOb.matrix_world
  214. for p_index, p in enumerate(ob.data.points):
  215. loc = mat @ p.co_deform # co_deform is the position in edit mode
  216. pt_distance, pt_dot = {}, {}
  217. for b in deform_bones:
  218. bone_vec = ((mat_arm @ b.tail) - (mat_arm @ b.head)).normalized()
  219. nearest_point_on_bone, factor = intersect_point_line(
  220. loc, mat_arm @ b.head, mat_arm @ b.tail) # 0 is point, 1 is factor
  221. if factor > 1.0: nearest_point_on_bone = mat_arm @ b.tail
  222. if factor < 0.0: nearest_point_on_bone = mat_arm @ b.head
  223. point_vec = nearest_point_on_bone - loc
  224. distance = point_vec.length_squared # no need to sqrt, this is faster and
  225. # the quadratic falloff is better than linear falloff.
  226. dot = 1-abs(point_vec.normalized().dot(bone_vec))
  227. # we want to weight zero at 1.0 so that it favors points in its "envelope"
  228. pt_distance[b.name]=distance; pt_dot[b.name] = dot
  229. # now we can assign weights
  230. distance_pairs = [(k,v) for k,v in pt_distance.items()]
  231. distance_pairs.sort(key = lambda a : a[1])
  232. i=0; max_distance = 0.0; near_enough_bones = []
  233. while (i < 4): # TODO: limit-total should be exposed to the user.
  234. if i+1 > len(distance_pairs): break # in case there are fewer than 4 deform bones
  235. near_enough_bones.append(distance_pairs[i][0])
  236. if distance_pairs[i][1] > max_distance: max_distance = distance_pairs[i][1]
  237. i+=1
  238. max_pre_normalized_weight = 0.0
  239. weights = {}
  240. if max_distance == 0.0: max_distance = 1.0
  241. for b_name in near_enough_bones:
  242. w = 1.0
  243. if pt_distance[b_name] > 0:
  244. w*= 1/(pt_distance[b_name]/max_distance) # weight by inverse-distance
  245. w*= pt_dot[b_name]**4 # NOTE: **4 is arbitrary but feels good to me.
  246. if w > max_pre_normalized_weight: max_pre_normalized_weight = w
  247. weights[b_name] = w
  248. if max_pre_normalized_weight == 0.0: max_pre_normalized_weight = 1.0
  249. for b_name in near_enough_bones:
  250. vg = ob.vertex_groups.get(b_name)
  251. vg.add([p_index], weights[b_name]/max_pre_normalized_weight, 'REPLACE')
  252. armOb.data.pose_position = 'POSE'
  253. def bFinalize(self, bContext=None):
  254. prGreen("Executing Armature Deform Node")
  255. mod_name = self.evaluate_input("Name")
  256. for xf in self.GetxForm():
  257. ob = xf.bGetObject()
  258. d = ob.modifiers.new(mod_name, type='ARMATURE')
  259. if d is None:
  260. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  261. self.bObject.append(d)
  262. d.object = self.bGetParentArmature()
  263. props_sockets = {
  264. 'vertex_group' : ("Blend Vertex Group", ""),
  265. 'invert_vertex_group' : ("Invert Vertex Group", ""),
  266. 'use_deform_preserve_volume' : ("Preserve Volume", False),
  267. 'use_multi_modifier' : ("Use Multi Modifier", False),
  268. 'use_bone_envelopes' : ("Use Envelopes", False),
  269. 'use_vertex_groups' : ("Use Vertex Groups", False),
  270. }
  271. evaluate_sockets(self, d, props_sockets)
  272. #
  273. if (skin_method := self.evaluate_input("Skinning Method")) == "AUTOMATIC_HEAT":
  274. match ob.type:
  275. case "MESH":
  276. self.do_automatic_skinning_mesh(ob, xf, bContext)
  277. case "LATTICE":
  278. self.do_automatic_skinning_lattice(ob, xf, bContext)
  279. elif skin_method == "COPY_FROM_OBJECT":
  280. self.initialize_vgroups(xf)
  281. self.copy_weights(xf)
  282. # elif skin_method == "EXISTING_GROUPS":
  283. # pass
  284. class DeformerHook(MantisDeformerNode):
  285. '''A node representing a hook deformer'''
  286. def __init__(self, signature, base_tree):
  287. super().__init__(signature, base_tree, HookSockets)
  288. # now set up the traverse target...
  289. self.init_parameters(additional_parameters={"Name":None})
  290. self.set_traverse([("Deformer", "Deformer")])
  291. self.prepared = True
  292. def driver_for_radius(self, object, hook, index, influence, bezier=True):
  293. """ Creates a driver to control the radius of a curve point with the hook."""
  294. from bpy.types import Bone, PoseBone
  295. var_template = {"owner":hook,
  296. "name":"a",
  297. "type":"TRANSFORMS",
  298. "space":'WORLD_SPACE',
  299. "channel":'SCALE_X',}
  300. var1_template = {"owner":hook.id_data,
  301. "name":"b",
  302. "type":"TRANSFORMS",
  303. "space":'WORLD_SPACE',
  304. "channel":'SCALE_X',}
  305. keys_template = [{"co":(0,0),
  306. "interpolation": "LINEAR",
  307. "type":"KEYFRAME",},
  308. {"co":(1,influence),
  309. "interpolation": "LINEAR",
  310. "type":"KEYFRAME",},]
  311. if bezier:
  312. owner=object.data.splines[0].bezier_points
  313. else:
  314. owner=object.data.splines[0].points
  315. driver = {
  316. "owner":owner[index],
  317. "prop":"radius",
  318. "ind":-1,
  319. "extrapolation":"LINEAR",
  320. "type":"AVERAGE",
  321. "vars":[],
  322. "keys":keys_template,
  323. }
  324. if isinstance(hook, (Bone, PoseBone)):
  325. driver['type']='SCRIPTED'
  326. driver['expression']="(((1/b)*a)+((1/b_001)*a_001)+((1/b_002)*a_002))/3"
  327. from .drivers import CreateDrivers
  328. axes='XYZ'
  329. for i in range(3):
  330. suffix = "" if i == 0 else f"_{i:03d}" # explicit names -- 5.2 no longer uniquifies duplicates
  331. var = var_template.copy()
  332. var["name"]="a"+suffix
  333. var["channel"]="SCALE_"+axes[i]
  334. driver["vars"].append(var)
  335. if isinstance(hook, (Bone, PoseBone)):
  336. var1=var1_template.copy()
  337. var1['name']="b"+suffix
  338. var1['channel']="SCALE_"+axes[i]
  339. driver['vars'].append(var1)
  340. CreateDrivers([driver])
  341. def bRelationshipPass(self, bContext = None,):
  342. self.executed = True
  343. def bFinalize(self, bContext=None):
  344. from bpy.types import Bone, PoseBone, Object
  345. prGreen(f"Executing Hook Deform Node: {self}")
  346. mod_name = self.evaluate_input("Name")
  347. affect_radius = self.evaluate_input("Affect Curve Radius")
  348. auto_bezier = self.evaluate_input("Auto-Bezier")
  349. target_node = self.evaluate_input('Hook Target')
  350. target = target_node.bGetObject(); subtarget = ""
  351. props_sockets = self.gen_property_socket_map()
  352. if isinstance(target, Bone) or isinstance(target, PoseBone):
  353. subtarget = target.name; target = target.id_data
  354. for xf in self.GetxForm():
  355. ob=xf.bGetObject()
  356. if ob.type == 'CURVE':
  357. spline_index = self.evaluate_input("Spline Index")
  358. from .utilities import get_extracted_spline_object
  359. ob = get_extracted_spline_object(ob, spline_index, self.mContext)
  360. reuse = False
  361. for m in ob.modifiers:
  362. if m.type == 'HOOK' and m.object == target and m.subtarget == subtarget:
  363. if self.evaluate_input("Influence") != m.strength:
  364. continue # make a new modifier so they can have different strengths
  365. if ob.animation_data: # this can be None
  366. drivers = ob.animation_data.drivers
  367. for k in props_sockets.keys():
  368. if driver := drivers.find(k):
  369. # TODO: I should check to see if the drivers are the same...
  370. break # continue searching for an equivalent modifier
  371. else: # There was no driver - use this one.
  372. d = m; reuse = True; break
  373. else: # use this one, there can't be drivers without animation_data.
  374. d = m; reuse = True; break
  375. else:
  376. d = ob.modifiers.new(mod_name, type='HOOK')
  377. if d is None:
  378. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  379. self.bObject.append(d)
  380. self.get_target_and_subtarget(d, input_name="Hook Target")
  381. vertices_used=[]
  382. if reuse: # Get the verts in the list... filter out all the unneeded 0's
  383. vertices_used = list(d.vertex_indices)
  384. include_0 = 0 in vertices_used
  385. vertices_used = list(filter(lambda a : a != 0, vertices_used))
  386. if include_0: vertices_used.append(0)
  387. # now we add the selected vertex to the list, too
  388. vertex = self.evaluate_input("Point Index")
  389. if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and auto_bezier:
  390. if affect_radius:
  391. self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength)
  392. vertex*=3
  393. vertices_used.extend([vertex, vertex+1, vertex+2])
  394. else:
  395. vertices_used.append(vertex)
  396. # if we have a curve and it is NOT using auto-bezier for the verts..
  397. if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and affect_radius and not auto_bezier:
  398. print (f"WARN: {self}: \"Affect Radius\" may not behave as expected"
  399. " when used on Bezier curves without Auto-Bezier")
  400. #bezier point starts at 1, and then every third vert, so 4, 7, 10...
  401. if vertex%3==1:
  402. self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength)
  403. if ob.type == 'CURVE' and ob.data.splines[0].type != 'BEZIER' and \
  404. affect_radius:
  405. self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength, bezier=False)
  406. d.vertex_indices_set(vertices_used)
  407. evaluate_sockets(self, d, props_sockets)
  408. finish_drivers(self)
  409. # todo: this node should be able to take many indices in the future.
  410. # Also: I have a Geometry Nodes implementation of this I can use... maybe...
  411. class DeformerMorphTarget(MantisDeformerNode):
  412. '''A node representing an armature deformer'''
  413. def __init__(self, signature, base_tree):
  414. super().__init__(signature, base_tree)
  415. inputs = [
  416. "Relative to",
  417. "Object",
  418. "Deformer",
  419. "Vertex Group",
  420. ]
  421. outputs = [
  422. "Deformer",
  423. "Morph Target",
  424. ]
  425. # now set up the traverse target...
  426. self.outputs.init_sockets(outputs)
  427. self.inputs.init_sockets(inputs)
  428. self.init_parameters(additional_parameters={"Name":None})
  429. self.set_traverse([("Deformer", "Deformer")])
  430. self.node_type = "LINK"
  431. self.prepared = True
  432. def GetxForm(self, trace_input="Object"):
  433. trace = trace_single_line(self, trace_input)
  434. for node in trace[0]:
  435. if (isinstance(node, deformable_types)):
  436. return node
  437. raise GraphError("%s is not connected to an upstream xForm" % self)
  438. def bRelationshipPass(self, bContext = None,):
  439. prGreen("Executing Morph Target Node")
  440. ob = None; relative = None
  441. # do NOT check if the object exists here. Just let the next node deal with that.
  442. try:
  443. ob = self.GetxForm().bGetObject().name
  444. except Exception as e: # this will and should throw an error if it fails
  445. ob = self.GetxForm().evaluate_input("Name")
  446. if self.inputs["Relative to"].is_linked:
  447. try:
  448. relative = self.GetxForm("Relative to").bGetObject().name
  449. except Exception as e: # same here
  450. prRed(f"Execution failed at {self}: no relative object found for morph target, despite link existing.")
  451. raise e
  452. vg = self.evaluate_input("Vertex Group") if self.evaluate_input("Vertex Group") else "" # just make sure it is a string
  453. mt={"object":ob, "vertex_group":vg, "relative_shape":relative}
  454. self.parameters["Morph Target"] = mt
  455. self.parameters["Name"] = ob # this is redundant but it's OK since accessing the mt is tedious
  456. self.executed = True
  457. class DeformerMorphTargetDeform(MantisDeformerNode):
  458. '''A node representing an armature deformer'''
  459. def __init__(self, signature, base_tree):
  460. super().__init__(signature, base_tree)
  461. inputs = [
  462. "Deformer",
  463. "Use Shape Key",
  464. "Use Offset",
  465. ]
  466. outputs = [
  467. "Deformer",
  468. ]
  469. self.outputs.init_sockets(outputs)
  470. self.inputs.init_sockets(inputs)
  471. self.init_parameters(additional_parameters={"Name":None})
  472. self.set_traverse([("Deformer", "Deformer")])
  473. self.node_type = "LINK"
  474. self.prepared = True
  475. self.executed = True
  476. setup_custom_property_inputs_outputs(self)
  477. # bpy.data.node_groups["Morph Deform.045"].nodes["Named Attribute.020"].data_type = 'FLOAT_VECTOR'
  478. # bpy.context.object.add_rest_position_attribute = True
  479. def reset_execution(self):
  480. return super().reset_execution()
  481. self.executed=True
  482. def gen_morph_target_modifier(self, xf, context):
  483. # first let's see if this is a no-op
  484. targets = []
  485. for k,v in self.inputs.items():
  486. if "Target" in k:
  487. targets.append(v)
  488. if not targets:
  489. return # nothing to do here.
  490. # at this point we make the node tree
  491. from .geometry_node_graphgen import gen_morph_target_nodes
  492. m, props_sockets = gen_morph_target_nodes(
  493. self.evaluate_input("Name"),
  494. xf.bGetObject(),
  495. targets,
  496. context,
  497. use_offset=self.evaluate_input("Use Offset"))
  498. self.bObject.append(m)
  499. evaluate_sockets(self, m, props_sockets)
  500. finish_drivers(self)
  501. def gen_shape_key_lattice(self, xf, context):
  502. # first check if we need to do anything
  503. targets = []
  504. for k,v in self.inputs.items():
  505. if "Target" in k:
  506. targets.append(v)
  507. if not targets:
  508. return # nothing to do here
  509. # TODO: deduplicate the code above here
  510. from time import time
  511. start_time = time()
  512. from bpy import data
  513. ob = xf.bGetObject()
  514. dg = context.view_layer.depsgraph
  515. dg.update()
  516. if xf.has_shape_keys == False:
  517. lat = ob.data.copy()
  518. ob.data = lat
  519. ob.add_rest_position_attribute = True
  520. ob.shape_key_clear()
  521. ob.shape_key_add(name='Basis', from_mix=False)
  522. else:
  523. lat = ob.data
  524. xf.has_shape_keys = True
  525. # first make a basis shape key
  526. keys, props_sockets, ={}, {}
  527. for i, t in enumerate(targets):
  528. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  529. if sk_ob is None:
  530. sk_ob = data.objects.new(mt_node.evaluate_input("Name"), data.meshes.new_from_object(ob))
  531. context.collection.objects.link(sk_ob)
  532. prOrange(f"WARN: no object found for f{mt_node}; creating duplicate of current object ")
  533. sk_ob = dg.id_eval_get(sk_ob)
  534. mt_name = sk_ob.name
  535. vg = mt_node.parameters["Morph Target"]["vertex_group"]
  536. if vg: mt_name = mt_name+"."+vg
  537. sk = ob.shape_key_add(name=mt_name, from_mix=False)
  538. # the shapekey data is absolute point data for each vertex, in order, very simple
  539. # SERIOUSLY IMPORTANT:
  540. # use the current position of the vertex AFTER SHAPE KEYS AND DEFORMERS
  541. # easiest way to do it is to eval the depsgraph
  542. # TODO: try and get it without depsgraph update, since that may be (very) slow
  543. sk_m = sk_ob.data#data.meshes.new_from_object(sk_ob, preserve_all_data_layers=True, depsgraph=dg)
  544. for j in range(len(m.vertices)):
  545. sk.data[j].co = sk_m.vertices[j].co # assume they match
  546. # data.meshes.remove(sk_m)
  547. sk.vertex_group = vg
  548. sk.slider_min = -10
  549. sk.slider_max = 10
  550. keys[mt_name]=sk
  551. props_sockets[mt_name]= ("Value."+str(i).zfill(3), 1.0)
  552. for i, t in enumerate(targets):
  553. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  554. if sk_ob is None: continue
  555. if rel := mt_node.parameters["Morph Target"]["relative_shape"]:
  556. sk = keys.get(mt_name)
  557. sk.relative_key = keys.get(rel)
  558. self.bObject.append(sk.id_data)
  559. evaluate_sockets(self, sk.id_data, props_sockets)
  560. finish_drivers(self)
  561. prWhite(f"Initializing morph target took {time() -start_time} seconds")
  562. def gen_shape_key(self, xf, context):
  563. # TODO: make this a feature of the node definition that appears only when there are no prior deformers - and shows a warning!
  564. # TODO: the below works well, but it is quite slow. It does not seem to have better performence. Its only advantage is export to FBX.
  565. # there are a number of things I need to fix here
  566. # - reuse shape keys if possible
  567. # - figure out how to make this a lot faster
  568. # - edit the xForm stuff to delete drivers from shape key ID's, since they belong to the Key, not the Object.
  569. # first check if we need to do anythign
  570. targets = []
  571. for k,v in self.inputs.items():
  572. if "Target" in k:
  573. targets.append(v)
  574. if not targets:
  575. return # nothing to do here
  576. from time import time
  577. start_time = time()
  578. from bpy import data
  579. ob = xf.bGetObject()
  580. dg = context.view_layer.depsgraph
  581. dg.update()
  582. if xf.has_shape_keys == False:
  583. match ob.type:
  584. case 'MESH':
  585. ob_data = data.meshes.new_from_object(ob, preserve_all_data_layers=True, depsgraph=dg)
  586. case 'LATTICE':
  587. ob_data = ob.data.copy()
  588. ob.data = ob_data
  589. ob.add_rest_position_attribute = True
  590. ob.shape_key_clear()
  591. ob.shape_key_add(name='Basis', from_mix=False)
  592. else:
  593. ob_data = ob.data
  594. xf.has_shape_keys = True
  595. # using the built-in shapekey feature is actually a lot harder in terms of programming because I need...
  596. # min/max, as it is just not a feature of the GN version
  597. # to carry info from the morph target node regarding relative shapes and vertex groups and all that
  598. # the drivers may be more difficult to apply, too.
  599. # hafta make new geometry for the object and add shape keys and all that
  600. # the benefit to all this being exporting to game engines via .fbx
  601. # first make a basis shape key
  602. keys={}
  603. props_sockets={}
  604. for i, t in enumerate(targets):
  605. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  606. if sk_ob is None:
  607. sk_ob = data.objects.new(mt_node.evaluate_input("Name"), data.meshes.new_from_object(ob))
  608. context.collection.objects.link(sk_ob)
  609. prOrange(f"WARN: no object found for f{mt_node}; creating duplicate of current object ")
  610. sk_ob = dg.id_eval_get(sk_ob)
  611. mt_name = sk_ob.name
  612. vg = mt_node.parameters["Morph Target"]["vertex_group"]
  613. if vg: mt_name = mt_name+"."+vg
  614. sk = ob.shape_key_add(name=mt_name, from_mix=False)
  615. # the shapekey data is absolute point data for each vertex, in order, very simple
  616. # SERIOUSLY IMPORTANT:
  617. # use the current position of the vertex AFTER SHAPE KEYS AND DEFORMERS
  618. # easiest way to do it is to eval the depsgraph
  619. # TODO: try and get it without depsgraph update, since that may be (very) slow
  620. sk_m = sk_ob.data#data.meshes.new_from_object(sk_ob, preserve_all_data_layers=True, depsgraph=dg)
  621. match ob.type:
  622. case 'MESH':
  623. for j in range(len(ob_data.vertices)):
  624. sk.data[j].co = sk_m.vertices[j].co # assume they match
  625. case 'LATTICE':
  626. for j in range(len(ob.data.points)):
  627. sk.data[j].co = sk_m.points[j].co_deform
  628. # data.meshes.remove(sk_m)
  629. sk.vertex_group = vg
  630. sk.slider_min = -10
  631. sk.slider_max = 10
  632. keys[mt_name]=sk
  633. props_sockets[mt_name]= ("Value."+str(i).zfill(3), 1.0)
  634. for i, t in enumerate(targets):
  635. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  636. if sk_ob is None: continue
  637. if rel := mt_node.parameters["Morph Target"]["relative_shape"]:
  638. sk = keys.get(mt_name)
  639. sk.relative_key = keys.get(rel)
  640. self.bObject.append(sk.id_data)
  641. evaluate_sockets(self, sk.id_data, props_sockets)
  642. finish_drivers(self)
  643. prWhite(f"Initializing morph target took {time() -start_time} seconds")
  644. def bFinalize(self, bContext=None):
  645. prGreen(f"Executing Morph Deform node {self}")
  646. use_shape_keys = self.evaluate_input("Use Shape Key")
  647. # if there is a not a prior deformer then there should be an option to use plain 'ol shape keys
  648. # GN is always desirable as an option though because it can be baked & many other reasons
  649. if use_shape_keys: # check and see if we can.
  650. if self.inputs.get("Deformer"): # I guess this isn't available in some node group contexts... bad. FIXME
  651. if (links := self.inputs["Deformer"].links):
  652. if not links[0].from_node.parameters.get("Use Shape Key"):
  653. use_shape_keys = False
  654. elif links[0].from_node.parameters.get("Use Shape Key") == False:
  655. use_shape_keys = False
  656. self.parameters["Use Shape Key"] = use_shape_keys
  657. for xf in self.GetxForm():
  658. # Lattice objects do not support geometry nodes at this time.
  659. ob = xf.bGetObject()
  660. if ob and ob.type == 'LATTICE':
  661. if not use_shape_keys:
  662. raise NotImplementedError("Blender does not support Geometry Nodes for Lattices. "
  663. "Enable 'Shape Key' and execute again.")
  664. self.gen_shape_key(xf, bContext)
  665. elif use_shape_keys:
  666. self.gen_shape_key(xf, bContext)
  667. else:
  668. self.gen_morph_target_modifier(xf, bContext)
  669. class DeformerSurfaceDeform(MantisDeformerNode):
  670. '''A node representing an surface deform modifier'''
  671. def __init__(self, signature, base_tree):
  672. super().__init__(signature, base_tree, SurfaceDeformSockets)
  673. # now set up the traverse target...
  674. self.init_parameters(additional_parameters={"Name":None})
  675. self.set_traverse([("Deformer", "Deformer")])
  676. self.prepared = True
  677. def GetxForm(self, socket="Deformer"):
  678. if socket == "Deformer":
  679. return super().GetxForm()
  680. else:
  681. trace_xForm_back(self, socket)
  682. def bRelationshipPass(self, bContext = None,):
  683. self.executed = True
  684. def bFinalize(self, bContext=None):
  685. prGreen("Executing Surface Deform Node")
  686. mod_name = self.evaluate_input("Name")
  687. for xf in self.GetxForm():
  688. ob = xf.bGetObject()
  689. d = ob.modifiers.new(mod_name, type='SURFACE_DEFORM')
  690. if d is None:
  691. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  692. self.bObject.append(d)
  693. self.get_target_and_subtarget(d, input_name="Target")
  694. props_sockets = self.gen_property_socket_map()
  695. evaluate_sockets(self, d, props_sockets)
  696. def bModifierApply(self, bContext=None):
  697. from bpy import ops
  698. standard_modifier_bind(self, bContext, ops.object.surfacedeform_bind)
  699. class DeformerMeshDeform(MantisDeformerNode):
  700. '''A node representing a mesh deform modifier'''
  701. def __init__(self, signature, base_tree):
  702. super().__init__(signature, base_tree, MeshDeformSockets)
  703. # now set up the traverse target...
  704. self.init_parameters(additional_parameters={"Name":None})
  705. self.set_traverse([("Deformer", "Deformer")])
  706. self.prepared = True
  707. def GetxForm(self, socket="Deformer"):
  708. if socket == "Deformer":
  709. return super().GetxForm()
  710. else:
  711. trace_xForm_back(self, socket)
  712. def bRelationshipPass(self, bContext = None,):
  713. self.executed = True
  714. def bFinalize(self, bContext=None):
  715. prGreen("Executing Mesh Deform Node")
  716. mod_name = self.evaluate_input("Name")
  717. for xf in self.GetxForm():
  718. ob = xf.bGetObject()
  719. d = ob.modifiers.new(mod_name, type='MESH_DEFORM')
  720. if d is None:
  721. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  722. self.bObject.append(d)
  723. self.get_target_and_subtarget(d, input_name="Object")
  724. props_sockets = self.gen_property_socket_map()
  725. evaluate_sockets(self, d, props_sockets)
  726. def bModifierApply(self, bContext=None):
  727. from bpy import ops
  728. standard_modifier_bind(self, bContext, ops.object.meshdeform_bind)
  729. class DeformerLatticeDeform(MantisDeformerNode):
  730. '''A node representing a lattice deform modifier'''
  731. def __init__(self, signature, base_tree):
  732. super().__init__(signature, base_tree, LatticeDeformSockets)
  733. # now set up the traverse target...
  734. self.init_parameters(additional_parameters={"Name":None})
  735. self.set_traverse([("Deformer", "Deformer")])
  736. self.prepared = True
  737. def GetxForm(self, socket="Deformer"):
  738. if socket == "Deformer":
  739. return super().GetxForm()
  740. else:
  741. trace_xForm_back(self, socket)
  742. def bRelationshipPass(self, bContext = None,):
  743. self.executed = True
  744. def bFinalize(self, bContext=None):
  745. prGreen("Executing Lattice Deform Node")
  746. mod_name = self.evaluate_input("Name")
  747. for xf in self.GetxForm():
  748. ob = xf.bGetObject()
  749. d = ob.modifiers.new(mod_name, type='LATTICE')
  750. if d is None:
  751. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  752. self.bObject.append(d)
  753. self.get_target_and_subtarget(d, input_name="Object")
  754. props_sockets = self.gen_property_socket_map()
  755. evaluate_sockets(self, d, props_sockets)
  756. class DeformerSmoothCorrectiveDeform(MantisDeformerNode):
  757. '''A node representing a corrective smooth deform modifier'''
  758. def __init__(self, signature, base_tree):
  759. super().__init__(signature, base_tree, SmoothDeformSockets)
  760. # now set up the traverse target...
  761. self.init_parameters(additional_parameters={"Name":None})
  762. self.set_traverse([("Deformer", "Deformer")])
  763. self.prepared = True
  764. def GetxForm(self, socket="Deformer"):
  765. if socket == "Deformer":
  766. return super().GetxForm()
  767. else:
  768. trace_xForm_back(self, socket)
  769. def bRelationshipPass(self, bContext = None,):
  770. self.executed = True
  771. def bFinalize(self, bContext=None):
  772. prGreen("Executing Smooth Deform Node")
  773. mod_name = self.evaluate_input("Name")
  774. for xf in self.GetxForm():
  775. ob = xf.bGetObject()
  776. d = ob.modifiers.new(mod_name, type='CORRECTIVE_SMOOTH')
  777. if d is None:
  778. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  779. self.bObject.append(d)
  780. # self.get_target_and_subtarget(d, input_name="Object")
  781. props_sockets = self.gen_property_socket_map()
  782. evaluate_sockets(self, d, props_sockets)