В блендере я хочу заменить целую древовидную структуру костей пустой.Рассмотрим эту модель костного дерева:
Костное дерево
Вся структура должна быть преобразована в дерево пустот с сохранением имен и порядка родительских / дочерних элементов:
(я только что изобразил первый уровень здесь, так как я думаю, что вы поняли идею)
Примечание: анимации на этом рисунке не интересны!
Пустое дерево
В данный момент я читаю во всех костях, сохраняю их в некотором списке 2D-Python и пытаюсь воссоздать всю структуру с пустыми портами, рекурсивно обходя этот массив:
class ReplaceBones(bpy.types.Operator):
bl_label = "Replace Bones"
bl_idname = "replace.bones"
bl_description = "Replaces all bones with empties."
def execute(self, context):
#Set mode to 'OBJECT'
if not bpy.context.mode == 'OBJECT':
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
#Deselect everything
bpy.ops.object.select_all(action='DESELECT')
#Check if Root exists
if 'Root' in bpy.context.scene.objects:
#Switch to Root
root = bpy.data.objects['Root']
bpy.context.scene.objects.active = root
#Get all Bones
contObj = bpy.context.object
bones = contObj.data
#Set mode to EDIT to access edit_bones
bpy.ops.object.mode_set(mode='EDIT')
boneList = []
childList = []
#Loop through bones
for bone in bones.edit_bones:
#boneList.append(bone.name)
boneList.append(childList)
childList = [bone.name]
for child in bone.children:
childList.append(child.name)
#test
print()
print("WHOLE LIST")
for bone in boneList:
print(bone)
print(".......length: " + str(len(bone)))
print()
#Set mode back to OBJECT
bpy.ops.object.mode_set(mode='OBJECT')
#Add Empties
self.recursiveAddEmpties(context, boneList, 'Root', 1)
else:
#Info pop up in blender
self.report({'INFO'}, "No Root found! Forgot to import model?")
return{"FINISHED"}
Рекурсивное прохождение:
def recursiveAddEmpties(self, context, bones, activeObj, index):
head = bones[index][0]
children = bones[index]
print()
print("Recursion head: " + head)
print("Recursion children: " + str(children))
print("Recursion children len: " + str(len(children)))
print("index: " + str(index))
print()
#add head
if index == 1:
bpy.ops.object.empty_add(type='PLAIN_AXES')
bpy.context.object.name = head
emptyHead = bpy.context.object
if not len(children) == 1:
root = bpy.data.objects[activeObj]
bpy.context.scene.objects.active = root
print("Active object: " + str(bpy.context.scene.objects.active))
#add childs
for child in children:
if not child == head:
print("Active child: " + child)
bpy.ops.object.empty_add(type='PLAIN_AXES')
childObj = bpy.context.object
bpy.context.object.name = child
childObj.parent = emptyHead
index += 1
print("index: " + str(index))
if not index == len(bones) - 1:
self.recursiveAddEmpties(context, bones, head, index)
Сам массив выглядит так:
Структура массива
Таким образом, в основном это представляет древовидную структуру таким образом, что «голова», которая содержит дочерние элементы (поддеревья), всегда имеет индекс 0, если не осталось только одной единственной кости (как ['Root Ponytail1Nub']))
Рекурсивная функция работает как-то.Таким образом, это добавляет, по крайней мере, все головы.Но как только первый уровень рекурсии из одной головы был сделан, он не может правильно добавить childs.
Результат выглядит так:
Результат
Теперь я знаю, в чем проблема.Я постоянно увеличиваю индекс массива до тех пор, пока он не выйдет за пределы диапазона, и затем произойдет следующий уровень рекурсии:
index += 1
if not index == len(bones) - 1:
self.recursiveAddEmpties(context, bones, head, index)
Это будет работать до тех пор, пока не будет выбран следующий заголовок поддерева, как L_Clavicle иэто дети.
Похоже, что основная структура построена правильно, но поддеревья немного испорчены.Я попытался реализовать функцию для поиска следующего вхождения головы, в основном устанавливая индекс для следующего индекса дочернего массива в этом списке:
index = self.getHeadIndex(context, index, head, bones)
if not index == len(bones) - 1:
self.recursiveAddEmpties(context, bones, head, index)
def getHeadIndex(self, context, index, head, bones):
#try to find index of next occurance of head in bone list
print("Trying to find index. Actual index: " + str(index))
print("for head: " + str(head))
#start = index + 1
start = index + 1
if not start > len(bones) - 1:
print("start: " + str(start))
for i in range(start, len(bones)):
children = bones[i]
print("i: " + str(i))
for child in children:
print("child: " + child)
if head == child:
print("index found at " + str(i))
return i
else:
print("index not found. returning " + str(index))
return index
Но это приводит к индексу == Нет ошибокили бесконечная рекурсия.
Суть всего этого в том, что я думаю, что главная проблема в том, что моя функция рекурсии работает так, что индекс будет увеличиваться до тех пор, пока не будет пройдено одно поддерево, но когда будет выбран следующий дочерний элемент, и это будетГлава следующего поддерева "index + = 1" приведет к проблемам.
Может быть, кто-то может просветить меня здесь:).