Last active
February 13, 2022 17:27
-
-
Save n-burk/f9ed11d0342e3d1587353f39d824e60d to your computer and use it in GitHub Desktop.
Blender geo node post animation (local space) sculpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
############################################## | |
# Select mesh and run script, new collection is created | |
# and keyable floats are dropped on mesh's new geoNode | |
# sculpting in action | |
# https://drive.google.com/file/d/1jDXskWJ0mx_aJMjBoaeRhuHS8vBOhwxT/view?usp=sharing | |
# | |
############################################## | |
import bpy | |
def dupShapes(shape, sculptCollection): | |
filledFrame ='{}'.format(bpy.context.scene.frame_current).zfill(4) | |
#sculptshape | |
bpy.ops.object.duplicate({"object" : shape}) | |
modShape = bpy.context.selected_objects[0] | |
for mod in modShape.modifiers: | |
bpy.ops.object.modifier_apply({"object" : modShape}, modifier=mod.name) | |
modShape.name = '{}.{}.sculptShape'.format(shape.name, filledFrame) | |
for collection in modShape.users_collection: | |
collection.objects.unlink(modShape) | |
bpy.ops.object.parent_clear() | |
sculptCollection.objects.link(modShape) | |
modShape.select_set(False) | |
modShape.parent = None | |
shape.select_set(True) | |
bpy.ops.object.duplicate({"object" : shape}) | |
baseShape = bpy.context.selected_objects[0] | |
bpy.ops.object.select_all(action='DESELECT') | |
baseShape.select_set(True) | |
baseShape.name = '{}.{}.baseShape'.format(shape.name, filledFrame) | |
baseShape.parent = None | |
for mod in baseShape.modifiers: | |
bpy.ops.object.modifier_apply({"object" : baseShape} ,modifier=mod.name) | |
for collection in baseShape.users_collection: | |
collection.objects.unlink(baseShape) | |
bpy.ops.object.parent_clear() | |
sculptCollection.objects.link(baseShape) | |
baseShape.hide_viewport = True | |
baseShape.hide_render = True | |
modShape.hide_render = True | |
return [modShape, baseShape] | |
def sculptCollection(): | |
found = False | |
for collection in bpy.data.collections: | |
if 'sculpt' in collection: | |
return collection | |
sculptCollection = bpy.data.collections.new('sculpt') | |
bpy.context.scene.collection.children.link(sculptCollection) | |
sculptCollection['sculpt'] = 1 | |
return sculptCollection | |
def recursiveChainFinder(node, attrIndex): | |
foundNode = None | |
if node.inputs[attrIndex].links: | |
inNode = node.inputs[attrIndex].links[0].from_node | |
foundNode = recursiveChainFinder(inNode, attrIndex) | |
return foundNode | |
return node | |
def geomNodeSetup(shape, baseShape, modShape): | |
filledFrame ='{}'.format(bpy.context.scene.frame_current).zfill(4) | |
if not 'sculpt' in shape.data: | |
shape.modifiers.new('SculptFrame', 'NODES') | |
sculptMod = shape.modifiers['SculptFrame'] | |
shape.data['sculpt'] = sculptMod.name | |
setPos = sculptMod.node_group.nodes.new('GeometryNodeSetPosition') | |
shape.data['setPos'] = setPos.name | |
inGeo = sculptMod.node_group.nodes['Group Input'] | |
outGeo = sculptMod.node_group.nodes['Group Output'] | |
sculptMod.node_group.links.new(inGeo.outputs['Geometry'], setPos.inputs['Geometry']) | |
sculptMod.node_group.links.new(setPos.outputs['Geometry'], outGeo.inputs['Geometry']) | |
sculptMod = shape.modifiers[shape.data['sculpt']] | |
setPos = sculptMod.node_group.nodes[shape.data['setPos']] | |
#grab old input | |
posInput = setPos.inputs['Offset'].links[0].from_node if setPos.inputs['Offset'].links else None | |
newVecAdd = sculptMod.node_group.nodes.new('ShaderNodeVectorMath') | |
frameMag = sculptMod.node_group.inputs.new("NodeSocketFloatFactor", "{}_sculptMag".format(filledFrame)) | |
frameMag.min_value = 0.0 | |
frameMag.max_value = 1.0 | |
frameMag.default_value = 1.0 | |
if posInput: | |
recursedInput = recursiveChainFinder(posInput, 0) | |
sculptMod.node_group.links.new(newVecAdd.outputs['Vector'], recursedInput.inputs[0]) | |
else: | |
sculptMod.node_group.links.new(newVecAdd.outputs['Vector'], setPos.inputs['Offset']) | |
baseInfo = sculptMod.node_group.nodes.new('GeometryNodeObjectInfo') | |
baseInfo.inputs['Object'].default_value = baseShape | |
modInfo = sculptMod.node_group.nodes.new('GeometryNodeObjectInfo') | |
modInfo.inputs['Object'].default_value = modShape | |
posId = sculptMod.node_group.nodes.new('GeometryNodeInputPosition') | |
baseCapPos = sculptMod.node_group.nodes.new('GeometryNodeAttributeTransfer') | |
modCapPos = sculptMod.node_group.nodes.new('GeometryNodeAttributeTransfer') | |
sculptMod.node_group.links.new(baseInfo.outputs['Geometry'], baseCapPos.inputs['Target']) | |
sculptMod.node_group.links.new(modInfo.outputs['Geometry'], modCapPos.inputs['Target']) | |
baseCapPos.data_type = 'FLOAT_VECTOR' | |
modCapPos.data_type = 'FLOAT_VECTOR' | |
baseCapPos.mapping = 'INDEX' | |
modCapPos.mapping = 'INDEX' | |
sculptMod.node_group.links.new(posId.outputs['Position'], baseCapPos.inputs['Attribute']) | |
sculptMod.node_group.links.new(posId.outputs['Position'], modCapPos.inputs['Attribute']) | |
vecSub = sculptMod.node_group.nodes.new('ShaderNodeVectorMath') | |
vecSub.operation = 'SUBTRACT' | |
vecMag = sculptMod.node_group.nodes.new('ShaderNodeVectorMath') | |
vecMag.operation = 'MULTIPLY' | |
sculptMod.node_group.links.new(modCapPos.outputs['Attribute'], vecSub.inputs[0]) | |
sculptMod.node_group.links.new(baseCapPos.outputs['Attribute'], vecSub.inputs[1]) | |
sculptMod.node_group.links.new(vecSub.outputs['Vector'], vecMag.inputs[0]) | |
sculptMod.node_group.links.new(sculptMod.node_group.nodes['Group Input'].outputs[frameMag.name], vecMag.inputs[1]) | |
sculptMod.node_group.links.new(vecMag.outputs['Vector'], newVecAdd.inputs[1]) | |
sel = bpy.context.selected_objects[0] | |
sculptCollection = sculptCollection() | |
sculptShapes = dupShapes(sel, sculptCollection) | |
geomNodeSetup(sel, sculptShapes[1], sculptShapes[0]) | |
bpy.ops.object.select_all(action='DESELECT') | |
sel.select_set(True) | |
bpy.context.view_layer.objects.active = sel |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment