Skocz do zawartości

Blender Python: Skrypt przypisany do określonej kości lub armatury?


Rekomendowane odpowiedzi

Napisano

Skleciłam sobie skrypt króry ustawia kości FK tak samo jak IK. Na tyle działa.

Problem mam z umieszczeniem skryptu w interfacie, jestem początkująca.

Doszłam do punktu że skrypt (tzn. button) po instalacji pojawia się w każdej kości obojętnie jakiej armatury w pose mode.

Chciałabym jednak, żeby button był dostępny tylko z określonych kości określonych armatur, żebym mogła go "uaktywnić" jakoś ręcznie tylko dla armatur które w ogóle mają nogi IK/FK. Żeby to jakoś było zapisane w danej armaturze. Da się?

Tu skrypt (odpuściłam część która kręci kośćmi, bo nie w tym problem).

 

bl_info = {
   "name": "Align FK to IK",
   "category": "Animation",
}

import bpy


class AlignFK_panel(bpy.types.Panel):
   """Creates a Panel in the Object properties window"""
   bl_label = "Align FK"
   bl_idname = "BONE_PT_alignFK"
   bl_space_type = 'PROPERTIES'
   bl_region_type = 'WINDOW'
   bl_context = "bone"

   def draw(self, context):
       layout = self.layout
       row = layout.row()
       row.operator("pose.align_fk", text = "Align FK")



class AlignFK(bpy.types.Operator): 
   bl_idname = "pose.align_fk"
   bl_label = "Align FK"
   bl_options = {"UNDO"}

   def execute(self, context): 

       #placeholder 
       print("hello world you are aligned now")
       return {'FINISHED'}

def register():
   bpy.utils.register_class(AlignFK)
   bpy.utils.register_class(AlignFK_panel)


def unregister():
   bpy.utils.unregister_class(AlignFK)
   bpy.utils.unregister_class(AlignFK_panel)

if __name__ == "__main__":
   register()

  • Odpowiedzi 8
  • Created
  • Ostatniej odpowiedzi

Top Posters In This Topic

Napisano

W pisaniu skryptów zupełnie się nie znam. Jak znajdę jakiś przydatny to sobie zapisuje i jak jest mi potrzebny to próbując logicznie myśląc, staram się tak pozmieniać linijki tekstu, tak aby zadziałał na moim rigu. Dlatego też gotowego rozwiązania niestety nie jestem w stanie Ci podać, ale wiem, że ten skrypt ma funkcje o którą prosisz. Używam go do większości moich rigów i jest łatwy do "rozgryzienia". Zdaje się, że w Twoim przypadku, pierwsze będziesz musiała zdefiniować imiona kości, tak aby skrypt wiedział która kość to która "#Define the names we'll use for bones" a potem tylko "#Define what controls to show depending on the bones selected". Ale tak jak pisałem, nie mam pojęcia czy to u Ciebie zadziała, musisz popróbować. :)

###RIG CONTROLS

