geometry_node_graphgen.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. from .utilities import (prRed, prGreen, prPurple, prWhite, prOrange,
  2. wrapRed, wrapGreen, wrapPurple, wrapWhite,
  3. wrapOrange,)
  4. def gen_morph_target_nodes(mod_name, mod_ob, targets, context, use_offset=True):
  5. from bpy import data
  6. modifier = mod_ob.modifiers.new(mod_name, type='NODES')
  7. mod_ob.add_rest_position_attribute = True
  8. ng = data.node_groups.new(mod_name, "GeometryNodeTree")
  9. ng.interface.new_socket("Geometry", in_out="INPUT", socket_type="NodeSocketGeometry")
  10. ng.interface.new_socket("Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry")
  11. inp = ng.nodes.new("NodeGroupInput")
  12. out = ng.nodes.new("NodeGroupOutput")
  13. # TODO CLEANUP here
  14. if (position := ng.nodes.get("Position")) is None: position = ng.nodes.new("GeometryNodeInputPosition")
  15. if (index := ng.nodes.get("Index")) is None: index = ng.nodes.new("GeometryNodeInputIndex")
  16. rest_position = ng.nodes.new("GeometryNodeInputNamedAttribute")
  17. rest_position.inputs["Name"].default_value="rest_position"
  18. rest_position.data_type = 'FLOAT_VECTOR'
  19. if use_offset == False:
  20. rest_position = position
  21. add_these = []
  22. props_sockets={}
  23. object_map = {}
  24. for i, t in enumerate(targets):
  25. mt_node = t.links[0].from_node
  26. mt_ob = mt_node.GetxForm().bGetObject()
  27. if mt_ob is None: # create it
  28. mt_ob = data.objects.new(mt_node.evaluate_input("Name"), data.meshes.new_from_object(self_ob))
  29. context.collection.objects.link(mt_ob)
  30. prOrange(f"WARN: no object found for f{mt_node}; creating duplicate of current object ")
  31. mt_name = mt_ob.name
  32. vg = mt_node.parameters["Morph Target"]["vertex_group"]
  33. if vg: mt_name = mt_name+"."+vg
  34. try:
  35. ob_relative = t.links[0].from_node.inputs["Relative to"].links[0].from_node.bGetObject()
  36. except IndexError:
  37. ob_relative = None
  38. ng.interface.new_socket(mt_name, in_out = "INPUT", socket_type="NodeSocketObject")
  39. ng.interface.new_socket(mt_name+" Value", in_out = "INPUT", socket_type="NodeSocketFloat")
  40. ob_node = ng.nodes.new("GeometryNodeObjectInfo")
  41. sample_index = ng.nodes.new("GeometryNodeSampleIndex"); sample_index.data_type = 'FLOAT_VECTOR'
  42. subtract = ng.nodes.new("ShaderNodeVectorMath"); subtract.operation="SUBTRACT"
  43. scale1 = ng.nodes.new("ShaderNodeVectorMath"); scale1.operation="SCALE"
  44. ng.links.new(input=inp.outputs[mt_name], output=ob_node.inputs["Object"])
  45. ng.links.new(input=index.outputs["Index"], output=sample_index.inputs["Index"])
  46. ng.links.new(input=position.outputs["Position"], output=sample_index.inputs["Value"])
  47. ng.links.new(input=sample_index.outputs["Value"], output=subtract.inputs[0])
  48. ng.links.new(input=ob_node.outputs["Geometry"], output=sample_index.inputs["Geometry"])
  49. if ob_relative: # TODO: this should also be exposed as an input
  50. ob_node1 = ng.nodes.new("GeometryNodeObjectInfo"); ob_node1.inputs["Object"].default_value = ob_relative
  51. sample_index1 = ng.nodes.new("GeometryNodeSampleIndex"); sample_index1.data_type = 'FLOAT_VECTOR'
  52. ng.links.new(input=index.outputs["Index"], output=sample_index1.inputs["Index"])
  53. ng.links.new(input=position.outputs["Position"], output=sample_index1.inputs["Value"])
  54. ng.links.new(input=ob_node1.outputs["Geometry"], output=sample_index1.inputs["Geometry"])
  55. ng.links.new(input=sample_index1.outputs["Value"], output=subtract.inputs[1])
  56. else:
  57. # ng.links.new(input=rest_position.outputs["Attribute"], output=subtract.inputs[1])
  58. ng.links.new(input=rest_position.outputs[0], output=subtract.inputs[1])
  59. ng.links.new(input=subtract.outputs["Vector"], output=scale1.inputs[0])
  60. # TODO: this should be exposed as a node tree input
  61. if vg:= mt_node.evaluate_input("Vertex Group"): # works
  62. vg_att = ng.nodes.new("GeometryNodeInputNamedAttribute"); vg_att.inputs["Name"].default_value=vg
  63. multiply = ng.nodes.new("ShaderNodeMath"); multiply.operation = "MULTIPLY"
  64. ng.links.new(input=vg_att.outputs["Attribute"], output=multiply.inputs[1])
  65. ng.links.new(input=inp.outputs[mt_name+" Value"], output=multiply.inputs[0])
  66. ng.links.new(input=multiply.outputs[0], output=scale1.inputs["Scale"])
  67. else:
  68. ng.links.new(input=inp.outputs[mt_name+" Value"], output=scale1.inputs["Scale"])
  69. add_these.append(scale1)
  70. object_map["Socket_"+str((i+1)*2)]=mt_node.GetxForm().bGetObject()
  71. props_sockets["Socket_"+str((i+1)*2+1)]= ("Value."+str(i).zfill(3), 1.0)
  72. set_position = ng.nodes.new("GeometryNodeSetPosition")
  73. bake = ng.nodes.new("GeometryNodeBake")
  74. ng.links.new(inp.outputs["Geometry"], output=set_position.inputs["Geometry"])
  75. ng.links.new(set_position.outputs["Geometry"], output=bake.inputs[0])
  76. ng.links.new(bake.outputs[0], output=out.inputs[0])
  77. if use_offset == True:
  78. prev_node = ng.nodes.new("FunctionNodeInputVector")
  79. else:
  80. prev_node = position
  81. for i, node in enumerate(add_these):
  82. add = ng.nodes.new("ShaderNodeVectorMath"); add.operation="ADD"
  83. ng.links.new(prev_node.outputs[0], output=add.inputs[0])
  84. ng.links.new(node.outputs[0], output=add.inputs[1])
  85. prev_node = add
  86. if use_offset == True:
  87. ng.links.new(add.outputs[0], output=set_position.inputs["Offset"])
  88. else:
  89. ng.links.new(add.outputs[0], output=set_position.inputs["Position"])
  90. try:
  91. from .utilities import SugiyamaGraph
  92. SugiyamaGraph(ng, 12)
  93. except ImportError:
  94. pass # this is unlikely to fail since I package the wheel but if it does it shouldn't crash out.
  95. for socket, ob in object_map.items():
  96. modifier[socket]=ob
  97. return modifier, props_sockets