-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathutils.py
More file actions
138 lines (107 loc) · 4.12 KB
/
Copy pathutils.py
File metadata and controls
138 lines (107 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import hashlib
import math
import bpy
def console_get():
for area in bpy.context.screen.areas:
if area.type == 'CONSOLE':
for space in area.spaces:
if space.type == 'CONSOLE':
for region in area.regions:
if region.type == 'WINDOW':
return area, space, region
return None, None, None
def console_write(text):
area, space, region = console_get()
if area is None:
return
context_override = bpy.context.copy()
context_override.update({
"space": space,
"area": area,
"region": region,
})
with bpy.context.temp_override(**context_override):
for line in text.split("\n"):
bpy.ops.console.scrollback_append(text=line, type='OUTPUT')
print = lambda x: console_write(str(x))
def print_rot_loc_matrix(intro: str, data):
import mathutils
loc = mathutils.Vector([0,0,0])
if isinstance(data, mathutils.Quaternion):
rot = data
else:
loc, rot, _ = data.decompose()
rot = rot.to_euler()
print(f'{intro}:\tRX={math.degrees(rot.x):> z6.1f}\tRY={math.degrees(rot.y):> z6.1f}\tRZ={math.degrees(rot.z):> z6.1f}\tX={loc.x: 1.3f}\tY={loc.y: 1.3f}\tZ={loc.z: 1.3f}')
def flip_image_y(image):
import itertools
width, height = image.size
row_size = width * image.channels
pixels_orig = image.pixels[:]
pixels = (pixels_orig[(height - row - 1) * row_size: (height - row) * row_size] for row in range(height))
pixels = itertools.chain.from_iterable(pixels)
pixels = list(pixels)
image.pixels[:] = pixels
return image
def get_hash(s: str) -> str:
return hashlib.md5(bytes(s, 'utf8')).hexdigest()
def add_driver(obj, obj_prop_path: str, target_id: str, target_data_path: str, fallback_value, index: int = -1):
if index != -1:
drivers = [obj.driver_add(obj_prop_path, index).driver]
else:
drivers = [d.driver for d in obj.driver_add(obj_prop_path, index)]
for driver in drivers:
var = driver.variables.new()
driver.type = 'SUM'
var.targets[0].id = target_id
# TODO set var.targets[0] type to armature
var.targets[0].data_path = target_data_path
var.targets[0].use_fallback_value = True
var.targets[0].fallback_value = fallback_value
return drivers
def get_weighted_vertex_groups(obj):
used_groups = {g.group for v in obj.data.vertices for g in v.groups if g.weight > 0.001}
return [v for v in obj.vertex_groups if v.index in used_groups]
def get_single_bone_name(obj, vertex_groups, vertex_group_whitelist) -> str:
if obj.parent_type == 'BONE' and obj.parent_bone != '':
return obj.parent_bone
vertex_groups = [v for v in vertex_groups if v.name in vertex_group_whitelist]
if len(vertex_groups) != 1:
return None
for v in obj.data.vertices:
if len(v.groups) == 0:
return None
max_veight = max(g.weight for g in v.groups)
if max_veight < 0.997:
return None
return vertex_groups[0].name
def can_be_force_skinned(obj):
armature = get_armature(obj)
if armature is not None:
bone_names = {b.name for b in armature.data.bones}
else:
bone_names = set()
vertex_groups = get_weighted_vertex_groups(obj)
return get_single_bone_name(obj, vertex_groups, bone_names) is not None or len(vertex_groups) == 0
def iter_animatable():
yield from bpy.data.objects
for i in bpy.data.materials:
yield i
if (node_tree := getattr(i, 'node_tree', None)) is not None:
yield node_tree
def get_armature(mesh_obj):
if mesh_obj.parent is not None and mesh_obj.parent.type == 'ARMATURE':
return mesh_obj.parent
for m in mesh_obj.modifiers:
if m.type == 'ARMATURE':
return m.object
def ensure_channelbag_exists(action, slot):
try:
layer = action.layers[0]
except IndexError:
layer = action.layers.new("Layer")
try:
strip = layer.strips[0]
except IndexError:
strip = layer.strips.new(type='KEYFRAME')
return strip.channelbag(slot, ensure=True)