class RigUI(bpy.types.Panel):
   bl_label = "Rig Controls"
   bl_space_type = "VIEW_3D"
   bl_region_type = "UI"
   bl_context = "posemode"

   def draw(self, context):
       layout = self.layout
       row = layout.row()
       pose_bones = context.active_object.pose.bones
       try:
           selected_bones = [bone.name for bone in context.selected_pose_bones]
           selected_bones += [context.active_pose_bone.name]
       except (AttributeError, TypeError):
           return

       def is_selected(names):
       #Returns whether any of the named bones are selected
           if type(names) == list:
               for name in names:
                   if name in selected_bones:
                       return True
           elif names in selected_bones:
               return True
           return False

       #Define the names we'll use for bones

       head = "head"
       neck = "neck"

       ribs = "ribs"
       hips = "hips"

       shoulderl = "shoulder.L"
       uparmfkl = "upper_arm_FK.L"
       forearmfkl = "forearm_FK.L"
       handfkl = "hand_FK.L"

       shoulderr = "shoulder.R"
       uparmfkr = "upper_arm_FK.R"
       forearmfkr = "forearm_FK.R"
       handfkr = "hand_FK.R"

       thighfkl = "thigh_FK.L"
       shinfkl = "shin_FK.L"
       footfkl = "foot_FK.L"
       toefkl = "toe_FK.L"

       thighfkr = "thigh_FK.R"
       shinfkr = "shin_FK.R"
       footfkr = "foot_FK.R"
       toefkr = "toe_FK.R"

       handikl = "hand_IK.L"
       elbowpolel = "elbow_pole.L"

       handikr = "hand_IK.R"
       elbowpoler = "elbow_pole.R"

       footikl = "foot_IK.L"
       kneepolel = "knee_pole.L"

       footikr = "foot_IK.R"
       kneepoler = "knee_pole.R"


       #Define what controls to show depending on the bones selected

       if is_selected([head, neck]):
           layout.prop(pose_bones["head"], '["isolate head"]', slider=True) 

       if is_selected([ribs, hips]):
           layout.prop(pose_bones["ribs"], '["isolate torso"]', slider=True)

       if is_selected([hips]):
           layout.prop(pose_bones["hips"], '["pivot slide"]', slider=True)

       if is_selected([shoulderl, uparmfkl, forearmfkl, handfkl]):
           layout.prop(pose_bones["upper_arm_FK.L"], '["isolate left arm"]', slider=True)

       if is_selected([shoulderr, uparmfkr, forearmfkr, handfkr]):
           layout.prop(pose_bones["upper_arm_FK.R"], '["isolate right arm"]', slider=True)

       if is_selected([thighfkl, shinfkl, footfkl, toefkl]):
           layout.prop(pose_bones["thigh_FK.L"], '["isolate left leg"]', slider=True)

       if is_selected([thighfkr, shinfkr, footfkr, toefkr]):
           layout.prop(pose_bones["thigh_FK.R"], '["isolate right leg"]', slider=True)

       if is_selected([handikl, elbowpolel, shoulderl, uparmfkl, forearmfkl, handfkl]):
           layout.prop(pose_bones["hand_IK.L"], '["fk/ik left arm"]', slider=True)

       if is_selected([handikr, elbowpoler, shoulderr, uparmfkr, forearmfkr, handfkr]):
           layout.prop(pose_bones["hand_IK.R"], '["fk/ik right arm"]', slider=True)

       if is_selected([footikl, kneepolel, thighfkl, shinfkl, footfkl, toefkl]):
           layout.prop(pose_bones["foot_IK.L"], '["fk/ik left leg"]', slider=True)

       if is_selected([footikr, kneepoler, thighfkr, shinfkr, footfkr, toefkr]):
           layout.prop(pose_bones["foot_IK.R"], '["fk/ik right leg"]', slider=True)



###RIG LAYERS    

class RigLayers(bpy.types.Panel):
   bl_label = "Rig Controls"
   bl_space_type = "VIEW_3D"
   bl_region_type = "UI"
   bl_label = "Rig Layers"

   def draw(self, context):
       layout = self.layout
       col = layout.column()

       #Layers

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=0, toggle=True, text='head')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=7, toggle=True, text='torso')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=1, toggle=True, text='FK left arm')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=2, toggle=True, text='IK left arm')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=3, toggle=True, text='FK right arm')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=4, toggle=True, text='IK right arm')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=8, toggle=True, text='FK left leg')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=9, toggle=True, text='IK left leg')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=10, toggle=True, text='FK right leg')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=11, toggle=True, text='IK right leg')

       row = col.row()
       row.prop(context.active_object.data, 'layers', index=15, toggle=True, text='ROOT')



bpy.utils.register_class(RigUI)
bpy.utils.register_class(RigLayers)

Napisano

Da sie, prostsze niż myślisz. W operatorze aktywujacym dodajesz Custom Property dla armatury, bool albo int.

 

https://www.blender.org/api/blender_python_api_current/info_quickstart.html#custom-properties

 

