Blender Scripting: head 㨠tail ã®åº§æ¨ã¨é©å½ãªãã£ã«ã¿ã¼æ¡ä»¶ã§ãã¼ã³ã®è¦ªåé¢ä¿ãèªåæ§ç¯ãã `connect-bones` ã®ä½ãæ¹ã¨ Add-on åã®æ¹æ³
ããã«ã¡ã¯ãPythonåå¿è â§Blenderåå¿è ã§ãããã£ã¼ãªã³ã°ããã¦ã¹ã½ã¡ã½ã¡ãããããã¨ã³ã¼ãã§å¦çããæ¹ãå¾æãªã®ã§ã un-h002; Atropos ã® cluster 対å¿ã§ç§èªèº«ã«è¿½å å®è£ ããã Blener Scripting ãå ¥éè¬åº§ãå ¼ãã¦æ´çãã¾ãðª
Note: èªè ã®æ³å®=Pythonã¾ãã¯Blenderã¯åå¿è Lv1ãããã ãã©ãä»ã«ä½ãããã®ããã°ã©ãã³ã°è¨èªã®Lv25ãããã®ä½¿ãæã®æ¹(ä½ãLvå¤ã¯ãããã1..99ãåºæ¬æ³å®ã¨ããå¤å ¸çJRPGãããã®æè¦å¤)ã§ãå¿ è¦ãªäºåç¥èã¯API Referenceãããã°èªã¿ã«è¡ããæ¹ã
æºåãããã®: bone ã親åé¢ä¿ãªãã§ããããå ¥ã£ã¦ãã¦ãä¸é¨ã® bone 㯠head 㨠tail ãåã座æ¨ã«ãã£ã¦è¦ªåé¢ä¿ã§ connected ã«ã§ãã Blender ã®ä½æ¥ç¶æ ãã¾ãã¯ãã®ã¡ã¢ã®å¦ç¿ç¨ã« Connected ãªè¦ªåé¢ä¿ã®ãã¼ã³ãå«ãã ãã¼ã¿ã Blender ã§ãã¹ã¦ã® armature ãé¸æãã¦è¦ªåé¢ä¿ã clear ããä½æ¥ç¶æ ãä¾ãã° ã»ã·ã«å¤èº«ã¢ã㪠ã§ä½ã£ã VRM ãååã®ã¡ã¢ã®ããã« Blender 㸠Import ããã¨ããããç¶æ ã«ãªãããããã¾ããã
ããã
- ã¯ãã¾ãã® Blender Scripting
- ãã¹ã¦ã® bone ãåæ
- åæããã bone 群ããã£ã«ã¿ã¼
- head 㨠tail ãåã座æ¨ã® bone çµã®æ½åº
- 2ã¤ã® bone çµã®ãé¸æã
- Blender çµã¿è¾¼ã¿æ©è½ã®
Armature: Make Parent
ãå¼ã¶ - ããããã®
connect-bones
Blender Scripting â Add-on å
1. ã¯ãã¾ãã® Blender Scripting
- Blenderä¸é¨ã®ã¿ãã
Scripting
ã¸åãæ¿ãã New Text
ãã¦ã- é©å½ãªååãä»ãã¦
- åä½ç¢ºèªç¨åº¦ã®ã³ã¼ããæ¸ãã¦
- Armature ã Edit Mode ã§é¸æã㦠(â å¾ã§ãããã³ã¼ãã«ã§ãã¾ãâ¨)
Run Script
import bpy # Blender API print( bpy ) # You can output to STDOUT anything! print( "Let's start", 123.45, 'Blender Scripting!' ) # You can concatenate a string and any object with a comma. # In this world, you can use the `#` for a line commenting. `//` is not work.
Note: Blender-2.82@Windows ç¾å¨ã® Scripting ã®ããã¹ãã¨ãã£ã¿ã¼ãSTDOUTã®åºåå ã® System Console Window 㯠UNICODE 表示ã«ããã©ã«ãã§ã¯å¯¾å¿ãã¦ããªãã®ã§éASCIIãã³ã¼ãã«ä½¿ããªãããã«ãã¾ããã
print
ã«ãã STDOUT ã®çµæ㯠F3 ->
Wm: Toggle System Console` ãªã©ããã¨è¡¨ç¤ºãããã·ã¹ãã ã³ã³ã½ã¼ã«çªã§ç¢ºèªã§ãã¾ãã
<module 'bpy' from 'C:\\Program Files\\Blender Foundation\\Blender 2.82\\2.82\\scripts\\modules\\bpy\\__init__.py'> Let's start 123.45 Blender Scripting!
ãããªè¡¨ç¤ºã Run Script
ã§åºãã° Blender Scripting ã® Lv1 ã¯ã¯ãªã¢ã¼ã§ããããã§ã¨ããããã¾ãð
Lv1 ãã¯ãªã¢ã¼ããå ±é ¬ã¨ã㦠Blender ã® API Documentation ãé²åãã¾ã:
ä»å¾ã® Blender Scripting ã©ã¤ãã«ãå½¹ç«ã¦ä¸ããðª
2. ãã¹ã¦ã® bone ãåæ
bpy
(ãã¶ã Blender-PYthon ã¨ãããããå½åç±æ¥ã§ãããâ¦) ãªãã¸ã§ã¯ãã®ã¡ã³ãã¼ãèªãã ãå¼ãã ãããã¨ãããã¦ãã® Blender ã®ç®¡çãªãã¸ã§ã¯ããçµã¿è¾¼ã¿æ©è½ã®å¼ã³åºããè¡ãã¾ãã
ä¾ãã°:
import bpy from itertools import chain armatures = bpy.data.armatures bones = list( chain( *[ a.edit_bones for a in armatures ] ) ) for b in bones: print( b, ' { head=', b.head, ' tail=', b.tail, '}' )
ããâã㦠Run Script
ããã¨â
<bpy_struct, Bone("NekoMimiBone_L")> { head= <Vector (0.0699, 0.2111, 0.0399)> tail= <Vector (0.0825, 0.2277, 0.0401)> } <bpy_struct, Bone("NekoMimiBone_L_001")> { head= <Vector (0.0825, 0.2277, 0.0401)> tail= <Vector (0.1012, 0.2548, 0.0416)> } <bpy_struct, Bone("NekoMimiBone_L_002")> { head= <Vector (0.1012, 0.2548, 0.0416)> tail= <Vector (0.1210, 0.2814, 0.0430)> } <bpy_struct, Bone("NekoMimiBone_L_003")> { head= <Vector (0.1210, 0.2814, 0.0430)> tail= <Vector (0.1408, 0.3081, 0.0444)> } <bpy_struct, Bone("Hair")> { head= <Vector (-0.0000, 0.1213, 0.0039)> tail= <Vector (-0.0000, 0.0988, 0.0286)> } <bpy_struct, Bone("Hoho_R")> { head= <Vector (-0.0817, 0.0463, 0.0867)> tail= <Vector (-0.1030, 0.0584, 0.1093)> } <bpy_struct, Bone("Hoho_L")> { head= <Vector (0.0817, 0.0463, 0.0867)> tail= <Vector (0.1030, 0.0584, 0.1093)> } <bpy_struct, Bone("Ago")> { head= <Vector (-0.0000, 0.0127, 0.0660)> tail= <Vector (-0.0000, 0.0190, 0.0987)> } <bpy_struct, Bone("Chest")> { head= <Vector (-0.0000, -0.1039, 0.0311)> tail= <Vector (0.0000, 0.0702, -0.0152)> } <bpy_struct, Bone("Mune_R")> { head= <Vector (-0.0940, -0.1429, 0.1315)> tail= <Vector (-0.0521, -0.1654, 0.0071)> } <bpy_struct, Bone("Mune_R_001")> { head= <Vector (0.0000, 0.0000, 0.0000)> tail= <Vector (-0.0000, 0.0333, -0.0000)> } <bpy_struct, Bone("Mune_L")> { head= <Vector (0.0940, -0.1429, 0.1315)> tail= <Vector (0.0521, -0.1654, 0.0071)> } <bpy_struct, Bone("Mune_L_001")> { head= <Vector (0.0000, 0.0000, 0.0000)> tail= <Vector (0.0000, 0.0333, -0.0000)> } <bpy_struct, Bone("Koshi")> { head= <Vector (-0.0000, 0.0000, 0.0000)> tail= <Vector (-0.0000, 0.0100, 0.0000)> }
âãããªå ·åã®åºåãå¾ããã¾ãã
ä¾ãèªãã æç¹ã§æ¢ã«æ¬é ã®ç®çãéæãã¦ãã¾ãã¾ãããï¼ð
ç´ æ´ãããå¦ç¿è½åãçºæ®ä¸ã§ç¥èãå¸ãè¾¼ã¿ããçãã®ããªããLv2ãã¯ãªã¢ã¼ããè¨å¿µã«:
ãã®â Bone
åã®ãªãã¡ã¬ã³ã¹ããã¥ã¢ã«ãé²åãã¾ãã head
ã tail
ãä½ããæ¸ãã¦ãããâ¨
3. åæããã bone 群ããã£ã«ã¿ã¼
ã¨ããã§ãå
ç¨ã®ã³ã¼ãã« [ ]
ã§å²ã¾ãããªã¹ããã³ã¼ãã§çæãã¦ããé¨åãããã¾ãããããã Python è¨èªã®ç¹å¾´çãªè¨èªæ©è½ã®1ã¤ã¨ãã¦æå㪠"ãªã¹ãå
å
表è¨" ã§ããâ¨
ãªã¹ãå å 表è¨ã§ã¯ãªã¹ãã¸å ¥ãããä½ããã
- ä»ã®ãªã¹ãã
for
ã§åæãã¤ã¤ if
ã§æ¡ä»¶ãä»ãããã- åãåºããçµæãã®ãã®ã§ã¯ãªãå å·¥ãå ãããªãã¸ã§ã¯ãã«ãã¦
æ°ããªãªã¹ããä½æããããããªãããªäºãã§ããäºãæ¢ã«ç¥ãã¾ãããããã§ãä¾ãã°:
import bpy from itertools import chain armatures = bpy.data.armatures bones = list( chain( *[ a.edit_bones for a in armatures ] ) ) filtered_bones = [ b for b in bones if b.name.startswith( 'NekoMimiBone' ) ] for b in filtered_bones: print( b, ' { head=', b.head, ' tail=', b.tail, '}' )
ãããªâå
·åã§åé
ã®ä¾ã«1è¡ filtered_bones
ã "NekoMimiBone" ã§ååãå§ã¾ã bone ã ããæ½åºãã¦ä½ãããã«è¿½å ãã¦ãbones
ã«æ¿ã㦠filtered_bones
ã print
ãã¦ã¿ãã¨:
<bpy_struct, Bone("NekoMimiBone")> { head= <Vector (-0.0000, 0.1213, 0.0039)> tail= <Vector (-0.0000, 0.2111, 0.0399)> } <bpy_struct, Bone("NekoMimiBone_R")> { head= <Vector (-0.0699, 0.2111, 0.0399)> tail= <Vector (-0.0825, 0.2277, 0.0401)> } <bpy_struct, Bone("NekoMimiBone_R_001")> { head= <Vector (-0.0825, 0.2277, 0.0401)> tail= <Vector (-0.1012, 0.2548, 0.0416)> } <bpy_struct, Bone("NekoMimiBone_R_002")> { head= <Vector (-0.1012, 0.2548, 0.0416)> tail= <Vector (-0.1210, 0.2814, 0.0430)> } <bpy_struct, Bone("NekoMimiBone_R_003")> { head= <Vector (-0.1210, 0.2814, 0.0430)> tail= <Vector (-0.1408, 0.3081, 0.0444)> } <bpy_struct, Bone("NekoMimiBone_L")> { head= <Vector (0.0699, 0.2111, 0.0399)> tail= <Vector (0.0825, 0.2277, 0.0401)> } <bpy_struct, Bone("NekoMimiBone_L_001")> { head= <Vector (0.0825, 0.2277, 0.0401)> tail= <Vector (0.1012, 0.2548, 0.0416)> } <bpy_struct, Bone("NekoMimiBone_L_002")> { head= <Vector (0.1012, 0.2548, 0.0416)> tail= <Vector (0.1210, 0.2814, 0.0430)> } <bpy_struct, Bone("NekoMimiBone_L_003")> { head= <Vector (0.1210, 0.2814, 0.0430)> tail= <Vector (0.1408, 0.3081, 0.0444)> }
ããã§ã¨ããããã¾ãð ä»åãä¾ãèªãã ã ãã§ç®çãéæãã¦ãã¾ãã¾ããããLv3ã®ã¯ãªã¢ã¼ã®è¨å¿µã«:
"Python-3.7" ã®å ¬å¼ãã¥ã¼ããªã¢ã«ã® "§5.1.3. ãªã¹ãå å 表è¨" ãé²åãã¾ãðª å·çç¾å¨ã® Python ãã®ãã®ã¯ 3.8 ãææ°çã§ããã Blender-2.82 ã«çµã¿è¾¼ã¾ãã Python 㯠3.7.4 ã§ãããªãã¡ã¬ã³ã¹ãåç §ããæã¯èªåãæ±ãè¨èªå¦çç³»ã®ãã¼ã¸ã§ã³ã«ã注æãã¾ãããã
Note: ã¡ãªã¿ã«ããããã¨ãªã¹ãå å 表è¨ã¯ä½ãªã®ãç¨åº¦ã®"å ¥éæ å ±"ã¯ããããã®éè¯è§£èª¬ãåºã¦ããã¨æãã¾ããPythonã®è¨èªã®å ¥éæ¸ç±ã§ãç´¹ä»ããã¦ããã§ãããã"Must"ã"Should"ã¨è¨ãã»ã©ãç¯ä»ã§ã¯ããã¾ããããããã¦ãã®ããã°ã©ãã³ã°è¨èªã®"åºç¤çãªä½ã"ã¯è¨èªå ¬å¼ã®è³æã第ä¸ã«åç §ããã¨æ¸ãééããæ» å¤ã«ããã¾ããããå¿ è¦ãªäºã¯å¿ ãæ¸ãã¦ããã¾ãããåççã§ããã§ããð
4. head 㨠tail ãåã座æ¨ã® bone çµã®æ½åº
å°ãè¤éããå¢å ããããªã®ã§ããªã¹ãå å 表è¨ãã¯ã³ã©ã¤ãã¼ãç¡çã«ä½ããã¨ãããããããé¢æ°ãå®ç¾©ãã¦æ°å¹´å¾ã®èªåã§ãè¦ãç¬éã«èªããããã«æ¸ãã¾ã:
import bpy from itertools import chain armatures = bpy.data.armatures bones = list( chain( *[ a.edit_bones for a in armatures ] ) ) filtered_bones = [ b for b in bones if b.name.startswith( 'NekoMimiBone' ) ] def find_connectable_pair( parent ): for candidate in filtered_bones: if parent.tail == candidate.head: return ( parent, candidate ) connectable_pairs = [ p for p in map( find_connectable_pair, filtered_bones ) if p != None ] for p in connectable_pairs: print( 'Parent:', p[0], ' <==/connectable/==< Child:', p[1] )
map
ã¯è¨èªçµã¿è¾¼ã¿ã®å
ã«ãªããªã¹ãã®è¦ç´ 群ãä»»æã®ãã¡ã³ã¯ã¿ã¼ã§å°å½±å¤æããè¦ç´ 群ããä½æãããªã¹ããå¾ã Python è¨èªã®ãªã¹ãå¦çç¨ã«çµã¿è¾¼ã¾ããé¢æ°ã§ããã¾ãã Python ã§ã¯ [ ]
ã¯ãªã¹ãã ( )
ã¯ã¿ãã«ã«ãªãã¾ããðª
Note: Python ã§ã¯ def
ã§é¢æ°ãå®ç¾©ã§ãã¾ãããã¾ã¾ã§è§¦ãã¦ãã¾ããã§ãããã Python ã®ãããããè¨èªæ©è½ã®ãã1ã¤ã®å¤§ããªç¹å¾´ã®ã¤ã³ãã³ã(indent)/ããã³ã(dedent)ã«ãããããã¯æ§é ã®çæãåé
ã¾ã§ã®æå¾ã® for
㨠print
ã®çµã¿åããã§ãæ¸ãã¦ããã¾ããã def
ã if
ãåæ§ã« :
ã®å¾ã®è¡ã§ indent = {
ãã dedent = }
ã¾ã§åãã¤ã³ãã³ãã¬ãã«ã®é£ç¶ããè¤æ°ã®è¡ã1ã¤ã®ãããã¯ã¨ãã¦å¦çããã¾ããã¾ãã Python ã§ã¯é¢æ°ã® return
ãæªå®ç¾©ã®å ´å㯠None
ãéãã¾ãã
âãããå®è¡ããã¨â
Parent: <bpy_struct, Bone("NekoMimiBone_R")> <==/connectable/==< Child: <bpy_struct, Bone("NekoMimiBone_R_001")> Parent: <bpy_struct, Bone("NekoMimiBone_R_001")> <==/connectable/==< Child: <bpy_struct, Bone("NekoMimiBone_R_002")> Parent: <bpy_struct, Bone("NekoMimiBone_R_002")> <==/connectable/==< Child: <bpy_struct, Bone("NekoMimiBone_R_003")> Parent: <bpy_struct, Bone("NekoMimiBone_L")> <==/connectable/==< Child: <bpy_struct, Bone("NekoMimiBone_L_001")> Parent: <bpy_struct, Bone("NekoMimiBone_L_001")> <==/connectable/==< Child: <bpy_struct, Bone("NekoMimiBone_L_002")> Parent: <bpy_struct, Bone("NekoMimiBone_L_002")> <==/connectable/==< Child: <bpy_struct, Bone("NekoMimiBone_L_003")>
ä»åãç°¡åã«ç®çãéæã§ãã¾ãã⨠ä½åãã¿ãªãã£ã¦ããããããªãã®ã§ããã¡ãâãLv4ã®ã¯ãªã¢ã¼ã®è¨å¿µã«é²åãã¾ãããæ´»ç¨ä¸ãã:
â㯠"Python-3.7" è¨èªãªãã¡ã¬ã³ã¹ã® "§2.1.8. ã¤ã³ãã³ã" ã§ãðª è¨èªãªãã¡ã¬ã³ã¹ã¯ãã¥ã¼ããªã¢ã«ãããã«ããã¨è¦æ ¼ã®è§£èª¬ãããææ¸ãªã®ã§ããã£ããæ´çããªããèªãå¿ è¦ã®ããé¨åãå°ãªãããã¾ããããè¨èªæ©è½ã®ä¸æ¢ãæãåºç¤çãªé¨åãä¾ãã°ã¤ã³ãã³ãã¨ããã³ãã«ããã³ã¼ããããã¯ã®çæã®æ£ç¢ºãªæ å ±ã空ç½æåãªãä½ã§ãè¯ãã®ããã¿ãã¨ã¹ãã¼ã¹ãæ··ãã£ã¦ããã¨ã©ããªãã®ãããããã£ãæ å ±ã«ã¤ãã¦è¨èªè¦æ ¼ã«åºã¥ããééãã®ï¼ããã¦ãã¯ï¼ç¡ãæ£ç¢ºãªæ å ±ã確èªã§ãã¾ããè¨èªæ©è½ã®åºç¤çãªè¦ç´ ã«ã¤ãã¦æ°ã«ãªãäºãããã°ãã¯ããã«è¨èªãªãã¡ã¬ã³ã¹ãåç §ããã¨ä¸å®ã®ç¡ã確å®ãªæ å ±ãï¼ãã¶ãï¼åå¾ã§ãã¦ä¾¿å©ã§ãâ¨
5. 2ã¤ã® bone çµã®ãé¸æã
ããã¾ã§ã¯ Blender API ãéã㦠Blender ã管çä¸ã®ãªãã¸ã§ã¯ãã«ã¤ã㦠read çãªã¢ã¯ã»ã¹ã§ããããããã write çãªäºããã¦ã¿ã¾ããããä¸çã¯"å¯ä½ç¨"ã§"é²ãã§"ãã¾ã:
import bpy from itertools import chain armatures = bpy.data.armatures bones = list( chain( *[ a.edit_bones for a in armatures ] ) ) filtered_bones = [ b for b in bones if b.name.startswith( 'NekoMimiBone' ) ] def find_connectable_pair( parent ): for candidate in filtered_bones: if parent.tail == candidate.head: return ( parent, candidate ) connectable_pairs = [ p for p in map( find_connectable_pair, filtered_bones ) if p != None ] for p in connectable_pairs: print( 'Parent:', p[0], ' <==/connectable/==< Child:', p[1] ) p[0].select = True p[1].select = True
âæå¾ã®2è¡ãå¢ããã ãã§ãããããã¾ã§ã«ãªã大ããªéããããã¾ãããã®ã³ã¼ãã§ã¯æå¾ã®2è¡ã§ã¹ã¯ãªããã®å¤ã® Blender ã®ä¸çã®å¤ãæ¸ãæãã¦ãã¾ããå®è¡å¾ã« Edit Mode ã§ä»åæä½å¯¾è±¡ã®ãã³ããã®ããããè¦ãã¨:
ãã³ããé¨åã® Connected ãªè¦ªåé¢ä¿ãè¦ãããã«æ§ç¯ã§ããããªãã¼ã³ç¾¤ãé¸æç¶æ ã«ãªãã¾ãããï¼ãã®ã¹ã¯ãªããã¯å®è¡ã«ããã¹ã¯ãªããã®å¤ã® Blender ã®ä¸çã«å¯ä½ç¨ãå¼ãèµ·ããäºã«æåãã¾ãããããã§ã¨ããããã¾ãð
ã¡ãªã¿ã«â㧠EditBone
ã® select
ããããã£ã¼ã®ä»æ§ã確èªã§ãã¾ã⨠Blender API ã«ã¯å¤ãã® "æä½" ã bpy.ops
ã«ã¡ã½ããã¨ãã¦æä¾ããã¦ãã¦ãä¾ãã° bpy.ops.armature.select_all
ã®ãããªä½¿ãæ次第ã§ã¯ä¾¿å©ãªæ©è½ãããã¾ããä¸æ¹ã§ãä»å使ã£ã EditBone
ã® select
ããããã£ã¼ã®ããã«ãç´æ¥å¤æ°ã®å¤ãæ¸ãæããã°ããå ´åãããã¾ãðª
6. Blender çµã¿è¾¼ã¿æ©è½ã® Armature: Make Parent
ãå¼ã¶
æ¢ã« bpy.ops.armature.parent_set
ãå¼ã¶ã ãã§ãããã¨åä»ãã¦ããããããã¾ããããã®éãã§ãðª ãã®éãã§ã¯ããã®ã§ããããã¡ã㨠API Reference ãè¦ã¦ãã使ããªãã¨ä½¿ãã¾ããã
ã¤ãã§ãããããä»ä¸ããè¿ã¥ãã¦ããã®ã§ãã¹ã¯ãªããã®å®è¡åã«æä½æ¥ã§ Edit Mode ã¸åãæ¿ãã¦ããå¿
è¦ãç¡ãããã« bpy.ops.object.mode_set
ãçµã¿è¾¼ãã§ãã¾ããã:
import bpy from itertools import chain bpy.ops.object.mode_set(mode='EDIT') armatures = bpy.data.armatures bones = list( chain( *[ a.edit_bones for a in armatures ] ) ) filtered_bones = [ b for b in bones if b.name.startswith( 'NekoMimiBone' ) ] def find_connectable_pair( parent ): for candidate in filtered_bones: if parent.tail == candidate.head: return ( parent, candidate ) connectable_pairs = [ p for p in map( find_connectable_pair, filtered_bones ) if p != None ] for p in connectable_pairs: print( 'connect-bones:', p[0].name, '<-', p[1].name ) p[1].select = True p[0].select = True armatures[0].edit_bones.active = p[0] bpy.ops.armature.parent_set() p[0].select = False p[1].select = False for p in connectable_pairs: p[1].select = True p[0].select = True
GUIã§æä½ããå ´åã«ã¯ãå
ã£ã½ãã¼ã³ãâãæ ¹æ¬ãã¼ã³ãã®é åºã§ãé¸æãã㦠Armature: Make Parent
ããã°æå¾
åä½ãããã®æ©è½ã§ããã bpy.ops.armature.parent_set
ãã¹ã¯ãªããã§ä½¿ãå ´åã¯ãé¸æãã ãã§ãªããã¢ã¯ãã£ãç¶æ
ããæèçã«æä½ãè¨è¿°ããå¿
è¦ãããã¾ããGUIæä½ã§ã¯æå¾ã«ã½ã¡ã£ã¨é¸æãããã¼ã³ããé¸æç¶æ
ããã¤ãã¢ã¯ãã£ãç¶æ
ãã«ãªãã¾ãããã¹ã¯ãªããã§ã¯ãé¸æãã¨ãã¢ã¯ãã£ãåãã®ã³ã¼ãã¯ããããå¥ã«è¨è¿°ããæ©è½ã¨ã㦠API ãæä¾ããã¦ãã¾ãðª
å ãã¦ãGUIæä½ã¨åæ§ã®ç¹ã¨ãã¦ãè¤æ°ã®è¦ªåé¢ä¿ã®æ§ç¯ãããå ´åã«ã¯ãå ã«è¦ªåé¢ä¿ãæ§ç¯ãããã¼ã³ã¯é¸æã解é¤ãã¦ããããã次ã®è¦ªåé¢ä¿ã®é¸æãè¡ãå¿ è¦ãããã¾ãã
ãªããä»å㯠bpy.ops.object.mode_set(mode='EDIT')
ãå ããã®ã§ãä¾ãã° Pose Mode
㧠Run Script
ãã¦ãèªåçã« Edit Mode
ã«ãªããã¹ã¯ãªãããæå¾
åä½ããããã«ãªã£ã¦ãã¾ãðª
ããã«ããã¾ãæ©è½ã¨ãã¦è¦ªåé¢ä¿ã®æ§ç¯ããã¹ã¦è¡ã£ãå¾ãããä¸åº¦ã親åé¢ä¿ã®ã¿ãã«ããã©ãã¼ã¹ãã¦è¦ªåé¢ä¿ãæ§ç¯ããï¼ã¯ãï¼ã®ãã¼ã³ãã¤ã¾ãå¤æ´ããã£ããã¼ã³ç¾¤ããé¸æãããç¶æ ã«ãã¦ãã¾ããã·ã¹ãã ã³ã³ã½ã¼ã«ã®ãã°ãèªã¾ãªãã¦ãGUIã§è¦è¦çã«ã©ãããã£ã¤ããã®ããããããããã工夫ã§ãã
å®è¡ãã㨠"NekoMimiBone" ã§å§ã¾ããã¼ã³ç¾¤ã«ã¤ãã¦ããã¾ã¯äºãã«ã°ãã°ãã§è¦ªåé¢ä¿ã¯ç¡ãããã© tail 㨠head ãåã座æ¨ã§éãªã£ã¦ãã bone ã®çµããã¹ã¦è¦ã¤ã㦠Connected ãªè¦ªåé¢ä¿ãæ§ç¯ãã¦ããã¾ã⨠Connected ãªã®ã§ãç¹ãã£ããã¼ã³ã®1ã¤ãé©å½ã«é¸æã㦠G
ã§åãããªã©ããã¨ç¹ãã£ããã¼ã³ãå½±é¿ãåãã¦å転ãããæ¡ç¸®ããã追å¾ããããã«ãªã£ã¦ãã¾ã:
7. ããããã® connect-bones
Blender Scripting -> Add-on åâ¨
âã¾ã§ã§ç®çãéæããã¹ã¯ãªãããææ¸ãã§å®è¡ã§ããããã«ãªãã¾ãã⨠ãã£ãããªã®ã§ Add-on ã«ãã¦ã¿ã¾ã:
ãã¥ã¼ããªã¢ã«ãåèã«ãã«ããã«ãæ¸ãã¦è©¦ãã¦ä¿®æ£ãã¦:
### The code for add-on ecosystem ### bl_info = { 'name' : 'connect-bones', 'blender' : ( 2, 80, 0 ), 'category': 'Armature', 'author' : 'USAGI.NETWORK / Usagi Ito', 'version' : ( 0, 0, 0 ), 'support' : 'TESTING', } addon_keymaps = [] import bpy from itertools import chain from re import compile class ConnectBones( bpy.types.Operator ): '''Connect bones if it find a bone pair that has a same position of a head and a tail''' bl_idname = 'armature.connect_bones' bl_label = 'Connect bones' bl_options = { 'REGISTER', 'UNDO' } name_regex: bpy.props.StringProperty( name = 'name_regex', default = '.*' ) def execute( self, context ): return connect_bones( self.name_regex ) def register(): bpy.utils.register_class( ConnectBones ) bpy.types.VIEW3D_MT_object.append( menu ) wm = bpy.context.window_manager kc = wm.keyconfigs.addon if kc: km = wm.keyconfigs.addon.keymaps.new( name = '3D View', space_type = 'VIEW_3D' ) kmi = km.keymap_items.new( idname = ConnectBones.bl_idname, type = 'C', value = 'PRESS', ctrl = True, shift = True, alt = True ) kmi.properties.name_regex = '(?!)' addon_keymaps.append( ( km, kmi ) ) def unregister(): bpy.utils.unregister_class( ConnectBones ) for km, kmi in addon_keymaps: km.keymap_items.remove(kmi) def menu( self, context ): self.layout.separator() self.layout.operator( ConnectBones.bl_idname ) addon_keymaps.clear() if __name__ == '__main__': register() ### The main code of the add-on ### def connect_bones( name_regex ): bpy.ops.object.mode_set(mode='EDIT') armatures = bpy.data.armatures bones = list( chain( *[ a.edit_bones for a in armatures ] ) ) regex = compile( name_regex ) filtered_bones = [ b for b in bones if regex.match( b.name ) ] def find_connectable_pair( parent ): for candidate in filtered_bones: if parent.tail == candidate.head: return ( parent, candidate ) connectable_pairs = [ p for p in map( find_connectable_pair, filtered_bones ) if p != None ] for p in connectable_pairs: print( 'connect-bones:', p[0].name, '<-', p[1].name ) p[1].select = True p[0].select = True armatures[0].edit_bones.active = p[0] bpy.ops.armature.parent_set() p[0].select = False p[1].select = False for p in connectable_pairs: p[0].select = True p[1].select = True return {'FINISHED'}
ãããªå ·åã§ã§ãã¾ããâ¨
- https://github.com/usagi/blender-connect-bones (âã®åçããé²åãã¦ããå¯è½æ§ãããã¾ã)
add-on åã«ãããã
- add-on ã¨ãã¦æ©è½ãæ±ç¨çã«ããããåé
ã¾ã§ã®è©¦ä½ã§ã¯
startwith
ã§ãã£ã«ã¿ã¼ãã¦ãã bone ã®ååãæ£è¦è¡¨ç¾ã§ãã£ã«ã¿ã¼ããæ¹å¼ã«å¤æ´ CTRL + SHIFT + ALT + C
ã·ã§ã¼ãã«ãããã¼ã§æ£è¦è¡¨ç¾ã®ãã¿ã¼ã³ãæå®ãããã¤ã¢ãã°ä»ãã§çºåå¯è½Python Console
ã使ãå ´åã¯bpy.ops.armature.connect_bones( name_regex= 'Neko' )
ã®ããã«çºåå¯è½
ã«ãã¾ããðª
ãã® add-on ã使ãã¨ãååãæ£è¦è¡¨ç¾ã§çã£ããã¼ã³ç¾¤ã« Connected ãªè¦ªåé¢ä¿ãæ§ç¯ã§ããã®ã§ãä¾ãã°ãã³ããã ãã髪ã®æ¯ã ããªã©ããç¨åº¦ç°¡åã«çã£ã¦ Connected ãªè¦ªåé¢ä¿ãã°ãã°ãã®ãã¼ã³ããæ§ç¯ã§ãã¾ããããã㦠Connected ãªè¦ªåé¢ä¿ãä½ã㨠Blender ã®å
èæ©è½ã§ Connected ãªè¦ªåãã¼ã³ç¾¤ã¯ä»»æã« Armature: Merge Bones
ã§ããããããã¨ãã¼ã¸å
ã®ãã¼ã³ããããã«å²ãå½ã¦ããã¦ããé ç¹ãã¬ã³ãã£ã³ã°ã®ã¦ã§ã¤ããåæãã¦å¼ãç¶ãã ãã¼ã³ã¨é ç¹ã¦ã§ã¤ãã®é¢ä¿ãèªåçã«ã§ããã®ã§ä¾¿å©ãã¨ãã add-on ã§ãã
âè¦ãããã¼ã³ã®ã»ã¨ãã©ã Connected ãªè¦ªåé¢ä¿ã«ã§ãããã¼ã¿ã§ãããæã§ä½æ¥ããã«ã¯å¤ããã¦å¤ããã¾ãâ¦ãã§ãããã® add-on ãããã°â
ãã§ãããã§ãããããã¾ãðª