Jump to content

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


Recommended Posts

Posted

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()

  • Replies 8
  • Created
  • Last Reply

Top Posters In This Topic

Posted

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)

Posted

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.

Posted (edited)

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()

Edited by Ania
Posted

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.

Posted (edited)

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ć.

Edited by Ania
Posted

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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...

Important Information

We are using cookies. Read about our Privacy Policy