http://blender.stackexchange.com/questions/43785/adding-other-types-of-custom-properties

 

Potem w kodzie interfaceu robisz łańcuch if'ów który sprawdza typ aktywnego obiektu i to czy ma twojego custom propa. If "my_prop1" in armature. Wtedy dopiero rysujesz button. IK możesz wykrywać iterując po bpy.context.active_object.pose.bones i korzystając z komendy in_ik_chain.

Napisano (edytowane)

Nowy problem z tym samym skryptem:

mam pliki: rycerz.blend oraz scena.blend do której ten rycerz jest podłączony z armaturą jako proxy. W pliku rycerz.blend odpalam skrypt, wszystko działa, otwieram scena.blend, wszystko działa. Niestety jeśli zamknę blendera, i potem otworzę nie rycerza ale od razu scena.blend, już nie działa, i muszę ponownie wchodzić do rycerz.blend, odpalić skrypt, żeby działało w scenie. Co dziwniejsze, button się pokazuje, tylko nie rusza kośćmi, tak jakby czytało tylko część skryptu.

 

Haczyk Register pod okienkiem tekstowym jest aktywny, bo myślałam że to coś z tym, ale nie pomogło.

 

Załączam skrypt. "fkp" to property kości o której pisał Monio.

 

bl_info = {
   "name": "Align FK to IK",
   "category": "Animation",
}

import bpy


class AlignFK_panel(bpy.types.Panel):
   """Creates a Panel in the Bone properties window"""
   bl_label = "Pose Tools"
   bl_idname = "BONE_PT_alignFK" 
   bl_space_type = 'PROPERTIES' 
   bl_region_type = 'WINDOW' 
   bl_context = "bone"



   def draw(self, context):
       try: 
           if bpy.context.active_pose_bone["fkp"] == 1: 
               layout = self.layout
               row = layout.row()
               row.operator("pose.align_fk", text = "Align FK")
       except:  
           print("no fkp set")


class AlignFK(bpy.types.Operator): 
   bl_idname = "pose.align_fk"
   bl_label = "Align FK"
   bl_options = {"UNDO"}

   def execute(self, context): 
       arm = bpy.context.active_object
       FK = bpy.context.active_pose_bone  #["FK_tibia.L"]

       def copy_matrix(source, target):
          target.matrix = source.matrix
          return



       def align_bones(active, bonelist):
           if active in bonelist:
               for bon in bonelist: 
                   IK = arm.pose.bones["ik"+bon[2:]]
                   FK = arm.pose.bones[bon]
                   copy_matrix(IK,FK)
                   bpy.data.scenes[0].update()
               bpy.ops.pose.select_all(action='DESELECT')
               for bon in bonelist: 
                   bpy.context.active_object.pose.bones[bon].bone.select=True
               bpy.data.scenes[0].update()
               bpy.ops.anim.keyframe_insert(type='Rotation')

       legbones = ["Fk_fem.L", "Fk_tib.L"] 
       align_bones(FK.name, legbones) 

       legbones = ["Fk_fem.R", "Fk_tib.R"]
       align_bones(FK.name, legbones) 

       return {'FINISHED'}

def register():
   bpy.utils.register_class(AlignFK)
   bpy.utils.register_class(AlignFK_panel)


def unregister():
   bpy.utils.unregister_class(AlignFK)
   bpy.utils.unregister_class(AlignFK_panel)

if __name__ == "__main__":
   register()

Edytowane przez Ania
Napisano

bl_info = {
   "name": "Align FK to IK",
   "category": "Animation",
}

import bpy

### Globalnie dodajesz typ Custom Property do typu kosci
from bpy.props import IntProperty
bpy.types.PoseBone.fkp = IntProperty(name = "FKP", default = 0)

