Skip to content

Instantly share code, notes, and snippets.

@unwave
Created April 24, 2024 02:01
Show Gist options
  • Save unwave/7d360719853b67d7a1735700a34b2b6e to your computer and use it in GitHub Desktop.
Save unwave/7d360719853b67d7a1735700a34b2b6e to your computer and use it in GitHub Desktop.
traverse bmesh and decide on places and orientations to put physics forces
import bpy
import bmesh
from blend_converter import bl_utils
BASE_LENGTH = 2
MAX_LENGTH = 1.5 * BASE_LENGTH
TRAVERSE_SELECT = False
bl_utils.select(bpy.data.objects['level'])
bpy.ops.object.duplicate(linked=False)
level_copy = bpy.context.object
bl_utils.select(level_copy)
level_copy.modifiers['Skin'].show_viewport = False
level_path_object = bl_utils.convert_to_mesh(level_copy)
pushers_collection = bpy.data.collections.new('pushers')
bpy.context.scene.collection.children.link(pushers_collection)
def get_empty():
empty_obj = bpy.data.objects.new("__blood_pusher__", None)
pushers_collection.objects.link(empty_obj)
empty_obj.empty_display_type = 'CUBE'
return empty_obj
def get_root_point_index(object):
for skin_v, v in zip(object.data.skin_vertices[0].data, object.data.vertices):
if skin_v.use_root:
return v.index
bl_utils.select(level_path_object)
bpy.ops.object.mode_set(mode='OBJECT')
skin_root_index = get_root_point_index(level_path_object)
bpy.ops.object.editmode_toggle()
bm = bmesh.from_edit_mesh(level_path_object.data)
bm.verts.ensure_lookup_table()
root_vertex = bm.verts[skin_root_index]
if TRAVERSE_SELECT:
bpy.ops.mesh.select_all(action='DESELECT')
segment_start_verts = []
# tuple <start, root>
target_verts = []
# tuple <target, prev>
seen_edges = set()
def get_root_vert(start_vert):
if not seen_edges:
return None
for edge in start_vert.link_edges:
if edge in seen_edges:
return edge.other_vert(start_vert)
if TRAVERSE_SELECT:
bpy.ops.mesh.select_all(action='DESELECT')
start_vert.select = True
raise Exception(f"root_vert not found for: {start_vert}")
def traverse(init_vert):
root_vert = get_root_vert(init_vert)
if root_vert is None:
# the skin modfier root
assert len(init_vert.link_edges) == 1
skin_mod_root_edge = init_vert.link_edges[0]
root_vert = init_vert
init_vert = skin_mod_root_edge.other_vert(init_vert)
seen_edges.add(skin_mod_root_edge)
segment_start_verts.append((init_vert, root_vert))
else:
segment_start_verts.append((init_vert, root_vert))
if TRAVERSE_SELECT:
init_vert.select = True
length = 0
pool = [init_vert]
while pool:
vert = pool.pop(0)
edges = vert.link_edges
if len(edges) == 1:
# ends of the polylines
if TRAVERSE_SELECT:
vert.select = True
elif len(edges) == 2:
for edge in edges:
if edge in seen_edges:
continue
seen_edges.add(edge)
length = length + edge.calc_length()
other_vert = edge.other_vert(vert)
if length >= MAX_LENGTH and len(other_vert.link_edges) == 2:
target_verts.append((other_vert, vert))
if TRAVERSE_SELECT:
other_vert.select = True
length = 0
pool.append(other_vert)
else:
for edge in edges:
if edge in seen_edges:
continue
seen_edges.add(edge)
traverse(edge.other_vert(vert))
traverse(root_vertex)
def get_tangent_quat(vert, prev_vert):
return (vert.co - prev_vert.co).normalized().to_track_quat('Z')
for start, root in segment_start_verts:
quat = get_tangent_quat(start, root)
empty_obj = get_empty()
empty_obj.matrix_world = quat.to_matrix().to_4x4()
empty_obj.scale = (1, 1, BASE_LENGTH)
empty_obj.location = start.co
for target, prev in target_verts:
quat = get_tangent_quat(target, prev)
empty_obj = get_empty()
empty_obj.matrix_world = quat.to_matrix().to_4x4()
empty_obj.scale = (1, 1, BASE_LENGTH)
empty_obj.location = target.co
bmesh.update_edit_mesh(level_path_object.data, loop_triangles=False, destructive=False)
bpy.ops.object.editmode_toggle()
bpy.data.objects.remove(level_path_object)
@unwave
Copy link
Author

unwave commented Apr 24, 2024

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment