Working on stuff

This commit is contained in:
Vladislav Khorev committed 2026-04-15 16:51:55 +03:00
1 parent f708843747
commit a47306533e
2 files changed
+293

No files matched your search

+228
View File
@@ -0,0 +1,228 @@
import bpy
import bmesh
#!
# Имена mesh и арматуры
mesh_name = "Joined"
armature_name = "Armature"
# Находим объект mesh по имени
mesh_obj = bpy.data.objects.get(mesh_name)
# Находим объект арматуры по имени
armature_obj = bpy.data.objects.get(armature_name)
# Устанавливаем текущий кадр на 0
bpy.context.scene.frame_set(0)
# Принудительно обновляем сцену, чтобы применить анимацию
bpy.context.view_layer.update()
# Открываем файл для записи
with open("C:\\Work\\Media\\witcher\\2026-04-13\\output\\gg_stand_idle001.txt", "w") as file:
# Обработка арматуры и анимации
if armature_obj and armature_obj.type == 'ARMATURE':
file.write("=== Armature Matrix ===\n")
for row in armature_obj.matrix_world:
file.write(f"{row}\n")
file.write(f"=== Armature Bones: {len(armature_obj.data.bones)}\n")
for bone in armature_obj.data.bones:
# Записываем имя кости, длину и связи
file.write(f"Bone: {bone.name}\n")
file.write(f" HEAD_LOCAL: {bone.head_local}\n")
file.write(f" TAIL_LOCAL: {bone.tail_local}\n")
file.write(f" Length: {(bone.tail_local - bone.head_local).length}\n")
for row in bone.matrix:
file.write(f" {row}\n")
file.write(f" Parent: {bone.parent.name if bone.parent else 'None'}\n")
file.write(f" Children: {[child.name for child in bone.children]}\n")
# Обработка mesh
if mesh_obj and mesh_obj.type == 'MESH':
# Создаем копию mesh, чтобы не изменять оригинал
mesh_copy = mesh_obj.copy()
mesh_copy.data = mesh_obj.data.copy()
bpy.context.collection.objects.link(mesh_copy)
# Убедимся, что объект активен
bpy.context.view_layer.objects.active = mesh_copy
mesh_copy.select_set(True)
# Применяем модификатор Armature (если он есть)
for modifier in mesh_copy.modifiers:
if modifier.type == 'ARMATURE':
# Включаем модификатор, если он отключен
if not modifier.show_viewport:
modifier.show_viewport = True
if not modifier.show_render:
modifier.show_render = True
# Проверяем, что модификатор связан с арматурой
if modifier.object is None:
print(f"Модификатор Armature на объекте {mesh_copy.name} не связан с арматурой. Пропускаем.")
continue
# Временно применяем модификатор, чтобы получить правильные координаты вершин
try:
bpy.ops.object.modifier_apply(modifier=modifier.name)
except RuntimeError as e:
print(f"Ошибка при применении модификатора Armature: {e}")
continue
# Переходим в режим редактирования
bpy.ops.object.mode_set(mode='EDIT')
# Получаем BMesh представление mesh
bm = bmesh.from_edit_mesh(mesh_copy.data)
# Записываем список вершин
file.write(f"===Vertices: {len(bm.verts)}\n")
for vertex in bm.verts:
file.write(f"Vertex {vertex.index}: {vertex.co}\n")
# Убедимся, что у меша есть UV слой
uv_layer = bm.loops.layers.uv.active
if not uv_layer:
file.write("UV слой не найден.\n")
if uv_layer:
file.write(f"===UV Coordinates:\n")
file.write(f"Face count: {len(bm.faces)}\n")
for face in bm.faces:
file.write(f"Face {face.index}\n")
file.write(f"UV Count: {len(face.loops)}\n")
for loop in face.loops:
uv_coords = loop[uv_layer].uv
file.write(f" UV {uv_coords}\n")
# Записываем нормали
file.write(f"===Normals:\n")
for vertex in bm.verts:
file.write(f"Vertex {vertex.index}: Normal {vertex.normal}\n")
# Записываем треугольники (индексы вершин)
file.write(f"===Triangles: {len(bm.faces)}\n")
for face in bm.faces:
if len(face.verts) == 3: # Проверяем, что это треугольник
verts_indices = [vert.index for vert in face.verts]
file.write(f"Triangle: {verts_indices}\n")
# Возвращаемся в объектный режим
bpy.ops.object.mode_set(mode='OBJECT')
# Записываем веса вершин
file.write("=== Vertex Weights (Max 5 bones per vertex) ===\n")
MAX_BONES = 5
for vertex in mesh_copy.data.vertices:
# Извлекаем все группы и веса для текущей вершины
all_weights = []
for group_element in vertex.groups:
all_weights.append({
'index': group_element.group,
'weight': group_element.weight
})
# Если костей больше лимита, фильтруем и перераспределяем
if len(all_weights) > MAX_BONES:
# Сортируем по весу (от большего к меньшему)
all_weights.sort(key=lambda x: x['weight'], reverse=True)
# Берем только топ-5
kept_weights = all_weights[:MAX_BONES]
# Считаем сумму весов оставшихся костей для нормализации
total_weight = sum(gw['weight'] for gw in kept_weights)
if total_weight > 0:
for gw in kept_weights:
gw['weight'] /= total_weight
else:
# На случай, если у всех веса были по 0.0 (редкий баг меша)
kept_weights[0]['weight'] = 1.0
final_weights = kept_weights
else:
final_weights = all_weights
file.write(f"Vertex {vertex.index}:\n")
file.write(f"Vertex groups: {len(final_weights)}\n")
for gw in final_weights:
group_name = mesh_copy.vertex_groups[gw['index']].name
file.write(f" Group: '{group_name}', Weight: {gw['weight']:.6f}\n")
# Удаляем временную копию mesh
bpy.data.objects.remove(mesh_copy)
else:
file.write(f"Объект с именем '{mesh_name}' не найден или не является mesh.\n")
# Обработка арматуры и анимации
if armature_obj and armature_obj.type == 'ARMATURE':
# Получаем все ключевые кадры для арматуры
file.write("=== Animation Keyframes ===\n")
if armature_obj.animation_data and armature_obj.animation_data.action:
action = armature_obj.animation_data.action
# Собираем все уникальные ключевые кадры
keyframes = set()
# Логика для Blender 5.0 (Strip-based / ChannelBag structure)
if hasattr(action, "layers"):
for layer in action.layers:
if hasattr(layer, "strips"):
for strip in layer.strips:
# Проверяем наличие channelbags (согласно вашему dir(strip))
if hasattr(strip, "channelbags"):
for bag in strip.channelbags:
for fcurve in bag.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
# На случай, если в этой версии используется единственное число
elif hasattr(strip, "channelbag") and strip.channelbag:
for fcurve in strip.channelbag.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
# Фоллбек для Legacy экшенов
if not keyframes and hasattr(action, "fcurves"):
for fcurve in action.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
keyframes = sorted(keyframes)
# Сортируем ключевые кадры
keyframes = sorted(keyframes)
# Сохраняем координаты и матрицы поворота для каждой кости на каждом ключевом кадре
file.write("=== Bone Transforms per Keyframe ===\n")
file.write(f"Keyframes: {len(keyframes)}\n")
for frame in keyframes:
# Устанавливаем текущий кадр
bpy.context.scene.frame_set(frame)
bpy.context.view_layer.update() # Обновляем сцену
file.write(f"Frame: {frame}\n")
for bone in armature_obj.pose.bones:
# Получаем координаты и матрицу поворота кости в мировом пространстве
matrix = bone.matrix
location = matrix.translation
rotation = matrix.to_euler()
# Записываем данные
file.write(f" Bone: {bone.name}\n")
file.write(f" Location: {location}\n")
file.write(f" Rotation: {rotation}\n")
file.write(f" Matrix:\n")
for row in matrix:
file.write(f" {row}\n")
else:
file.write(f"Объект с именем '{armature_name}' не найден или не является арматурой.\n")
print("Данные сохранены в файл 'mesh_armature_and_animation_data.txt'")