class AlignFK_panel(bpy.types.Panel):
   """Creates a Panel in the Bone properties window"""
   bl_label = "Pose Tools"
   bl_idname = "BONE_PT_alignFK" 
   bl_space_type = 'PROPERTIES' 
   bl_region_type = 'WINDOW' 
   bl_context = "bone"

   def draw(self, context):
       layout = self.layout
       col = layout.column()

       ###
       if bpy.context.active_object.mode == 'POSE':
           ###
           pbone = bpy.context.active_pose_bone
           if 'fkp' in pbone:
               col.prop(pbone, 'fkp')
               ### Czy to nie powinno być zamienione na wieksze niz zero ?
               if pbone.fkp == 1:
                   col.operator("pose.align_fk", text = "Align FK")
           ###
           else:
               col.label("No FKP set", icon='ERROR')
               col.operator("pose.align_fk_initialize", text = "Initialize FKP")
       ###
       else:
           col.label("Enable Pose Mode", icon='ERROR')

class AlignFKInitialize(bpy.types.Operator): 
   bl_idname = "pose.align_fk_initialize"
   bl_label = "Align FK Initialize"
   bl_options = {"UNDO"}

   def execute(self, context):
       bpy.context.active_pose_bone.fkp = 1
       return {'FINISHED'}


class AlignFK(bpy.types.Operator): 
   bl_idname = "pose.align_fk"
   bl_label = "Align FK"
   bl_options = {"UNDO"}

   def execute(self, context): 
       arm = bpy.context.active_object
       FK = bpy.context.active_pose_bone  #["FK_tibia.L"]

       def copy_matrix(source, target):
          target.matrix = source.matrix
          return

       def align_bones(active, bonelist):
           if active in bonelist:
               for bon in bonelist: 
                   IK = arm.pose.bones["ik"+bon[2:]]
                   FK = arm.pose.bones[bon]
                   copy_matrix(IK,FK)
                   bpy.data.scenes[0].update()
               bpy.ops.pose.select_all(action='DESELECT')
               for bon in bonelist: 
                   bpy.context.active_object.pose.bones[bon].bone.select=True
               bpy.data.scenes[0].update()
               bpy.ops.anim.keyframe_insert(type='Rotation')

       legbones = ["Fk_fem.L", "Fk_tib.L"] 
       align_bones(FK.name, legbones) 

       legbones = ["Fk_fem.R", "Fk_tib.R"]
       align_bones(FK.name, legbones) 

       return {'FINISHED'}

def register():
   bpy.utils.register_class(AlignFKInitialize)
   bpy.utils.register_class(AlignFK)
   bpy.utils.register_class(AlignFK_panel)


def unregister():
   bpy.utils.unregister_class(AlignFKInitialize)
   bpy.utils.unregister_class(AlignFK)
   bpy.utils.unregister_class(AlignFK_panel)

if __name__ == "__main__":
   register()

 

Nie wiem czy to rozwiąże twój problem. Wydaje mi się że to nie działało bo nie zdefiniowałaś typu Custom Property z poziomu Addona. Dodałem jakieś tam UI.

Napisano (edytowane)

Monio dzięki ale nie pomogło. Skrypt jest przez twoją zmianę wygodniejszy, bo nie muszę ręcznie dodawać property, ale w pliku w którym model jest jako proxy, interface nie pokazuje przycisków z twojego skryptu.

 

Czy skrypty są ładowane jakoś lokalnie, tylko w pliku w którym jest ich tekst? Ale ten mój zaktywowałam nawet przez Properties/Addons, więc myślę że powinien być zdefiniowany globalnie, a on dalej nie działa.

Jeśli zładuję tekst skryptu do pliku ze sceną, i dam run script, to potem działa, ale chyba też nie o to chodzi żeby to za każdym razem odpalać.

Edytowane przez Ania
Napisano

Ok już wszystko działa. Blender czytał jakąś starą wersję skryptu którą sobie bez mojej wiedzy gdzieś zapisał (AppData/Roaming/..), a w tej wersji były tylko końskie nogi, nie rycerskie.

Wykasowałam z tamtąd, zainstalowałam na nowo przez Properties/Addons, teraz wszystko gra.

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się



×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Wykorzystujemy cookies. Przeczytaj więcej Polityka prywatności