1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # Project Name: MakeHuman
20 # Product Home Page: http://www.makehuman.org/
21 # Code Home Page: http://code.google.com/p/makehuman/
22 # Authors: Thomas Larsson
23 # Script copyright (C) MakeHuman Team 2001-2013
24 # Coding Standards: See http://www.makehuman.org/node/165
28 MHX (MakeHuman eXchange format) importer for Blender 2.5x.
31 This script should be distributed with Blender.
32 If not, place it in the .blender/scripts/addons dir
33 Activate the script in the "Addons" tab (user preferences).
34 Access from the File > Import menu.
36 Alternatively, run the script in the script editor (Alt-P), and access from the File > Import menu
40 'name': 'Import: MakeHuman (.mhx)',
41 'author': 'Thomas Larsson',
42 'version': (1, 15, 1),
43 "blender": (2, 65, 0),
44 'location': "File > Import > MakeHuman (.mhx)",
45 'description': 'Import files in the MakeHuman eXchange format (.mhx)',
47 'wiki_url': 'http://sites.google.com/site/makehumandocs/blender-export-and-mhx',
48 'tracker_url': 'https://projects.blender.org/tracker/index.php?'\
49 'func=detail&aid=21872',
50 'category': 'Import-Export'}
66 from mathutils
import Vector
, Matrix
67 from bpy
.props
import *
72 theDir
= "~/makehuman/exports"
82 warnedTextureDir
= False
99 T_EnforceVersion
= 0x01
107 T_ShapeDrivers
= 0x80
110 T_Shape
= T_Shapekeys
121 DefaultToggle
= ( T_EnforceVersion
+ T_Mesh
+ T_Armature
+
122 T_Shapekeys
+ T_ShapeDrivers
+ T_Proxy
+ T_Clothes
+ T_Rigify
)
124 toggle
= DefaultToggle
125 toggleSettings
= toggle
131 def initLoadedData():
148 'MaterialTextureSlot' : {},
158 'MeshTextureFaceLayer' : {},
159 'MeshColorLayer' : {},
162 'ParticleSystem' : {},
164 'ObjectConstraints' : {},
165 'ObjectModifiers' : {},
170 def reinitGlobalData():
173 'MeshTextureFaceLayer', 'MeshColorLayer', 'VertexGroup', 'ShapeKey',
174 'ParticleSystem', 'ObjectConstraints', 'ObjectModifiers', 'MaterialSlot']:
179 'Object' : 'objects',
181 'Lattice' : 'lattices',
186 'Armature' : 'armatures',
188 'BoneGroup' : 'bone_groups',
190 'PoseBone' : 'pose_bones',
191 'Material' : 'materials',
192 'Texture' : 'textures',
194 'Camera' : 'cameras',
200 # readMhxFile(filePath):
203 def readMhxFile(filePath
):
204 global todo
, nErrors
, theScale
, theArmature
, defaultScale
, One
205 global toggle
, warnedVersion
, theMessage
, alpha7
, theDir
207 defaultScale
= theScale
211 warnedVersion
= False
215 theDir
= os
.path
.dirname(filePath
)
216 fileName
= os
.path
.expanduser(filePath
)
217 _
,ext
= os
.path
.splitext(fileName
)
218 if ext
.lower() != ".mhx":
219 print("Error: Not a mhx file: %s" % fileName
.encode('utf-8', 'strict'))
221 print( "Opening MHX file %s " % fileName
.encode('utf-8', 'strict') )
222 print("Toggle %x" % toggle
)
225 # ignore = False # UNUSED
234 file= open(fileName
, "rU")
235 print( "Tokenizing" )
239 lineSplit
= line
.split()
241 if len(lineSplit
) == 0:
243 elif lineSplit
[0][0] == '#':
244 if lineSplit
[0] == '#if':
245 if comment
== nesting
:
247 res
= eval(lineSplit
[1])
253 elif lineSplit
[0] == '#else':
254 if comment
== nesting
-1:
256 elif comment
== nesting
:
258 elif lineSplit
[0] == '#endif':
259 if comment
== nesting
:
262 elif comment
< nesting
:
264 elif lineSplit
[0] == 'end':
272 print( "Tokenizer error at or before line %d.\nThe mhx file has been corrupted.\nTry to export it again from MakeHuman." % lineNo
)
275 elif lineSplit
[-1] == ';':
276 if lineSplit
[0] == '\\':
278 tokens
.append([key
,lineSplit
[2:-1],[]])
281 tokens
.append([key
,lineSplit
[1:-1],[]])
284 tokens
.append([key
,lineSplit
[1:],[]])
291 MyError("Tokenizer error (%d).\nThe mhx file has been corrupted.\nTry to export it again from MakeHuman." % level
)
296 for (expr
, glbals
, lcals
) in todo
:
298 print("Doing %s" % expr
)
299 exec(expr
, glbals
, lcals
)
301 msg
= "Failed: %s\n" % expr
306 scn
.objects
.active
= theArmature
307 theArmature
.MhAlpha8
= not alpha7
308 #bpy.ops.wm.properties_edit(data_path="object", property="MhxRig", value=theArmature["MhxRig"])
311 msg
= "File %s loaded in %g s" % (fileName
, time2
-time1
)
313 msg
+= " but there where %d errors. " % (nErrors
)
318 # getObject(name, var, glbals, lcals):
321 def getObject(name
, var
, glbals
, lcals
):
323 ob
= loadedData
['Object'][name
]
326 pushOnTodoList(None, "ob = loadedData['Object'][name]" % globals(), locals())
331 # checkMhxVersion(major, minor):
334 def checkMhxVersion(major
, minor
):
336 print("MHX", (major
,minor
), (MAJOR_VERSION
, MINOR_VERSION
), warnedVersion
)
337 if major
!= MAJOR_VERSION
or minor
< FROM_VERSION
:
342 "Wrong MHX version\n" +
343 "Expected MHX %d.%02d but the loaded file " % (MAJOR_VERSION
, MINOR_VERSION
) +
344 "has version MHX %d.%02d\n" % (major
, minor
))
345 if minor
< FROM_VERSION
:
347 "You can disable this error message by deselecting the \n" +
348 "Enforce version option when importing. Better:\n" +
349 "Export the MHX file again with an updated version of MakeHuman.\n" +
350 "The most up-to-date version of MakeHuman is the nightly build.\n")
353 "Download the most recent Blender build from www.graphicall.org. \n" +
354 "The most up-to-date version of the import script is distributed\n" +
355 "with Blender. It can also be downloaded from MakeHuman. \n" +
356 "It is located in the importers/mhx/blender25x \n" +
357 "folder and is called import_scene_mhx.py. \n")
358 if (toggle
& T_EnforceVersion
or minor
> MINOR_VERSION
):
372 global MHX249
, ifResult
, theScale
, defaultScale
, One
374 for (key
, val
, sub
) in tokens
:
377 checkMhxVersion(int(val
[0]), int(val
[1]))
378 elif key
== 'MHX249':
379 MHX249
= eval(val
[0])
380 print("Blender 2.49 compatibility mode is %s\n" % MHX249
)
384 msg
= concatList(val
)
387 msg
= concatList(val
)
390 msg
= concatList(val
)
392 elif key
== 'NoScale':
396 theScale
= defaultScale
398 elif key
== "Object":
399 parseObject(val
, sub
)
402 data
= parseMesh(val
, sub
)
403 elif key
== "Armature":
404 data
= parseArmature(val
, sub
)
406 data
= parsePose(val
, sub
)
407 elif key
== "Action":
408 data
= parseAction(val
, sub
)
409 elif key
== "Material":
410 data
= parseMaterial(val
, sub
)
411 elif key
== "Texture":
412 data
= parseTexture(val
, sub
)
414 data
= parseImage(val
, sub
)
416 data
= parseCurve(val
, sub
)
417 elif key
== "TextCurve":
418 data
= parseTextCurve(val
, sub
)
419 elif key
== "Lattice":
420 data
= parseLattice(val
, sub
)
422 data
= parseGroup(val
, sub
)
424 data
= parseLamp(val
, sub
)
426 data
= parseWorld(val
, sub
)
428 data
= parseScene(val
, sub
)
429 elif key
== "DefineProperty":
430 parseDefineProperty(val
, sub
)
431 elif key
== "Process":
432 parseProcess(val
, sub
)
433 elif key
== "PostProcess":
436 elif key
== "CorrectRig":
438 elif key
== "Rigify":
439 if toggle
& T_Rigify
:
440 rigifyMhx(bpy
.context
, val
[0])
441 elif key
== 'AnimationData':
443 ob
= loadedData
['Object'][val
[0]]
447 bpy
.context
.scene
.objects
.active
= ob
448 parseAnimationData(ob
, val
, sub
)
449 elif key
== 'MaterialAnimationData':
451 ob
= loadedData
['Object'][val
[0]]
455 bpy
.context
.scene
.objects
.active
= ob
456 mat
= ob
.data
.materials
[int(val
[2])]
457 parseAnimationData(mat
, val
, sub
)
458 elif key
== 'ShapeKeys':
460 ob
= loadedData
['Object'][val
[0]]
462 MyError("ShapeKeys object %s does not exist" % val
[0])
464 bpy
.context
.scene
.objects
.active
= ob
465 parseShapeKeys(ob
, ob
.data
, val
, sub
)
467 data
= parseDefaultType(key
, val
, sub
)
470 # parseDefaultType(typ, args, tokens):
473 def parseDefaultType(typ
, args
, tokens
):
478 expr
= "bpy.data.%s.new('%s')" % (Plural
[typ
], name
)
481 bpyType
= typ
.capitalize()
482 loadedData
[bpyType
][name
] = data
486 for (key
, val
, sub
) in tokens
:
487 defaultKey(key
, val
, sub
, 'data', [], globals(), locals())
494 def concatList(elts
):
497 string
+= " %s" % elt
501 # parseAction(args, tokens):
502 # parseFCurve(fcu, args, tokens):
503 # parseKeyFramePoint(pt, args, tokens):
506 def parseAction(args
, tokens
):
511 ob
= bpy
.context
.object
512 bpy
.ops
.object.mode_set(mode
='POSE')
513 if ob
.animation_data
:
514 ob
.animation_data
.action
= None
516 for (key
, val
, sub
) in tokens
:
518 prepareActionFCurve(ob
, created
, val
, sub
)
520 act
= ob
.animation_data
.action
521 loadedData
['Action'][name
] = act
523 print("Ignoring action %s" % name
)
526 print("Action", name
, act
, ob
)
528 for (key
, val
, sub
) in tokens
:
530 fcu
= parseActionFCurve(act
, ob
, val
, sub
)
532 defaultKey(key
, val
, sub
, 'act', [], globals(), locals())
533 ob
.animation_data
.action
= None
534 bpy
.ops
.object.mode_set(mode
='OBJECT')
537 def prepareActionFCurve(ob
, created
, args
, tokens
):
540 (expr
, channel
) = channelFromDataPath(dataPath
, index
)
542 if channel
in created
[expr
]:
545 created
[expr
].append(channel
)
547 created
[expr
] = [channel
]
550 for (key
, val
, sub
) in tokens
:
552 times
.append(int(val
[0]))
557 print("Ignoring illegal expression: %s" % expr
)
562 #bpy.context.scene.current_frame = t
563 bpy
.ops
.anim
.change_frame(frame
= t
)
565 data
.keyframe_insert(channel
)
569 #print("failed", data, expr, channel)
571 print("Mismatch", n
, len(times
), expr
, channel
)
574 def channelFromDataPath(dataPath
, index
):
575 words
= dataPath
.split(']')
580 elif len(words
) == 2:
581 # pose.bones["tongue"].location
582 expr
= "ob.%s]" % (words
[0])
583 cwords
= words
[1].split('.')
585 elif len(words
) == 3:
586 # pose.bones["brow.R"]["mad"]
587 expr
= "ob.%s]" % (words
[0])
588 cwords
= words
[1].split('"')
590 return (expr
, channel
)
592 def parseActionFCurve(act
, ob
, args
, tokens
):
595 (expr
, channel
) = channelFromDataPath(dataPath
, index
)
599 for fcu
in act
.fcurves
:
600 (expr1
, channel1
) = channelFromDataPath(fcu
.data_path
, fcu
.array_index
)
601 if expr1
== expr
and channel1
== channel
and fcu
.array_index
== index
:
608 for (key
, val
, sub
) in tokens
:
611 pt
= fcu
.keyframe_points
[n
]
612 pt
.interpolation
= 'LINEAR'
613 pt
= parseKeyFramePoint(pt
, val
, sub
)
618 #MyError("kp", fcu, n, len(fcu.keyframe_points), val)
620 defaultKey(key
, val
, sub
, 'fcu', [], globals(), locals())
623 def parseKeyFramePoint(pt
, args
, tokens
):
624 pt
.co
= (float(args
[0]), float(args
[1]))
626 pt
.handle1
= (float(args
[2]), float(args
[3]))
627 pt
.handle2
= (float(args
[3]), float(args
[5]))
631 # parseAnimationData(rna, args, tokens):
632 # parseDriver(drv, args, tokens):
633 # parseDriverVariable(var, args, tokens):
636 def parseAnimationData(rna
, args
, tokens
):
637 if not eval(args
[1]):
639 if rna
.animation_data
is None:
640 rna
.animation_data_create()
641 adata
= rna
.animation_data
642 for (key
, val
, sub
) in tokens
:
644 fcu
= parseAnimDataFCurve(adata
, rna
, val
, sub
)
646 defaultKey(key
, val
, sub
, 'adata', [], globals(), locals())
649 def parseAnimDataFCurve(adata
, rna
, args
, tokens
):
655 for (key
, val
, sub
) in tokens
:
657 fcu
= parseDriver(adata
, dataPath
, index
, rna
, val
, sub
)
658 fmod
= fcu
.modifiers
[0]
659 fcu
.modifiers
.remove(fmod
)
660 elif key
== 'FModifier':
661 parseFModifier(fcu
, val
, sub
)
663 pt
= fcu
.keyframe_points
.insert(n
, 0)
664 pt
.interpolation
= 'LINEAR'
665 pt
= parseKeyFramePoint(pt
, val
, sub
)
668 defaultKey(key
, val
, sub
, 'fcu', [], globals(), locals())
672 fcurve = con.driver_add("influence", 0)
673 driver = fcurve.driver
674 driver.type = 'AVERAGE'
676 def parseDriver(adata
, dataPath
, index
, rna
, args
, tokens
):
677 if dataPath
[-1] == ']':
678 words
= dataPath
.split(']')
679 expr
= "rna." + words
[0] + ']'
680 pwords
= words
[1].split('"')
685 words
= dataPath
.split('.')
688 for n
in range(len(words
)-1):
689 expr
+= "." + words
[n
]
690 expr
+= ".driver_add('%s', index)" % channel
695 for (key
, val
, sub
) in tokens
:
696 if key
== 'DriverVariable':
697 var
= parseDriverVariable(drv
, rna
, val
, sub
)
699 defaultKey(key
, val
, sub
, 'drv', [], globals(), locals())
702 def parseDriverVariable(drv
, rna
, args
, tokens
):
703 var
= drv
.variables
.new()
707 for (key
, val
, sub
) in tokens
:
709 parseDriverTarget(var
, nTarget
, rna
, val
, sub
)
712 defaultKey(key
, val
, sub
, 'var', [], globals(), locals())
715 def parseFModifier(fcu
, args
, tokens
):
716 fmod
= fcu
.modifiers
.new(args
[0])
717 #fmod = fcu.modifiers[0]
718 for (key
, val
, sub
) in tokens
:
719 defaultKey(key
, val
, sub
, 'fmod', [], globals(), locals())
723 var = driver.variables.new()
724 var.name = target_bone
725 var.targets[0].id_type = 'OBJECT'
726 var.targets[0].id = obj
727 var.targets[0].rna_path = driver_path
729 def parseDriverTarget(var
, nTarget
, rna
, args
, tokens
):
730 targ
= var
.targets
[nTarget
]
732 #targ.id_type = args[1]
733 dtype
= args
[1].capitalize()
735 targ
.id = loadedData
[dtype
][name
]
736 for (key
, val
, sub
) in tokens
:
737 if key
== 'data_path':
738 words
= val
[0].split('"')
740 targ
.data_path
= propNames(words
[1])[1]
742 targ
.data_path
= propNames(val
)[1]
744 defaultKey(key
, val
, sub
, 'targ', [], globals(), locals())
749 # parseMaterial(args, ext, tokens):
750 # parseMTex(mat, args, tokens):
751 # parseTexture(args, tokens):
754 def parseMaterial(args
, tokens
):
757 mat
= bpy
.data
.materials
.new(name
)
760 loadedData
['Material'][name
] = mat
761 for (key
, val
, sub
) in tokens
:
763 parseMTex(mat
, val
, sub
)
765 parseRamp(mat
, val
, sub
)
766 elif key
== 'RaytraceTransparency':
767 parseDefault(mat
.raytrace_transparency
, sub
, {}, [])
769 parseDefault(mat
.halo
, sub
, {}, [])
771 parseDefault(mat
.subsurface_scattering
, sub
, {}, [])
772 elif key
== 'Strand':
773 parseDefault(mat
.strand
, sub
, {}, [])
774 elif key
== 'NodeTree':
776 parseNodeTree(mat
.node_tree
, val
, sub
)
777 elif key
== 'AnimationData':
778 parseAnimationData(mat
, val
, sub
)
780 exclude
= ['specular_intensity', 'tangent_shading']
781 defaultKey(key
, val
, sub
, 'mat', [], globals(), locals())
785 def parseMTex(mat
, args
, tokens
):
791 tex
= loadedData
['Texture'][texname
]
792 mtex
= mat
.texture_slots
.add()
793 mtex
.texture_coords
= texco
796 for (key
, val
, sub
) in tokens
:
797 defaultKey(key
, val
, sub
, "mtex", [], globals(), locals())
801 def parseTexture(args
, tokens
):
804 print( "Parsing texture %s" % args
)
806 tex
= bpy
.data
.textures
.new(name
=name
, type=args
[1])
807 loadedData
['Texture'][name
] = tex
809 for (key
, val
, sub
) in tokens
:
813 img
= loadedData
['Image'][imgName
]
816 msg
= "Unable to load image '%s'" % val
[0]
818 parseRamp(tex
, val
, sub
)
819 elif key
== 'NodeTree':
821 parseNodeTree(tex
.node_tree
, val
, sub
)
823 defaultKey(key
, val
, sub
, "tex", ['use_nodes', 'use_textures', 'contrast', 'use_alpha'], globals(), locals())
827 def parseRamp(data
, args
, tokens
):
828 nvar
= "data.%s" % args
[0]
829 use
= "data.use_%s = True" % args
[0]
834 for (key
, val
, sub
) in tokens
:
835 # print("Ramp", key, val)
837 elts
[n
].color
= eval(val
[0])
838 elts
[n
].position
= eval(val
[1])
841 defaultKey(key
, val
, sub
, "tex", ['use_nodes', 'use_textures', 'contrast'], globals(), locals())
843 def parseSSS(mat
, args
, tokens
):
844 sss
= mat
.subsurface_scattering
845 for (key
, val
, sub
) in tokens
:
846 defaultKey(key
, val
, sub
, "sss", [], globals(), locals())
848 def parseStrand(mat
, args
, tokens
):
850 for (key
, val
, sub
) in tokens
:
851 defaultKey(key
, val
, sub
, "strand", [], globals(), locals())
854 # parseNodeTree(tree, args, tokens):
855 # parseNode(node, args, tokens):
856 # parseSocket(socket, args, tokens):
859 def parseNodeTree(tree
, args
, tokens
):
861 print("Tree", tree
, args
)
862 print(list(tree
.nodes
))
864 for (key
, val
, sub
) in tokens
:
866 parseNodes(tree
.nodes
, val
, sub
)
868 defaultKey(key
, val
, sub
, "tree", [], globals(), locals())
870 def parseNodes(nodes
, args
, tokens
):
871 print("Nodes", nodes
, args
)
874 for (key
, val
, sub
) in tokens
:
876 parseSocket(node
.inputs
, val
, sub
)
877 elif key
== 'Outputs':
878 parseSocket(node
.outputs
, val
, sub
)
880 defaultKey(key
, val
, sub
, "node", [], globals(), locals())
882 def parseNode(node
, args
, tokens
):
883 print("Node", node
, args
)
884 print(list(node
.inputs
), list(node
.outputs
))
886 for (key
, val
, sub
) in tokens
:
888 parseSocket(node
.inputs
, val
, sub
)
889 elif key
== 'Outputs':
890 parseSocket(node
.outputs
, val
, sub
)
892 defaultKey(key
, val
, sub
, "node", [], globals(), locals())
894 def parseSocket(socket
, args
, tokens
):
895 print("Socket", socket
, args
)
896 socket
.name
= args
[0]
897 for (key
, val
, sub
) in tokens
:
899 parseNode(tree
.nodes
, val
, sub
)
901 defaultKey(key
, val
, sub
, "tree", [], globals(), locals())
906 # loadImage(filepath):
907 # parseImage(args, tokens):
910 def loadImage(relFilepath
):
911 filepath
= os
.path
.normpath(os
.path
.join(theDir
, relFilepath
))
912 print( "Loading %s" % filepath
.encode('utf-8','strict'))
913 if os
.path
.isfile(filepath
):
914 #print( "Found file %s." % filepath.encode('utf-8','strict') )
916 img
= bpy
.data
.images
.load(filepath
)
919 print( "Cannot read image" )
922 print( "No such file: %s" % filepath
.encode('utf-8','strict') )
926 def parseImage(args
, tokens
):
930 for (key
, val
, sub
) in tokens
:
931 if key
== 'Filename':
933 for n
in range(1,len(val
)):
934 filename
+= " " + val
[n
]
935 img
= loadImage(filename
)
940 defaultKey(key
, val
, sub
, "img", ['depth', 'dirty', 'has_data', 'size', 'type', 'use_premultiply'], globals(), locals())
941 print ("Image %s" % img
)
942 loadedData
['Image'][imgName
] = img
946 # parseObject(args, tokens):
947 # createObject(type, name, data, datName):
948 # setObjectAndData(args, typ):
951 def parseObject(args
, tokens
):
953 print( "Parsing object %s" % args
)
959 ob
= bpy
.data
.objects
.new(name
, None)
960 loadedData
['Object'][name
] = ob
964 data
= loadedData
[typ
.capitalize()][datName
]
966 MyError("Failed to find data: %s %s %s" % (name
, typ
, datName
))
970 ob
= loadedData
['Object'][name
]
971 bpy
.context
.scene
.objects
.active
= ob
972 #print("Found data", ob)
977 ob
= createObject(typ
, name
, data
, datName
)
980 for (key
, val
, sub
) in tokens
:
981 if key
== 'Modifier':
982 parseModifier(ob
, val
, sub
)
983 elif key
== 'Constraint':
984 parseConstraint(ob
.constraints
, None, val
, sub
)
985 elif key
== 'AnimationData':
986 parseAnimationData(ob
, val
, sub
)
987 elif key
== 'ParticleSystem':
988 parseParticleSystem(ob
, val
, sub
)
989 elif key
== 'FieldSettings':
990 parseDefault(ob
.field
, sub
, {}, [])
992 defaultKey(key
, val
, sub
, "ob", ['type', 'data'], globals(), locals())
994 if bpy
.context
.object == ob
:
995 if ob
.type == 'MESH':
996 bpy
.ops
.object.shade_smooth()
998 print("Context", ob
, bpy
.context
.object, bpy
.context
.scene
.objects
.active
)
1001 def createObject(typ
, name
, data
, datName
):
1002 # print( "Creating object %s %s %s" % (typ, name, data) )
1003 ob
= bpy
.data
.objects
.new(name
, data
)
1005 loadedData
[typ
.capitalize()][datName
] = data
1006 loadedData
['Object'][name
] = ob
1009 def linkObject(ob
, data
):
1010 #print("Data", data, ob.data)
1011 if data
and ob
.data
is None:
1013 scn
= bpy
.context
.scene
1014 scn
.objects
.link(ob
)
1015 scn
.objects
.active
= ob
1016 #print("Linked object", ob)
1017 #print("Scene", scn)
1018 #print("Active", scn.objects.active)
1019 #print("Context", bpy.context.object)
1022 def setObjectAndData(args
, typ
):
1025 #bpy.ops.object.add(type=typ)
1026 ob
= bpy
.context
.object
1028 ob
.data
.name
= datName
1029 loadedData
[typ
][datName
] = ob
.data
1030 loadedData
['Object'][obName
] = ob
1035 # parseModifier(ob, args, tokens):
1039 def parseModifier(ob
, args
, tokens
):
1042 if typ
== 'PARTICLE_SYSTEM':
1044 mod
= ob
.modifiers
.new(name
, typ
)
1045 for (key
, val
, sub
) in tokens
:
1046 if key
== 'HookAssignNth':
1047 if val
[0] == 'CURVE':
1048 hookAssignNth(mod
, int(val
[1]), True, ob
.data
.splines
[0].points
)
1049 elif val
[0] == 'LATTICE':
1050 hookAssignNth(mod
, int(val
[1]), False, ob
.data
.points
)
1051 elif val
[0] == 'MESH':
1052 hookAssignNth(mod
, int(val
[1]), True, ob
.data
.vertices
)
1054 MyError("Unknown hook %s" % val
)
1056 defaultKey(key
, val
, sub
, 'mod', [], globals(), locals())
1059 def hookAssignNth(mod
, n
, select
, points
):
1063 points
[n
].select
= True
1066 sel
.append(pt
.select
)
1067 #print(mod, sel, n, points)
1069 bpy
.ops
.object.mode_set(mode
='EDIT')
1070 bpy
.ops
.object.hook_reset(modifier
=mod
.name
)
1071 bpy
.ops
.object.hook_select(modifier
=mod
.name
)
1072 bpy
.ops
.object.hook_assign(modifier
=mod
.name
)
1073 bpy
.ops
.object.mode_set(mode
='OBJECT')
1077 # parseParticleSystem(ob, args, tokens):
1078 # parseParticles(particles, args, tokens):
1079 # parseParticle(par, args, tokens):
1082 def parseParticleSystem(ob
, args
, tokens
):
1083 print(ob
, bpy
.context
.object)
1084 pss
= ob
.particle_systems
1085 print(pss
, pss
.values())
1088 #psys = pss.new(name, typ)
1089 bpy
.ops
.object.particle_system_add()
1090 print(pss
, pss
.values())
1093 psys
.settings
.type = typ
1094 loadedData
['ParticleSystem'][name
] = psys
1097 for (key
, val
, sub
) in tokens
:
1098 if key
== 'Particles':
1099 parseParticles(psys
, val
, sub
)
1101 defaultKey(key
, val
, sub
, 'psys', [], globals(), locals())
1104 def parseParticles(psys
, args
, tokens
):
1105 particles
= psys
.particles
1106 bpy
.ops
.particle
.particle_edit_toggle()
1108 for (key
, val
, sub
) in tokens
:
1109 if key
== 'Particle':
1110 parseParticle(particles
[n
], val
, sub
)
1113 for par
in particles
:
1114 defaultKey(key
, val
, sub
, 'par', [], globals(), locals())
1115 bpy
.ops
.particle
.particle_edit_toggle()
1118 def parseParticle(par
, args
, tokens
):
1120 for (key
, val
, sub
) in tokens
:
1123 h
.location
= eval(val
[0])
1124 h
.time
= int(val
[1])
1125 h
.weight
= float(val
[2])
1127 elif key
== 'location':
1128 par
.location
= eval(val
[0])
1132 # unpackList(list_of_tuples):
1135 def unpackList(list_of_tuples
):
1137 for t
in list_of_tuples
:
1144 # parseMesh (args, tokens):
1147 def parseMesh (args
, tokens
):
1148 global todo
, BMeshAware
1150 print( "Parsing mesh %s" % args
)
1154 me
= bpy
.data
.meshes
.new(mename
)
1155 ob
= createObject('MESH', obname
, me
, mename
)
1163 for (key
, val
, sub
) in tokens
:
1165 verts
= parseVerts(sub
)
1166 elif key
== 'Edges':
1167 edges
= parseEdges(sub
)
1168 elif key
== 'Faces':
1169 faces
= parseFaces(sub
)
1172 me
.from_pydata(verts
, [], faces
)
1174 me
.from_pydata(verts
, edges
, [])
1187 for (key
, val
, sub
) in tokens
:
1188 if key
== 'Verts' or key
== 'Edges' or key
== 'Faces':
1190 elif key
== 'MeshTextureFaceLayer':
1192 parseUvTextureBMesh(val
, sub
, me
)
1194 parseUvTextureNoBMesh(val
, sub
, me
)
1195 elif key
== 'MeshColorLayer':
1196 parseVertColorLayer(val
, sub
, me
)
1197 elif key
== 'VertexGroup':
1198 parseVertexGroup(ob
, me
, val
, sub
)
1199 elif key
== 'ShapeKeys':
1200 parseShapeKeys(ob
, me
, val
, sub
)
1201 elif key
== 'Material':
1203 mat
= loadedData
['Material'][val
[0]]
1207 me
.materials
.append(mat
)
1209 defaultKey(key
, val
, sub
, "me", [], globals(), locals())
1211 for (key
, val
, sub
) in tokens
:
1214 parseFaces2BMesh(sub
, me
)
1216 parseFaces2NoBMesh(sub
, me
)
1220 # parseVerts(tokens):
1221 # parseEdges(tokens):
1222 # parseFaces(tokens):
1223 # parseFaces2(tokens, me):
1226 def parseVerts(tokens
):
1228 for (key
, val
, sub
) in tokens
:
1230 verts
.append( (theScale
*float(val
[0]), theScale
*float(val
[1]), theScale
*float(val
[2])) )
1233 def parseEdges(tokens
):
1235 for (key
, val
, sub
) in tokens
:
1237 edges
.append((int(val
[0]), int(val
[1])))
1240 def parseFaces(tokens
):
1242 for (key
, val
, sub
) in tokens
:
1245 face
= [int(val
[0]), int(val
[1]), int(val
[2])]
1247 face
= [int(val
[0]), int(val
[1]), int(val
[2]), int(val
[3])]
1251 def parseFaces2BMesh(tokens
, me
):
1253 for (key
, val
, sub
) in tokens
:
1256 f
.material_index
= int(val
[0])
1257 f
.use_smooth
= int(val
[1])
1263 for i
in range(npts
):
1265 f
.material_index
= mn
1272 f
.material_index
= mn
1273 elif key
== 'ftall':
1275 smooth
= int(val
[1])
1276 for f
in me
.polygons
:
1277 f
.material_index
= mat
1278 f
.use_smooth
= smooth
1281 def parseFaces2NoBMesh(tokens
, me
):
1283 for (key
, val
, sub
) in tokens
:
1286 f
.material_index
= int(val
[0])
1287 f
.use_smooth
= int(val
[1])
1293 for i
in range(npts
):
1295 f
.material_index
= mn
1302 f
.material_index
= mn
1303 elif key
== 'ftall':
1305 smooth
= int(val
[1])
1307 f
.material_index
= mat
1308 f
.use_smooth
= smooth
1313 # parseUvTexture(args, tokens, me,):
1314 # parseUvTexData(args, tokens, uvdata):
1317 def parseUvTextureBMesh(args
, tokens
, me
):
1319 bpy
.ops
.mesh
.uv_texture_add()
1320 uvtex
= me
.uv_textures
[-1]
1322 uvloop
= me
.uv_layers
[-1]
1323 loadedData
['MeshTextureFaceLayer'][name
] = uvloop
1324 for (key
, val
, sub
) in tokens
:
1326 parseUvTexDataBMesh(val
, sub
, uvloop
.data
)
1328 defaultKey(key
, val
, sub
, "uvtex", [], globals(), locals())
1331 def parseUvTexDataBMesh(args
, tokens
, data
):
1333 for (key
, val
, sub
) in tokens
:
1335 data
[n
].uv
= (float(val
[0]), float(val
[1]))
1337 data
[n
].uv
= (float(val
[2]), float(val
[3]))
1339 data
[n
].uv
= (float(val
[4]), float(val
[5]))
1342 data
[n
].uv
= (float(val
[6]), float(val
[7]))
1346 def parseUvTextureNoBMesh(args
, tokens
, me
):
1348 uvtex
= me
.uv_textures
.new(name
= name
)
1349 loadedData
['MeshTextureFaceLayer'][name
] = uvtex
1350 for (key
, val
, sub
) in tokens
:
1352 parseUvTexDataNoBMesh(val
, sub
, uvtex
.data
)
1354 defaultKey(key
, val
, sub
, "uvtex", [], globals(), locals())
1357 def parseUvTexDataNoBMesh(args
, tokens
, data
):
1359 for (key
, val
, sub
) in tokens
:
1361 data
[n
].uv1
= (float(val
[0]), float(val
[1]))
1362 data
[n
].uv2
= (float(val
[2]), float(val
[3]))
1363 data
[n
].uv3
= (float(val
[4]), float(val
[5]))
1365 data
[n
].uv4
= (float(val
[6]), float(val
[7]))
1370 # parseVertColorLayer(args, tokens, me):
1371 # parseVertColorData(args, tokens, data):
1374 def parseVertColorLayer(args
, tokens
, me
):
1376 print("VertColorLayer", name
)
1377 vcol
= me
.vertex_colors
.new(name
)
1378 loadedData
['MeshColorLayer'][name
] = vcol
1379 for (key
, val
, sub
) in tokens
:
1381 parseVertColorData(val
, sub
, vcol
.data
)
1383 defaultKey(key
, val
, sub
, "vcol", [], globals(), locals())
1386 def parseVertColorData(args
, tokens
, data
):
1388 for (key
, val
, sub
) in tokens
:
1390 data
[n
].color1
= eval(val
[0])
1391 data
[n
].color2
= eval(val
[1])
1392 data
[n
].color3
= eval(val
[2])
1393 data
[n
].color4
= eval(val
[3])
1399 # parseVertexGroup(ob, me, args, tokens):
1402 def parseVertexGroup(ob
, me
, args
, tokens
):
1405 print( "Parsing vertgroup %s" % args
)
1414 if (toggle
& T_Armature
) or (grpName
in ['Eye_L', 'Eye_R', 'Gums', 'Head', 'Jaw', 'Left', 'Middle', 'Right', 'Scalp']):
1416 group
= loadedData
['VertexGroup'][grpName
]
1418 group
= ob
.vertex_groups
.new(grpName
)
1419 loadedData
['VertexGroup'][grpName
] = group
1420 for (key
, val
, sub
) in tokens
:
1422 group
.add( [int(val
[0])], float(val
[1]), 'REPLACE' )
1427 # parseShapeKeys(ob, me, args, tokens):
1428 # parseShapeKey(ob, me, args, tokens):
1429 # addShapeKey(ob, name, vgroup, tokens):
1434 if (toggle
& T_Shapekeys
) and (name
== 'Basis'):
1437 return (toggle
& T_Face
)
1440 def parseShapeKeys(ob
, me
, args
, tokens
):
1441 for (key
, val
, sub
) in tokens
:
1442 if key
== 'ShapeKey':
1443 parseShapeKey(ob
, me
, val
, sub
)
1444 elif key
== 'AnimationData':
1446 parseAnimationData(me
.shape_keys
, val
, sub
)
1447 elif key
== 'Expression':
1448 prop
= "Mhe" + val
[0].capitalize()
1449 parseUnits(prop
, ob
, sub
)
1450 elif key
== 'Viseme':
1451 name
= val
[0].upper()
1452 if name
in ["REST", "ETC"]:
1453 name
= name
.capitalize()
1455 parseUnits(prop
, ob
, sub
)
1456 ob
.active_shape_key_index
= 0
1459 def parseUnits(prop
, ob
, sub
):
1462 unit
= words
[0].replace("-","_")
1464 string
+= "%s:%s;" % (unit
, value
)
1469 def parseShapeKey(ob
, me
, args
, tokens
):
1471 print( "Parsing ob %s shape %s" % (bpy
.context
.object, args
[0] ))
1474 if invalid(args
[2]):
1477 if lr
== 'Sym': # or toggle & T_Symm:
1478 addShapeKey(ob
, name
, None, tokens
)
1480 addShapeKey(ob
, name
+'_L', 'Left', tokens
)
1481 addShapeKey(ob
, name
+'_R', 'Right', tokens
)
1483 MyError("ShapeKey L/R %s" % lr
)
1487 def addShapeKey(ob
, name
, vgroup
, tokens
):
1488 skey
= ob
.shape_key_add(name
=name
, from_mix
=False)
1490 skey
.relative_key
= loadedData
['ShapeKey']['Basis']
1493 skey
.vertex_group
= vgroup
1494 loadedData
['ShapeKey'][name
] = skey
1496 for (key
, val
, sub
) in tokens
:
1499 pt
= skey
.data
[index
].co
1500 pt
[0] += theScale
*float(val
[1])
1501 pt
[1] += theScale
*float(val
[2])
1502 pt
[2] += theScale
*float(val
[3])
1504 defaultKey(key
, val
, sub
, "skey", [], globals(), locals())
1510 # parseArmature (obName, args, tokens)
1513 def parseArmature (args
, tokens
):
1514 global toggle
, theArmature
1516 print( "Parsing armature %s" % args
)
1522 amt
= bpy
.data
.armatures
.new(amtname
)
1523 ob
= createObject('ARMATURE', obname
, amt
, amtname
)
1527 bpy
.ops
.object.mode_set(mode
='OBJECT')
1528 bpy
.ops
.object.mode_set(mode
='EDIT')
1532 for (key
, val
, sub
) in tokens
:
1535 if not invalid(val
[1]):
1536 bone
= amt
.edit_bones
.new(bname
)
1537 parseBone(bone
, amt
, sub
, heads
, tails
)
1538 loadedData
['Bone'][bname
] = bone
1539 elif key
== 'RecalcRoll':
1541 for bone
in amt
.edit_bones
:
1543 blist
= eval(val
[0])
1545 bone
= amt
.edit_bones
[name
]
1547 bpy
.ops
.armature
.calculate_roll(type='Z')
1548 for bone
in amt
.edit_bones
:
1549 rolls
[bone
.name
] = bone
.roll
1550 bpy
.ops
.object.mode_set(mode
='OBJECT')
1551 for bone
in amt
.bones
:
1552 bone
['Roll'] = rolls
[bone
.name
]
1553 bpy
.ops
.object.mode_set(mode
='EDIT')
1555 defaultKey(key
, val
, sub
, "amt", ['MetaRig'], globals(), locals())
1556 bpy
.ops
.object.mode_set(mode
='OBJECT')
1561 # parseBone(bone, amt, tokens, heads, tails):
1564 def parseBone(bone
, amt
, tokens
, heads
, tails
):
1567 for (key
, val
, sub
) in tokens
:
1569 bone
.head
= (theScale
*float(val
[0]), theScale
*float(val
[1]), theScale
*float(val
[2]))
1571 bone
.tail
= (theScale
*float(val
[0]), theScale
*float(val
[1]), theScale
*float(val
[2]))
1572 #elif key == 'restrict_select':
1574 elif key
== 'hide' and val
[0] == 'True':
1577 defaultKey(key
, val
, sub
, "bone", [], globals(), locals())
1581 # parsePose (args, tokens):
1584 def parsePose (args
, tokens
):
1587 ob
= loadedData
['Object'][name
]
1588 bpy
.context
.scene
.objects
.active
= ob
1589 bpy
.ops
.object.mode_set(mode
='POSE')
1590 pbones
= ob
.pose
.bones
1592 for (key
, val
, sub
) in tokens
:
1593 if key
== 'Posebone':
1594 parsePoseBone(pbones
, ob
, val
, sub
)
1595 elif key
== 'BoneGroup':
1596 parseBoneGroup(ob
.pose
, nGrps
, val
, sub
)
1598 elif key
== 'SetProp':
1601 value
= eval(val
[2])
1605 defaultKey(key
, val
, sub
, "ob.pose", [], globals(), locals())
1606 bpy
.ops
.object.mode_set(mode
='OBJECT')
1611 # parsePoseBone(pbones, args, tokens):
1612 # parseArray(data, exts, args):
1615 def parseBoneGroup(pose
, nGrps
, args
, tokens
):
1618 print( "Parsing bonegroup %s" % args
)
1620 bpy
.ops
.pose
.group_add()
1621 bg
= pose
.bone_groups
.active
1622 loadedData
['BoneGroup'][name
] = bg
1623 for (key
, val
, sub
) in tokens
:
1624 defaultKey(key
, val
, sub
, "bg", [], globals(), locals())
1627 def parsePoseBone(pbones
, ob
, args
, tokens
):
1629 if invalid(args
[1]):
1634 amt
.bones
.active
= pb
.bone
1636 for (key
, val
, sub
) in tokens
:
1637 if key
== 'Constraint':
1638 amt
.bones
.active
= pb
.bone
1639 cns
= parseConstraint(pb
.constraints
, pb
, val
, sub
)
1640 elif key
== 'bpyops':
1641 amt
.bones
.active
= pb
.bone
1642 expr
= "bpy.ops.%s" % val
[0]
1645 elif key
== 'ik_dof':
1646 parseArray(pb
, ["ik_dof_x", "ik_dof_y", "ik_dof_z"], val
)
1647 elif key
== 'ik_limit':
1648 parseArray(pb
, ["ik_limit_x", "ik_limit_y", "ik_limit_z"], val
)
1649 elif key
== 'ik_max':
1650 parseArray(pb
, ["ik_max_x", "ik_max_y", "ik_max_z"], val
)
1651 elif key
== 'ik_min':
1652 parseArray(pb
, ["ik_min_x", "ik_min_y", "ik_min_z"], val
)
1653 elif key
== 'ik_stiffness':
1654 parseArray(pb
, ["ik_stiffness_x", "ik_stiffness_y", "ik_stiffness_z"], val
)
1656 #bpy.ops.object.mode_set(mode='OBJECT')
1657 amt
.bones
[name
].hide
= eval(val
[0])
1658 #bpy.ops.object.mode_set(mode='POSE')
1661 defaultKey(key
, val
, sub
, "pb", [], globals(), locals())
1662 #print("pb %s done" % name)
1665 def parseArray(data
, exts
, args
):
1668 expr
= "data.%s = %s" % (ext
, args
[n
])
1675 # parseConstraint(constraints, pb, args, tokens)
1678 def parseConstraint(constraints
, pb
, args
, tokens
):
1679 if invalid(args
[2]):
1681 if (toggle
&T_Opcns
and pb
):
1683 aob
= bpy
.context
.object
1688 print("pose", apose
)
1689 abone
= aamt
.bones
.active
1690 print("bone", abone
)
1691 print('Num cns before', len(list(constraints
)))
1692 bpy
.ops
.pose
.constraint_add(type=args
[1])
1693 cns
= constraints
.active
1694 print('and after', pb
, cns
, len(list(constraints
)))
1696 cns
= constraints
.new(args
[1])
1699 for (key
,val
,sub
) in tokens
:
1701 parseArray(cns
, ["invert_x", "invert_y", "invert_z"], val
)
1703 parseArray(cns
, ["use_x", "use_y", "use_z"], val
)
1704 elif key
== 'pos_lock':
1705 parseArray(cns
, ["lock_location_x", "lock_location_y", "lock_location_z"], val
)
1706 elif key
== 'rot_lock':
1707 parseArray(cns
, ["lock_rotation_x", "lock_rotation_y", "lock_rotation_z"], val
)
1709 defaultKey(key
, val
, sub
, "cns", ["use_target"], globals(), locals())
1712 #print("cns %s done" % cns.name)
1718 # parseCurve (args, tokens):
1719 # parseSpline(cu, args, tokens):
1720 # parseBezier(spline, n, args, tokens):
1723 def parseCurve (args
, tokens
):
1726 print( "Parsing curve %s" % args
)
1727 bpy
.ops
.object.add(type='CURVE')
1728 cu
= setObjectAndData(args
, 'Curve')
1730 for (key
, val
, sub
) in tokens
:
1732 parseSpline(cu
, val
, sub
)
1734 defaultKey(key
, val
, sub
, "cu", [], globals(), locals())
1737 def parseTextCurve (args
, tokens
):
1740 print( "Parsing text curve %s" % args
)
1741 bpy
.ops
.object.text_add()
1742 txt
= setObjectAndData(args
, 'Text')
1744 for (key
, val
, sub
) in tokens
:
1746 parseSpline(txt
, val
, sub
)
1747 elif key
== 'BodyFormat':
1748 parseCollection(txt
.body_format
, sub
, [])
1749 elif key
== 'EditFormat':
1750 parseDefault(txt
.edit_format
, sub
, {}, [])
1752 parseDefault(txt
.font
, sub
, {}, [])
1753 elif key
== 'TextBox':
1754 parseCollection(txt
.body_format
, sub
, [])
1756 defaultKey(key
, val
, sub
, "txt", [], globals(), locals())
1760 def parseSpline(cu
, args
, tokens
):
1762 spline
= cu
.splines
.new(typ
)
1763 nPointsU
= int(args
[1])
1764 nPointsV
= int(args
[2])
1765 #spline.point_count_u = nPointsU
1766 #spline.point_count_v = nPointsV
1767 if typ
== 'BEZIER' or typ
== 'BSPLINE':
1768 spline
.bezier_points
.add(nPointsU
)
1770 spline
.points
.add(nPointsU
)
1773 for (key
, val
, sub
) in tokens
:
1775 parseBezier(spline
.bezier_points
[n
], val
, sub
)
1778 parsePoint(spline
.points
[n
], val
, sub
)
1781 defaultKey(key
, val
, sub
, "spline", [], globals(), locals())
1784 def parseBezier(bez
, args
, tokens
):
1785 bez
.co
= eval(args
[0])
1786 bez
.co
= theScale
*bez
.co
1787 bez
.handle1
= eval(args
[1])
1788 bez
.handle1_type
= args
[2]
1789 bez
.handle2
= eval(args
[3])
1790 bez
.handle2_type
= args
[4]
1793 def parsePoint(pt
, args
, tokens
):
1794 pt
.co
= eval(args
[0])
1795 pt
.co
= theScale
*pt
.co
1800 # parseLattice (args, tokens):
1803 def parseLattice (args
, tokens
):
1806 print( "Parsing lattice %s" % args
)
1807 bpy
.ops
.object.add(type='LATTICE')
1808 lat
= setObjectAndData(args
, 'Lattice')
1809 for (key
, val
, sub
) in tokens
:
1811 parseLatticePoints(val
, sub
, lat
.points
)
1813 defaultKey(key
, val
, sub
, "lat", [], globals(), locals())
1816 def parseLatticePoints(args
, tokens
, points
):
1819 for (key
, val
, sub
) in tokens
:
1821 v
= points
[n
].co_deform
1822 v
.x
= theScale
*float(val
[0])
1823 v
.y
= theScale
*float(val
[1])
1824 v
.z
= theScale
*float(val
[2])
1829 # parseLamp (args, tokens):
1830 # parseFalloffCurve(focu, args, tokens):
1833 def parseLamp (args
, tokens
):
1836 print( "Parsing lamp %s" % args
)
1837 bpy
.ops
.object.add(type='LAMP')
1838 lamp
= setObjectAndData(args
, 'Lamp')
1839 for (key
, val
, sub
) in tokens
:
1840 if key
== 'FalloffCurve':
1841 parseFalloffCurve(lamp
.falloff_curve
, val
, sub
)
1843 defaultKey(key
, val
, sub
, "lamp", [], globals(), locals())
1846 def parseFalloffCurve(focu
, args
, tokens
):
1850 # parseGroup (args, tokens):
1851 # parseGroupObjects(args, tokens, grp):
1854 def parseGroup (args
, tokens
):
1857 print( "Parsing group %s" % args
)
1860 grp
= bpy
.data
.groups
.new(grpName
)
1861 loadedData
['Group'][grpName
] = grp
1862 for (key
, val
, sub
) in tokens
:
1863 if key
== 'Objects':
1864 parseGroupObjects(val
, sub
, grp
)
1866 defaultKey(key
, val
, sub
, "grp", [], globals(), locals())
1869 def parseGroupObjects(args
, tokens
, grp
):
1872 for (key
, val
, sub
) in tokens
:
1875 ob
= loadedData
['Object'][val
[0]]
1876 grp
.objects
.link(ob
)
1880 print(ob
, ob
.type, rig
, ob
.parent
)
1881 if ob
.type == 'ARMATURE':
1883 elif ob
.type == 'EMPTY' and rig
and not ob
.parent
:
1889 # parseWorld (args, tokens):
1892 def parseWorld (args
, tokens
):
1895 print( "Parsing world %s" % args
)
1896 world
= bpy
.context
.scene
.world
1897 for (key
, val
, sub
) in tokens
:
1898 if key
== 'Lighting':
1899 parseDefault(world
.lighting
, sub
, {}, [])
1901 parseDefault(world
.mist
, sub
, {}, [])
1902 elif key
== 'Stars':
1903 parseDefault(world
.stars
, sub
, {}, [])
1905 defaultKey(key
, val
, sub
, "world", [], globals(), locals())
1909 # parseScene (args, tokens):
1910 # parseRenderSettings(render, args, tokens):
1911 # parseToolSettings(tool, args, tokens):
1914 def parseScene (args
, tokens
):
1917 print( "Parsing scene %s" % args
)
1918 scn
= bpy
.context
.scene
1919 for (key
, val
, sub
) in tokens
:
1920 if key
== 'NodeTree':
1921 scn
.use_nodes
= True
1922 parseNodeTree(scn
, val
, sub
)
1923 elif key
== 'GameData':
1924 parseDefault(scn
.game_data
, sub
, {}, [])
1925 elif key
== 'KeyingSet':
1927 #parseDefault(scn.keying_sets, sub, {}, [])
1928 elif key
== 'ObjectBase':
1930 #parseDefault(scn.bases, sub, {}, [])
1931 elif key
== 'RenderSettings':
1932 parseRenderSettings(scn
.render
, sub
, [])
1933 elif key
== 'ToolSettings':
1934 subkeys
= {'ImagePaint' : "image_paint",
1935 'Sculpt' : "sculpt",
1936 'VertexPaint' : "vertex_paint",
1937 'WeightPaint' : "weight_paint" }
1938 parseDefault(scn
.tool_settings
, sub
, subkeys
, [])
1939 elif key
== 'UnitSettings':
1940 parseDefault(scn
.unit_settings
, sub
, {}, [])
1942 defaultKey(key
, val
, sub
, "scn", [], globals(), locals())
1945 def parseRenderSettings(render
, args
, tokens
):
1948 print( "Parsing RenderSettings %s" % args
)
1949 for (key
, val
, sub
) in tokens
:
1952 #parseDefault(scn.layers, sub, [])
1954 defaultKey(key
, val
, sub
, "render", [], globals(), locals())
1958 # parseDefineProperty(args, tokens):
1961 def parseDefineProperty(args
, tokens
):
1962 expr
= "bpy.types.Object.%s = %sProperty" % (args
[0], args
[1])
1964 for option
in args
[2:]:
1965 expr
+= "%s %s" % (c
, option
)
1977 def correctRig(args
):
1979 print("CorrectRig %s" % human
)
1981 ob
= loadedData
['Object'][human
]
1984 ob
.MhxShapekeyDrivers
= (toggle
&T_Shapekeys
!= 0 and toggle
&T_ShapeDrivers
!= 0)
1985 bpy
.context
.scene
.objects
.active
= ob
1986 bpy
.ops
.object.mode_set(mode
='POSE')
1989 for pb
in ob
.pose
.bones
:
1990 pb
.bone
.select
= False
1991 for cns
in pb
.constraints
:
1992 if cns
.type == 'CHILD_OF':
1993 cnslist
.append((pb
, cns
, cns
.influence
))
1996 for (pb
, cns
, inf
) in cnslist
:
1997 amt
.bones
.active
= pb
.bone
1999 #print("Childof %s %s %s %.2f" % (amt.name, pb.name, cns.name, inf))
2000 bpy
.ops
.constraint
.childof_clear_inverse(constraint
=cns
.name
, owner
='BONE')
2001 bpy
.ops
.constraint
.childof_set_inverse(constraint
=cns
.name
, owner
='BONE')
2004 for (pb
, cns
, inf
) in cnslist
:
2013 def postProcess(args
):
2015 print("Postprocess %s" % human
)
2017 ob
= loadedData
['Object'][human
]
2020 if toggle
& T_Diamond
== 0 and ob
:
2025 # deleteDiamonds(ob)
2026 # Delete joint diamonds in main mesh
2027 # Invisio = material # 1
2030 def deleteDiamonds(ob
):
2031 bpy
.context
.scene
.objects
.active
= ob
2032 if not bpy
.context
.object:
2034 print("Delete helper geometry in %s" % bpy
.context
.object)
2035 bpy
.ops
.object.mode_set(mode
='EDIT')
2036 bpy
.ops
.mesh
.select_all(action
='DESELECT')
2037 bpy
.ops
.object.mode_set(mode
='OBJECT')
2040 for mn
,mat
in enumerate(me
.materials
):
2041 if "Invis" in mat
.name
:
2045 print("WARNING: Nu Invisio material found. Cannot delete helper geometry")
2047 for f
in me
.polygons
:
2048 if f
.material_index
>= invisioNum
:
2049 for vn
in f
.vertices
:
2050 me
.vertices
[vn
].select
= True
2053 if f
.material_index
>= invisioNum
:
2054 for vn
in f
.vertices
:
2055 me
.vertices
[vn
].select
= True
2056 if BMeshAware
and toggle
&T_CrashSafe
:
2057 theMessage
= "\n *** WARNING ***\nHelper deletion turned off due to Blender crash.\nHelpers can be deleted by deleting all selected vertices in Edit mode\n **********\n"
2060 bpy
.ops
.object.mode_set(mode
='EDIT')
2062 bpy
.ops
.mesh
.delete(type='VERT')
2063 print("Verts deleted")
2064 bpy
.ops
.object.mode_set(mode
='OBJECT')
2065 print("Back to object mode")
2069 # defaultKey(ext, args, tokens, var, exclude, glbals, lcals):
2074 def propNames(string
):
2076 #string = string.encode('utf-8', 'strict')
2078 # Alpha 7 compatibility
2079 if string
[0:2] == "&_":
2080 string
= "Mhf"+string
[2:]
2082 elif string
[0] == "&":
2083 string
= "Mha"+string
[1:]
2085 elif string
[0] == "*":
2086 string
= "Mhs"+string
[1:]
2088 elif len(string
) > 4 and string
[0:4] == "Hide":
2089 string
= "Mhh"+string
[4:]
2092 if string
[0] == "_":
2094 elif (len(string
) > 3 and
2095 string
[0:3] in ["Mha", "Mhf", "Mhs", "Mhh", "Mhv", "Mhc"]):
2096 name
= string
.replace("-","_")
2097 return name
, '["%s"]' % name
2099 return string
, '["%s"]' % string
2102 def defProp(args
, var
, glbals
, lcals
):
2104 name
= propNames(args
[1])[0]
2106 rest
= 'description="%s"' % args
[3].replace("_", " ")
2108 rest
+= ", " + args
[4]
2111 #expr = 'bpy.types.Object.%s = %sProperty(%s)' % (name, proptype, rest)
2112 expr
= '%s["%s"] = %s' % (var
, name
, value
)
2113 exec(expr
, glbals
, lcals
)
2116 def defNewProp(name
, proptype
, rest
):
2117 expr
= 'bpy.types.Object.%s = %sProperty(%s)' % (name
, proptype
, rest
)
2122 def setProperty(args
, var
, glbals
, lcals
):
2125 name
= propNames(args
[0])[0]
2128 expr
= '%s["%s"] = %s' % (var
, name
, value
)
2129 exec(expr
, glbals
, lcals
)
2132 tip
= 'description="%s"' % args
[2].replace("_", " ")
2133 if value
in ["True", "False"]:
2135 elif value
[0] in ["'",'"']:
2141 theProperty
= (name
, tip
, proptype
)
2144 def defineProperty(args
):
2146 if theProperty
is None:
2148 (name
, tip
, proptype
) = theProperty
2149 if len(args
) >= 2 and proptype
!= "Bool":
2150 if "BOOLEAN" in args
[1]:
2153 tip
= tip
+ "," + args
[1].replace(":", "=").replace('"', " ")
2154 expr
= "bpy.types.Object.%s = %sProperty(%s)" % (name
, proptype
, tip
)
2158 def defaultKey(ext
, args
, tokens
, var
, exclude
, glbals
, lcals
):
2161 if ext
== 'Property':
2162 return setProperty(args
, var
, glbals
, lcals
)
2163 elif ext
== 'PropKeys':
2164 return defineProperty(args
)
2165 elif ext
== 'DefProp':
2166 return defProp(args
, var
, glbals
, lcals
)
2169 expr
= "bpy.ops.%s" % args
[0]
2174 nvar
= "%s.%s" % (var
, ext
)
2181 MyError("Key length 0: %s" % ext
)
2184 if rnaType
== 'Add':
2185 print("*** Cannot Add yet ***")
2188 elif rnaType
== 'Refer':
2191 data
= "loadedData['%s']['%s']" % (typ
, name
)
2193 elif rnaType
== 'Struct' or rnaType
== 'Define':
2197 data
= eval(nvar
, glbals
, lcals
)
2200 # print("Old structrna", nvar, data)
2207 # print("Creator", creator, eval(var,glbals,lcals))
2210 rna
= eval(var
,glbals
,lcals
)
2211 data
= eval(creator
)
2214 # print("New struct", nvar, typ, data)
2216 if rnaType
== 'Define':
2217 loadedData
[typ
][name
] = data
2220 for (key
, val
, sub
) in tokens
:
2221 defaultKey(key
, val
, sub
, "data", [], globals(), locals())
2223 print("Struct done", nvar
)
2226 elif rnaType
== 'PropertyRNA':
2227 MyError("PropertyRNA!")
2228 #print("PropertyRNA ", ext, var)
2229 for (key
, val
, sub
) in tokens
:
2230 defaultKey(ext
, val
, sub
, nvar
, [], glbals
, lcals
)
2233 elif rnaType
== 'Array':
2234 for n
in range(1, len(args
)):
2235 expr
= "%s[%d] = %s" % (nvar
, n
-1, args
[n
])
2236 exec(expr
, glbals
, lcals
)
2238 expr
= "%s[0] = %s" % (nvar
, args
[1])
2239 exec(expr
, glbals
, lcals
)
2242 elif rnaType
== 'List':
2244 for (key
, val
, sub
) in tokens
:
2245 elt
= eval(val
[1], glbals
, lcals
)
2248 elif rnaType
== 'Matrix':
2252 for (key
, val
, sub
) in tokens
:
2255 expr
= "%s[%d][%d] = %g" % (nvar
, i
, j
, float(val
[j
]))
2256 exec(expr
, glbals
, lcals
)
2262 data
= loadedData
[rnaType
][args
[1]]
2263 #print("From loaded", rnaType, args[1], data)
2268 #print(var, ext, data)
2269 expr
= "%s = %s" % (nvar
, data
)
2271 exec(expr
, glbals
, lcals
)
2273 pushOnTodoList(var
, expr
, glbals
, lcals
)
2280 def pushOnTodoList(var
, expr
, glbals
, lcals
):
2283 print(dir(eval(var
, glbals
, lcals
)))
2285 "Unrecognized expression %s.\n" % expr
+
2286 "This can mean that Blender's python API has changed\n" +
2287 "since the MHX file was exported. Try to export again\n" +
2288 "from an up-to-date MakeHuman nightly build.\n" +
2289 "Alternatively, your Blender version may be obsolete.\n" +
2290 "Download an up-to-date version from www.graphicall.org")
2291 todo
.append((expr
, glbals
, lcals
))
2296 # parseBoolArray(mask):
2299 def parseBoolArray(mask
):
2308 # parseMatrix(args, tokens)
2311 def parseMatrix(args
, tokens
):
2312 matrix
= mathutils
.Matrix()
2314 for (key
, val
, sub
) in tokens
:
2316 matrix
[i
][0] = float(val
[0])
2317 matrix
[i
][1] = float(val
[1])
2318 matrix
[i
][2] = float(val
[2])
2319 matrix
[i
][3] = float(val
[3])
2324 # parseDefault(data, tokens, subkeys, exclude):
2327 def parseDefault(data
, tokens
, subkeys
, exclude
):
2328 for (key
, val
, sub
) in tokens
:
2329 if key
in subkeys
.keys():
2330 for (key2
, val2
, sub2
) in sub
:
2331 defaultKey(key2
, val2
, sub2
, "data.%s" % subkeys
[key
], [], globals(), locals())
2333 defaultKey(key
, val
, sub
, "data", exclude
, globals(), locals())
2335 def parseCollection(data
, tokens
, exclude
):
2344 # extractBpyType(data):
2347 def extractBpyType(data):
2348 typeSplit = str(type(data)).split("'")
2349 if typeSplit[0] != '<class ':
2351 classSplit = typeSplit[1].split(".")
2352 if classSplit[0] == 'bpy' and classSplit[1] == 'types':
2353 return classSplit[2]
2354 elif classSplit[0] == 'bpy_types':
2355 return classSplit[1]
2364 if string == 'True':
2366 elif string == 'False':
2369 MyError("Bool %s?" % string)
2372 # invalid(condition):
2375 def invalid(condition
):
2376 global rigLeg
, rigArm
, toggle
2377 res
= eval(condition
, globals())
2379 res
= eval(condition
, globals())
2380 #print("%s = %s" % (condition, res))
2383 #print("%s invalid!" % condition)
2389 # clearScene(context):
2394 scn
= bpy
.context
.scene
2395 for n
in range(len(scn
.layers
)):
2396 scn
.layers
[n
] = True
2398 print("clearScene %s %s" % (toggle
& T_Replace
, scn
))
2399 if not toggle
& T_Replace
:
2402 for ob
in scn
.objects
:
2403 if ob
.type in ['MESH', 'ARMATURE', 'EMPTY', 'CURVE', 'LATTICE']:
2404 scn
.objects
.active
= ob
2405 ob
.name
= "#" + ob
.name
2407 bpy
.ops
.object.mode_set(mode
='OBJECT')
2410 scn
.objects
.unlink(ob
)
2413 for grp
in bpy
.data
.groups
:
2414 grp
.name
= "#" + grp
.name
2420 # args = sceneLayers sceneHideLayers boneLayers boneHideLayers or nothing
2423 def hideLayers(args
):
2425 sceneLayers
= int(args
[2], 16)
2426 sceneHideLayers
= int(args
[3], 16)
2427 boneLayers
= int(args
[4], 16)
2428 # boneHideLayers = int(args[5], 16)
2431 sceneLayers
= 0x00ff
2436 scn
= bpy
.context
.scene
2440 scn
.layers
[n
] = True if sceneLayers
& mask
else False
2441 if sceneHideLayers
& mask
:
2442 hidelayers
.append(n
)
2445 for ob
in scn
.objects
:
2446 for n
in hidelayers
:
2449 ob
.hide_render
= True
2454 ob
= loadedData
['Object'][human
]
2461 ob
.data
.layers
[n
] = True if boneLayers
& mask
else False
2462 if boneHideLayers
& mask
:
2463 hidelayers
.append(n
)
2466 for b
in ob
.data
.bones
:
2467 for n
in hidelayers
:
2479 ConfigFile
= '~/mhx_import.cfg'
2483 global toggle
, toggleSettings
, theScale
2484 path
= os
.path
.realpath(os
.path
.expanduser(ConfigFile
))
2486 fp
= open(path
, 'rU')
2487 print('Storing defaults')
2489 print('Cannot open "%s" for reading' % path
)
2493 words
= line
.split()
2496 toggle
= int(words
[0],16)
2497 theScale
= float(words
[1])
2499 print('Configuration file "%s" is corrupt' % path
)
2501 toggleSettings
= toggle
2504 def writeDefaults():
2505 global toggleSettings
, theScale
2506 path
= os
.path
.realpath(os
.path
.expanduser(ConfigFile
))
2508 fp
= open(path
, 'w')
2509 print('Storing defaults')
2511 print('Cannot open "%s" for writing' % path
)
2513 fp
.write("%x %f Graphicall" % (toggleSettings
, theScale
))
2517 ###################################################################################
2519 # Postprocessing of rigify rig
2521 # rigifyMhx(context, name):
2523 ###################################################################################
2525 def rigifyMhx(context
, name
):
2526 print("Modifying MHX rig to Rigify")
2528 mhx
= loadedData
['Object'][name
]
2529 mhx
.MhxRigify
= True
2530 bpy
.context
.scene
.objects
.active
= mhx
2532 # Delete old widgets
2534 for ob in scn.objects:
2535 if ob.type == 'MESH' and ob.name[0:3] == "WGT":
2536 scn.objects.unlink(ob)
2539 # Save mhx bone locations
2545 bpy
.ops
.object.mode_set(mode
='EDIT')
2548 'head' : 'DEF-head',
2549 'ribs' : 'DEF-ribs',
2550 'upper_arm.L' : 'DEF-upper_arm.L.02',
2551 'thigh.L' : 'DEF-thigh.L.02',
2552 'upper_arm.R' : 'DEF-upper_arm.R.02',
2553 'thigh.R' : 'DEF-thigh.R.02',
2556 for eb
in mhx
.data
.edit_bones
:
2557 heads
[eb
.name
] = eb
.head
.copy()
2558 tails
[eb
.name
] = eb
.tail
.copy()
2559 rolls
[eb
.name
] = eb
.roll
2561 par
= eb
.parent
.name
2562 # print(eb.name, par)
2564 parents
[eb
.name
] = newParents
[par
]
2566 parents
[eb
.name
] = par
2568 parents
[eb
.name
] = None
2569 extras
[eb
.name
] = not eb
.layers
[16]
2570 bpy
.ops
.object.mode_set(mode
='OBJECT')
2572 # Find corresponding meshes. Can be several (clothes etc.)
2574 for ob
in scn
.objects
:
2575 for mod
in ob
.modifiers
:
2576 if (mod
.type == 'ARMATURE' and mod
.object == mhx
):
2577 meshes
.append((ob
, mod
))
2579 MyError("Did not find matching mesh")
2581 # Rename Head vertex group
2582 for (mesh
, mod
) in meshes
:
2584 vg
= mesh
.vertex_groups
['DfmHead']
2585 vg
.name
= 'DEF-head'
2589 # Change meta bone locations
2590 scn
.objects
.active
= None
2592 bpy
.ops
.object.armature_human_advanced_add()
2597 MyError("Unable to create advanced human. \n" \
2598 "Make sure that the Rigify addon is enabled. \n" \
2599 "It is found under Rigging.")
2602 meta
= context
.object
2603 bpy
.ops
.object.mode_set(mode
='EDIT')
2604 for eb
in meta
.data
.edit_bones
:
2605 eb
.head
= heads
[eb
.name
]
2606 eb
.tail
= tails
[eb
.name
]
2607 eb
.roll
= rolls
[eb
.name
]
2608 extras
[eb
.name
] = False
2611 ('UP-thumb.L', 'thumb.01.L', 'thumb.03.L', ['thumb.02.L']),
2612 ('UP-index.L', 'finger_index.01.L', 'finger_index.03.L', ['finger_index.02.L']),
2613 ('UP-middle.L', 'finger_middle.01.L', 'finger_middle.03.L', ['finger_middle.02.L']),
2614 ('UP-ring.L', 'finger_ring.01.L', 'finger_ring.03.L', ['finger_ring.02.L']),
2615 ('UP-pinky.L', 'finger_pinky.01.L', 'finger_pinky.03.L', ['finger_pinky.02.L']),
2616 ('UP-thumb.R', 'thumb.01.R', 'thumb.03.R', ['thumb.02.R']),
2617 ('UP-index.R', 'finger_index.01.R', 'finger_index.03.R', ['finger_index.02.R']),
2618 ('UP-middle.R', 'finger_middle.01.R', 'finger_middle.03.R', ['finger_middle.02.R']),
2619 ('UP-ring.R', 'finger_ring.01.R', 'finger_ring.03.R', ['finger_ring.02.R']),
2620 ('UP-pinky.R', 'finger_pinky.01.R', 'finger_pinky.03.R', ['finger_pinky.02.R']),
2623 for (upbone
, first
, last
, middles
) in fingerPlanes
:
2624 extras
[upbone
] = False
2625 #lineateChain(upbone, first, last, middles, 0.01, meta, heads, tails)
2628 ('UP-leg.L', 'thigh.L', 'shin.L'),
2629 ('UP-arm.L', 'upper_arm.L', 'forearm.L'),
2630 ('UP-leg.R', 'thigh.R', 'shin.R'),
2631 ('UP-arm.R', 'upper_arm.R', 'forearm.R'),
2634 for (upbone
, first
, last
) in ikPlanes
:
2635 extras
[upbone
] = False
2636 lineateChain(upbone
, first
, last
, [], 0.1, meta
, heads
, tails
)
2638 bpy
.ops
.object.mode_set(mode
='OBJECT')
2640 # Generate rigify rig
2641 bpy
.ops
.pose
.rigify_generate()
2642 scn
.objects
.unlink(meta
)
2643 rigify
= context
.object
2644 rigify
.name
= name
+"Rig"
2647 rigify
.layers
= layers
2648 rigify
.show_x_ray
= True
2649 for (mesh
, mod
) in meshes
:
2652 grp
= loadedData
['Group'][name
]
2653 grp
.objects
.link(rigify
)
2655 # Parent widgets under empty
2656 empty
= bpy
.data
.objects
.new("Widgets", None)
2657 scn
.objects
.link(empty
)
2658 empty
.layers
= 20*[False]
2659 empty
.layers
[19] = True
2660 empty
.parent
= rigify
2661 for ob
in scn
.objects
:
2662 if ob
.type == 'MESH' and ob
.name
[0:4] == "WGT-" and not ob
.parent
:
2664 grp
.objects
.link(ob
)
2665 elif ob
.parent
== mhx
:
2668 # Copy extra bones to rigify rig
2669 bpy
.ops
.object.mode_set(mode
='EDIT')
2670 for name
in heads
.keys():
2672 eb
= rigify
.data
.edit_bones
.new(name
)
2673 eb
.head
= heads
[name
]
2674 eb
.tail
= tails
[name
]
2675 eb
.roll
= rolls
[name
]
2676 for name
in heads
.keys():
2677 if extras
[name
] and parents
[name
]:
2678 eb
= rigify
.data
.edit_bones
[name
]
2679 eb
.parent
= rigify
.data
.edit_bones
[parents
[name
]]
2681 # Copy constraints etc.
2682 bpy
.ops
.object.mode_set(mode
='POSE')
2683 for name
in heads
.keys():
2685 pb1
= mhx
.pose
.bones
[name
]
2686 pb2
= rigify
.pose
.bones
[name
]
2687 pb2
.custom_shape
= pb1
.custom_shape
2688 pb2
.lock_location
= pb1
.lock_location
2689 pb2
.lock_rotation
= pb1
.lock_rotation
2690 pb2
.lock_scale
= pb1
.lock_scale
2693 b2
.use_deform
= b1
.use_deform
2694 b2
.hide_select
= b1
.hide_select
2695 b2
.show_wire
= b1
.show_wire
2704 for cns1
in pb1
.constraints
:
2705 cns2
= copyConstraint(cns1
, pb1
, pb2
, mhx
, rigify
)
2706 if cns2
.type == 'CHILD_OF':
2707 rigify
.data
.bones
.active
= pb2
.bone
2708 bpy
.ops
.constraint
.childof_set_inverse(constraint
=cns2
.name
, owner
='BONE')
2710 # Create animation data
2711 if mhx
.animation_data
:
2712 for fcu
in mhx
.animation_data
.drivers
:
2713 rigify
.animation_data
.drivers
.from_existing(src_driver
=fcu
)
2715 fixDrivers(rigify
.animation_data
, mhx
, rigify
)
2716 for (mesh
, mod
) in meshes
:
2717 mesh
.parent
= rigify
2718 skeys
= mesh
.data
.shape_keys
2720 fixDrivers(skeys
.animation_data
, mhx
, rigify
)
2722 scn
.objects
.unlink(mhx
)
2723 print("Rigify rig complete")
2727 # lineateChain(upbone, first, last, middles, minDist, rig, heads, tails):
2728 # lineate(pt, start, minDist, normal, offVector):
2731 def lineateChain(upbone
, first
, last
, middles
, minDist
, rig
, heads
, tails
):
2732 fb
= rig
.data
.edit_bones
[first
]
2733 lb
= rig
.data
.edit_bones
[last
]
2734 uhead
= heads
[upbone
]
2735 utail
= tails
[upbone
]
2736 tang
= lb
.tail
- fb
.head
2737 tangent
= tang
/tang
.length
2738 up
= (uhead
+utail
)/2 - fb
.head
2739 norm
= up
- tangent
*tangent
.dot(up
)
2740 normal
= norm
/norm
.length
2741 offVector
= tangent
.cross(normal
)
2743 fb
.tail
= lineate(fb
.tail
, fb
.head
, minDist
, normal
, offVector
)
2744 lb
.head
= lineate(lb
.head
, fb
.head
, minDist
, normal
, offVector
)
2745 for bone
in middles
:
2746 mb
= rig
.data
.edit_bones
[bone
]
2747 mb
.head
= lineate(mb
.head
, fb
.head
, minDist
, normal
, offVector
)
2748 mb
.tail
= lineate(mb
.tail
, fb
.head
, minDist
, normal
, offVector
)
2751 def lineate(pt
, start
, minDist
, normal
, offVector
):
2753 diff
= diff
- offVector
*offVector
.dot(diff
)
2754 dist
= diff
.dot(normal
)
2756 diff
+= (minDist
- dist
)*normal
2760 # fixDrivers(adata, mhx, rigify):
2763 def fixDrivers(adata
, mhx
, rigify
):
2766 for fcu
in adata
.drivers
:
2767 for var
in fcu
.driver
.variables
:
2768 for targ
in var
.targets
:
2774 # copyConstraint(cns1, pb1, pb2, mhx, rigify):
2777 def copyConstraint(cns1
, pb1
, pb2
, mhx
, rigify
):
2779 'Head' : 'DEF-head',
2780 'MasterFloor' : 'root',
2781 'upper_arm.L' : 'DEF-upper_arm.L.01',
2782 'upper_arm.R' : 'DEF-upper_arm.R.01',
2783 'thigh.L' : 'DEF-thigh.L.01',
2784 'thigh.R' : 'DEF-thigh.R.01',
2785 'shin.L' : 'DEF-shin.L.01',
2786 'shin.R' : 'DEF-shin.R.01'
2789 cns2
= pb2
.constraints
.new(cns1
.type)
2790 for prop
in dir(cns1
):
2791 if prop
== 'target':
2792 if cns1
.target
== mhx
:
2793 cns2
.target
= rigify
2795 cns2
.target
= cns1
.target
2796 elif prop
== 'subtarget':
2798 cns2
.subtarget
= substitute
[cns1
.subtarget
]
2800 cns2
.subtarget
= cns1
.subtarget
2801 elif prop
[0] != '_':
2803 expr
= "cns2.%s = cns1.%s" % (prop
, prop
)
2804 #print(pb1.name, expr)
2811 # class OBJECT_OT_RigifyMhxButton(bpy.types.Operator):
2814 class OBJECT_OT_RigifyMhxButton(bpy
.types
.Operator
):
2815 bl_idname
= "mhxrig.rigify_mhx"
2816 bl_label
= "Rigify MHX rig"
2817 bl_options
= {'UNDO'}
2819 def execute(self
, context
):
2820 rigifyMhx(context
, context
.object.name
)
2824 # class RigifyMhxPanel(bpy.types.Panel):
2827 class RigifyMhxPanel(bpy
.types
.Panel
):
2828 bl_label
= "Rigify MHX"
2829 bl_space_type
= "VIEW_3D"
2830 bl_region_type
= "UI"
2833 def poll(cls
, context
):
2835 return context
.object.MhxRigify
2838 def draw(self
, context
):
2839 self
.layout
.operator("mhxrig.rigify_mhx")
2842 ###################################################################################
2846 ###################################################################################
2849 from bpy
.props
import StringProperty
, FloatProperty
, EnumProperty
, BoolProperty
2851 class ErrorOperator(bpy
.types
.Operator
):
2852 bl_idname
= "mhx.error"
2853 bl_label
= "Error when loading MHX file"
2855 def execute(self
, context
):
2856 return {'RUNNING_MODAL'}
2858 def invoke(self
, context
, event
):
2859 global theErrorLines
2861 for line
in theErrorLines
:
2862 if len(line
) > maxlen
:
2865 height
= 20+5*len(theErrorLines
)
2866 #self.report({'INFO'}, theMessage)
2867 wm
= context
.window_manager
2868 return wm
.invoke_props_dialog(self
, width
=width
, height
=height
)
2870 def draw(self
, context
):
2871 global theErrorLines
2872 for line
in theErrorLines
:
2873 self
.layout
.label(line
)
2875 def MyError(message
):
2876 global theMessage
, theErrorLines
, theErrorStatus
2877 theMessage
= message
2878 theErrorLines
= message
.split('\n')
2879 theErrorStatus
= True
2880 bpy
.ops
.mhx
.error('INVOKE_DEFAULT')
2881 raise MhxError(theMessage
)
2883 class MhxError(Exception):
2884 def __init__(self
, value
):
2887 return repr(self
.value
)
2889 class SuccessOperator(bpy
.types
.Operator
):
2890 bl_idname
= "mhx.success"
2891 bl_label
= "MHX file successfully loaded:"
2892 message
= StringProperty()
2894 def execute(self
, context
):
2895 return {'RUNNING_MODAL'}
2897 def invoke(self
, context
, event
):
2898 wm
= context
.window_manager
2899 return wm
.invoke_props_dialog(self
)
2901 def draw(self
, context
):
2902 self
.layout
.label(self
.message
+ theMessage
)
2904 ###################################################################################
2908 ###################################################################################
2910 from bpy_extras
.io_utils
import ImportHelper
2913 ("enforce", "Enforce version", "Only accept MHX files of correct version", T_EnforceVersion
),
2914 #("crash_safe", "Crash-safe", "Disable features that have caused Blender crashes", T_CrashSafe),
2915 ("mesh", "Mesh", "Use main mesh", T_Mesh
),
2916 ("proxy", "Proxies", "Use proxies", T_Proxy
),
2917 #("armature", "Armature", "Use armature", T_Armature),
2918 #("replace", "Replace scene", "Replace scene", T_Replace),
2919 ("cage", "Cage", "Load mesh deform cage", T_Cage
),
2920 ("clothes", "Clothes", "Include clothes", T_Clothes
),
2921 ("shapekeys", "Shapekeys", "Include shapekeys", T_Shapekeys
),
2922 ("shapedrivers", "Shapekey drivers", "Include shapekey drivers", T_ShapeDrivers
),
2923 #("symm", "Symmetric shapes", "Keep shapekeys symmetric", T_Symm),
2924 ("diamond", "Helper geometry", "Keep helper geometry", T_Diamond
),
2925 ("rigify", "Rigify", "Create rigify control rig", T_Rigify
),
2928 class ImportMhx(bpy
.types
.Operator
, ImportHelper
):
2929 """Import from MHX file format (.mhx)"""
2930 bl_idname
= "import_scene.makehuman_mhx"
2931 bl_description
= 'Import from MHX file format (.mhx)'
2932 bl_label
= "Import MHX"
2933 bl_space_type
= "PROPERTIES"
2934 bl_region_type
= "WINDOW"
2935 bl_options
= {'UNDO'}
2937 filename_ext
= ".mhx"
2938 filter_glob
= StringProperty(default
="*.mhx", options
={'HIDDEN'})
2939 filepath
= StringProperty(subtype
='FILE_PATH')
2941 scale
= FloatProperty(name
="Scale", description
="Default meter, decimeter = 1.0", default
= theScale
)
2942 advanced
= BoolProperty(name
="Advanced settings", description
="Use advanced import settings", default
=False)
2943 for (prop
, name
, desc
, flag
) in MhxBoolProps
:
2944 expr
= '%s = BoolProperty(name="%s", description="%s", default=(toggleSettings&%s != 0))' % (prop
, name
, desc
, flag
)
2948 def draw(self
, context
):
2949 layout
= self
.layout
2950 layout
.prop(self
, "scale")
2951 layout
.prop(self
, "advanced")
2953 for (prop
, name
, desc
, flag
) in MhxBoolProps
:
2954 layout
.prop(self
, prop
)
2957 def execute(self
, context
):
2958 global toggle
, toggleSettings
, theScale
, MhxBoolProps
2959 if not self
.advanced
:
2960 toggle
= DefaultToggle
2963 for (prop
, name
, desc
, flag
) in MhxBoolProps
:
2964 expr
= '(%s if self.%s else 0)' % (flag
, prop
)
2965 toggle |
= eval(expr
)
2966 toggleSettings
= toggle
2967 print("execute flags %x" % toggle
)
2968 theScale
= self
.scale
2970 #filepathname = self.filepath.encode('utf-8', 'strict')
2972 readMhxFile(self
.filepath
)
2973 bpy
.ops
.mhx
.success('INVOKE_DEFAULT', message
= self
.filepath
)
2975 print("Error when loading MHX file %s:\n" % self
.filepath
+ theMessage
)
2979 self
.advanced
= False
2983 def invoke(self
, context
, event
):
2984 global toggle
, theScale
, MhxBoolProps
2986 self
.scale
= theScale
2987 for (prop
, name
, desc
, flag
) in MhxBoolProps
:
2988 expr
= 'self.%s = (toggle&%s != 0)' % (prop
, flag
)
2990 context
.window_manager
.fileselect_add(self
)
2991 return {'RUNNING_MODAL'}
2994 ###################################################################################
2998 ###################################################################################
3004 stopStaringVisemes = ({
3007 ('PUpLip', (0,-0.1)),
3008 ('PLoLip', (0,0.1)),
3010 ('PTongue', (0,0.0))],
3013 ('PUpLip', (0,-0.1)),
3014 ('PLoLip', (0,0.1)),
3016 ('PTongue', (0,0.0))],
3017 'MBP' : [('PMouth', (-0.3,0)),
3021 ('PTongue', (0,0.0))],
3022 'OO' : [('PMouth', (-1.5,0)),
3026 ('PTongue', (0,0.0))],
3027 'O' : [('PMouth', (-1.1,0)),
3031 ('PTongue', (0,0.0))],
3032 'R' : [('PMouth', (-0.9,0)),
3033 ('PUpLip', (0,-0.2)),
3034 ('PLoLip', (0,0.2)),
3036 ('PTongue', (0,0.0))],
3037 'FV' : [('PMouth', (0,0)),
3039 ('PLoLip', (0,-0.8)),
3041 ('PTongue', (0,0.0))],
3042 'S' : [('PMouth', (0,0)),
3043 ('PUpLip', (0,-0.2)),
3044 ('PLoLip', (0,0.2)),
3046 ('PTongue', (0,0.0))],
3047 'SH' : [('PMouth', (-0.6,0)),
3048 ('PUpLip', (0,-0.5)),
3049 ('PLoLip', (0,0.5)),
3051 ('PTongue', (0,0.0))],
3052 'EE' : [('PMouth', (0.3,0)),
3053 ('PUpLip', (0,-0.3)),
3054 ('PLoLip', (0,0.3)),
3055 ('PJaw', (0,0.025)),
3056 ('PTongue', (0,0.0))],
3057 'AH' : [('PMouth', (-0.1,0)),
3058 ('PUpLip', (0,-0.4)),
3061 ('PTongue', (0,0.0))],
3062 'EH' : [('PMouth', (0.1,0)),
3063 ('PUpLip', (0,-0.2)),
3064 ('PLoLip', (0,0.2)),
3066 ('PTongue', (0,0.0))],
3067 'TH' : [('PMouth', (0,0)),
3068 ('PUpLip', (0,-0.5)),
3069 ('PLoLip', (0,0.5)),
3070 ('PJaw', (-0.2,0.1)),
3071 ('PTongue', (0,-0.6))],
3072 'L' : [('PMouth', (0,0)),
3073 ('PUpLip', (0,-0.2)),
3074 ('PLoLip', (0,0.2)),
3075 ('PJaw', (0.2,0.2)),
3076 ('PTongue', (0,-0.8))],
3077 'G' : [('PMouth', (0,0)),
3078 ('PUpLip', (0,-0.1)),
3079 ('PLoLip', (0,0.1)),
3080 ('PJaw', (-0.3,0.1)),
3081 ('PTongue', (0,-0.6))],
3083 'Blink' : [('PUpLid', (0,1.0)), ('PLoLid', (0,-1.0))],
3084 'Unblink' : [('PUpLid', (0,0)), ('PLoLid', (0,0))],
3087 bodyLanguageVisemes = ({
3089 ('MouthWidth_L', 0),
3090 ('MouthWidth_R', 0),
3091 ('MouthNarrow_L', 0),
3092 ('MouthNarrow_R', 0),
3094 ('UpLipsMidHeight', 0),
3095 ('LoLipsMidHeight', 0),
3098 ('TongueBackHeight', 0),
3099 ('TongueHeight', 0),
3102 ('MouthWidth_L', 0),
3103 ('MouthWidth_R', 0),
3104 ('MouthNarrow_L', 0),
3105 ('MouthNarrow_R', 0),
3107 ('UpLipsMidHeight', 0),
3108 ('LoLipsMidHeight', 0),
3111 ('TongueBackHeight', 0),
3112 ('TongueHeight', 0),
3115 ('MouthWidth_L', 0),
3116 ('MouthWidth_R', 0),
3117 ('MouthNarrow_L', 0),
3118 ('MouthNarrow_R', 0),
3120 ('UpLipsMidHeight', 0),
3121 ('LoLipsMidHeight', 0),
3124 ('TongueBackHeight', 0),
3125 ('TongueHeight', 0),
3128 ('MouthWidth_L', 0),
3129 ('MouthWidth_R', 0),
3130 ('MouthNarrow_L', 1.0),
3131 ('MouthNarrow_R', 1.0),
3133 ('UpLipsMidHeight', 0),
3134 ('LoLipsMidHeight', 0),
3137 ('TongueBackHeight', 0),
3138 ('TongueHeight', 0),
3141 ('MouthWidth_L', 0),
3142 ('MouthWidth_R', 0),
3143 ('MouthNarrow_L', 0.9),
3144 ('MouthNarrow_R', 0.9),
3146 ('UpLipsMidHeight', 0),
3147 ('LoLipsMidHeight', 0),
3150 ('TongueBackHeight', 0),
3151 ('TongueHeight', 0),
3154 ('MouthWidth_L', 0),
3155 ('MouthWidth_R', 0),
3156 ('MouthNarrow_L', 0.5),
3157 ('MouthNarrow_R', 0.5),
3159 ('UpLipsMidHeight', 0.2),
3160 ('LoLipsMidHeight', -0.2),
3163 ('TongueBackHeight', 0),
3164 ('TongueHeight', 0),
3167 ('MouthWidth_L', 0.2),
3168 ('MouthWidth_R', 0.2),
3169 ('MouthNarrow_L', 0),
3170 ('MouthNarrow_R', 0),
3172 ('UpLipsMidHeight', 0),
3173 ('LoLipsMidHeight', 0.3),
3176 ('TongueBackHeight', 0),
3177 ('TongueHeight', 0),
3180 ('MouthWidth_L', 0),
3181 ('MouthWidth_R', 0),
3182 ('MouthNarrow_L', 0),
3183 ('MouthNarrow_R', 0),
3185 ('UpLipsMidHeight', 0.5),
3186 ('LoLipsMidHeight', -0.7),
3189 ('TongueBackHeight', 0),
3190 ('TongueHeight', 0),
3193 ('MouthWidth_L', 0.8),
3194 ('MouthWidth_R', 0.8),
3195 ('MouthNarrow_L', 0),
3196 ('MouthNarrow_R', 0),
3198 ('UpLipsMidHeight', 1.0),
3199 ('LoLipsMidHeight', 0),
3202 ('TongueBackHeight', 0),
3203 ('TongueHeight', 0),
3206 ('MouthWidth_L', 0.2),
3207 ('MouthWidth_R', 0.2),
3208 ('MouthNarrow_L', 0),
3209 ('MouthNarrow_R', 0),
3211 ('UpLipsMidHeight', 0.6),
3212 ('LoLipsMidHeight', -0.6),
3215 ('TongueBackHeight', 0),
3216 ('TongueHeight', 0),
3219 ('MouthWidth_L', 0),
3220 ('MouthWidth_R', 0),
3221 ('MouthNarrow_L', 0),
3222 ('MouthNarrow_R', 0),
3224 ('UpLipsMidHeight', 0.4),
3225 ('LoLipsMidHeight', 0),
3228 ('TongueBackHeight', 0),
3229 ('TongueHeight', 0),
3232 ('MouthWidth_L', 0),
3233 ('MouthWidth_R', 0),
3234 ('MouthNarrow_L', 0),
3235 ('MouthNarrow_R', 0),
3237 ('UpLipsMidHeight', 0.5),
3238 ('LoLipsMidHeight', -0.6),
3240 ('MouthOpen', 0.25),
3241 ('TongueBackHeight', 0),
3242 ('TongueHeight', 0),
3245 ('MouthWidth_L', 0),
3246 ('MouthWidth_R', 0),
3247 ('MouthNarrow_L', 0),
3248 ('MouthNarrow_R', 0),
3250 ('UpLipsMidHeight', 0),
3251 ('LoLipsMidHeight', 0),
3254 ('TongueBackHeight', 1.0),
3255 ('TongueHeight', 1.0)
3258 ('MouthWidth_L', 0),
3259 ('MouthWidth_R', 0),
3260 ('MouthNarrow_L', 0),
3261 ('MouthNarrow_R', 0),
3263 ('UpLipsMidHeight', 0.5),
3264 ('LoLipsMidHeight', -0.5),
3266 ('MouthOpen', -0.2),
3267 ('TongueBackHeight', 1.0),
3268 ('TongueHeight', 1.0),
3271 ('MouthWidth_L', 0),
3272 ('MouthWidth_R', 0),
3273 ('MouthNarrow_L', 0),
3274 ('MouthNarrow_R', 0),
3276 ('UpLipsMidHeight', 0.5),
3277 ('LoLipsMidHeight', -0.5),
3279 ('MouthOpen', -0.2),
3280 ('TongueBackHeight', 1.0),
3281 ('TongueHeight', 0),
3299 VisemePanelBones = {
3300 'MouthOpen' : ('PJaw', (0,0.25)),
3301 'UpLipsMidHeight' : ('PUpLipMid', (0,-0.25)),
3302 'LoLipsMidHeight' : ('PLoLipMid', (0,-0.25)),
3303 'LoLipsIn': ('PLoLipMid', (-0.25,0)),
3304 'MouthWidth_L' : ('PMouth_L', (0.25,0)),
3305 'MouthWidth_R' : ('PMouth_R', (-0.25,0)),
3306 'MouthNarrow_L' : ('PMouth_L', (-0.25,0)),
3307 'MouthNarrow_R' : ('PMouth_R', (0.25,0)),
3308 'LipsPart' : ('PMouthMid', (0, -0.25)),
3309 'TongueBackHeight': ('PTongue', (-0.25, 0)),
3310 'TongueHeight' : ('PTongue', (0, -0.25)),
3312 'UpLidUp_L' : ('PUpLid_L', (0,1.0)),
3313 'UpLidUp_R' : ('PUpLid_R', (0,1.0)),
3314 'LoLidDown_L' : ('PLoLid_L', (0,-1.0)),
3315 'LoLidDown_R' : ('PLoLid_R', (0,-1.0)),
3319 ('Rest', 'Etc', 'AH'),
3327 # makeVisemes(ob, scn):
3328 # class VIEW3D_OT_MhxMakeVisemesButton(bpy.types.Operator):
3331 def makeVisemes(ob, scn):
3332 if ob.type != 'MESH':
3333 print("Active object %s is not a mesh" % ob)
3335 if not ob.data.shape_keys:
3336 print("%s has no shapekeys" % ob)
3339 ob.data.shape_keys.key_blocks["VIS_Rest"]
3340 print("Visemes already created")
3345 verts = ob.data.vertices
3346 for (vis,shapes) in bodyLanguageVisemes.items():
3347 if vis in ['Blink', 'Unblink']:
3349 vkey = ob.shape_key_add(name="VIS_%s" % vis)
3351 for n,v in enumerate(verts):
3352 vkey.data[n].co = v.co
3353 for (name,value) in shapes:
3354 if name[-2:] == "_R":
3356 skey = ob.data.shape_keys.key_blocks[name]
3358 for n,v in enumerate(verts):
3359 vkey.data[n].co += factor*(skey.data[n].co - v.co)
3360 print("Visemes made")
3363 class VIEW3D_OT_MhxMakeVisemesButton(bpy.types.Operator):
3364 bl_idname = "mhx.make_visemes"
3365 bl_label = "Generate viseme shapekeys"
3366 bl_options = {'UNDO'}
3368 def execute(self, context):
3369 makeVisemes(context.object, context.scene)
3377 MohoVisemes
= dict({
3390 MagpieVisemes
= dict({
3403 # setViseme(context, vis, setKey, frame):
3404 # setBoneLocation(context, pbone, loc, mirror, setKey, frame):
3405 # class VIEW3D_OT_MhxVisemeButton(bpy.types.Operator):
3408 def getVisemeSet(context, rig):
3410 visset = rig['MhxVisemeSet']
3412 return bodyLanguageVisemes
3413 if visset == 'StopStaring':
3414 return stopStaringVisemes
3415 elif visset == 'BodyLanguage':
3416 return bodyLanguageVisemes
3418 raise MhxError("Unknown viseme set %s" % visset)
3421 def setVisemeAlpha7(context, vis, visemes, setKey, frame):
3422 (rig, mesh) = getMhxRigMesh(context.object)
3427 if rig.MhxShapekeyDrivers:
3429 scale *= rig.pose.bones['PFace'].bone.length
3434 shapekeys = mesh.data.shape_keys.key_blocks
3436 for (skey, value) in visemes[vis]:
3438 (b, (x,z)) = VisemePanelBones[skey]
3439 loc = mathutils.Vector((float(x*value),0,float(z*value)))
3440 pb = rig.pose.bones[b]
3441 pb.location = loc*scale
3442 if setKey or context.tool_settings.use_keyframe_insert_auto:
3444 pb.keyframe_insert('location', index=n, frame=frame, group=pb.name)
3451 rig[skey] = value*scale
3452 if setKey or context.tool_settings.use_keyframe_insert_auto:
3453 rig.keyframe_insert('["%s"]' % skey, frame=frame, group="Visemes")
3456 shapekeys[skey].value = value*scale
3459 if setKey or context.tool_settings.use_keyframe_insert_auto:
3460 shapekeys[skey].keyframe_insert("value", frame=frame)
3465 class VIEW3D_OT_MhxVisemeButton(bpy.types.Operator):
3466 bl_idname = 'mhx.pose_viseme'
3468 bl_options = {'UNDO'}
3469 viseme = StringProperty()
3471 def invoke(self, context, event):
3472 (rig, mesh) = getMhxRigMesh(context.object)
3473 visemes = getVisemeSet(context, rig)
3474 setVisemeAlpha7(context, self.viseme, visemes, False, context.scene.frame_current)
3480 def readLipsync(context
, filepath
, offs
, struct
):
3481 (rig
, mesh
) = getMhxRigMesh(context
.object)
3483 props
= getProps(rig
, "Mhv")
3487 dummy
,units
= getUnitsFromString("x;"+rig
[prop
])
3488 visemes
[prop
] = units
3489 props
= getProps(rig
, "Mhsmouth")
3490 auto
= context
.tool_settings
.use_keyframe_insert_auto
3492 factor
= rig
.MhxStrength
3493 shapekeys
= getMhmShapekeys(rig
, mesh
)
3495 visemes
= getVisemeSet(context
, rig
)
3496 context
.scene
.objects
.active
= rig
3497 bpy
.ops
.object.mode_set(mode
='POSE')
3499 fp
= open(filepath
, "rU")
3505 vis
= "Mhv" + struct
[words
[1]]
3506 frame
= int(words
[0])+offs
3508 setMhmProps(rig
, shapekeys
, "Mhsmouth", visemes
[vis
], factor
, auto
, frame
)
3510 setVisemeAlpha7(context
, vis
, visemes
, True, frame
)
3513 #setInterpolation(rig)
3515 print("Lipsync file %s loaded" % filepath
)
3518 class VIEW3D_OT_MhxMohoButton(bpy
.types
.Operator
, ImportHelper
):
3519 bl_idname
= "mhx.pose_load_moho"
3520 bl_label
= "Load Moho (.dat)"
3521 bl_options
= {'UNDO'}
3523 filename_ext
= ".dat"
3524 filter_glob
= StringProperty(default
="*.dat", options
={'HIDDEN'})
3525 filepath
= StringProperty(subtype
='FILE_PATH')
3527 def execute(self
, context
):
3528 readLipsync(context
, self
.properties
.filepath
, context
.scene
.frame_start
- 1, MohoVisemes
)
3531 def invoke(self
, context
, event
):
3532 context
.window_manager
.fileselect_add(self
)
3533 return {'RUNNING_MODAL'}
3536 class MhxLipsyncPanel(bpy
.types
.Panel
):
3537 bl_label
= "MHX Lipsync"
3538 bl_space_type
= "VIEW_3D"
3539 bl_region_type
= "UI"
3540 bl_options
= {'DEFAULT_CLOSED'}
3543 def poll(cls
, context
):
3544 return pollMhx(context
.object)
3546 def draw(self
, context
):
3547 rig
,mesh
= getMhxRigMesh(context
.object)
3549 layout
.label("No MHX rig found")
3551 layout
= self
.layout
3554 visemes
= getProps(rig
, "Mhv")
3556 layout
.label("No visemes found")
3559 layout
.operator("mhx.pose_reset_expressions", text
="Reset visemes").prefix
="Mhsmouth"
3560 layout
.operator("mhx.pose_key_expressions", text
="Key visemes").prefix
="Mhsmouth"
3561 layout
.prop(rig
, "MhxStrength")
3564 for prop
in visemes
:
3568 row
.operator("mhx.pose_mhm", text
=prop
[3:]).data
="Mhsmouth;"+rig
[prop
]
3575 row
.operator("mhx.pose_mhm", text
="Blink").data
="Mhsmouth;eye_left_closure:1;eye_right_closure:1"
3576 row
.operator("mhx.pose_mhm", text
="Unblink").data
="Mhsmouth;eye_left_closure:0;eye_right_closure:0"
3578 layout
.label("Lipsync disabled for alpha7 mhx files")
3580 for (vis1
, vis2
, vis3
) in VisemeList
:
3582 row
.operator("mhx.pose_viseme", text
=vis1
).viseme
= vis1
3583 row
.operator("mhx.pose_viseme", text
=vis2
).viseme
= vis2
3584 row
.operator("mhx.pose_viseme", text
=vis3
).viseme
= vis3
3587 row
.operator("mhx.pose_viseme", text
="Blink").viseme
= 'Blink'
3588 row
.operator("mhx.pose_viseme", text
="Unblink").viseme
= 'Unblink'
3590 layout
.operator("mhx.make_visemes")
3594 row
.operator("mhx.pose_load_moho")
3595 #layout.operator("mhx.update")
3598 # updatePose(context):
3599 # class VIEW3D_OT_MhxUpdateButton(bpy.types.Operator):
3602 def updatePose(context
):
3604 scn
.frame_current
= scn
.frame_current
3605 bpy
.ops
.object.posemode_toggle()
3606 bpy
.ops
.object.posemode_toggle()
3609 class VIEW3D_OT_MhxUpdateButton(bpy
.types
.Operator
):
3610 bl_idname
= "mhx.update"
3613 def execute(self
, context
):
3618 ###################################################################################
3622 ###################################################################################
3624 class VIEW3D_OT_MhxResetExpressionsButton(bpy
.types
.Operator
):
3625 bl_idname
= "mhx.pose_reset_expressions"
3626 bl_label
= "Reset expressions"
3627 bl_options
= {'UNDO'}
3628 prefix
= StringProperty()
3630 def execute(self
, context
):
3631 rig
,mesh
= getMhxRigMesh(context
.object)
3632 shapekeys
= getMhmShapekeys(rig
, mesh
)
3633 clearMhmProps(rig
, shapekeys
, self
.prefix
, context
.tool_settings
.use_keyframe_insert_auto
, context
.scene
.frame_current
)
3638 class VIEW3D_OT_MhxKeyExpressionsButton(bpy
.types
.Operator
):
3639 bl_idname
= "mhx.pose_key_expressions"
3640 bl_label
= "Key expressions"
3641 bl_options
= {'UNDO'}
3642 prefix
= StringProperty()
3644 def execute(self
, context
):
3645 rig
,mesh
= getMhxRigMesh(context
.object)
3646 props
= getProps(rig
, self
.prefix
)
3647 frame
= context
.scene
.frame_current
3649 rig
.keyframe_insert(prop
, frame
=frame
)
3654 class VIEW3D_OT_MhxPinExpressionButton(bpy
.types
.Operator
):
3655 bl_idname
= "mhx.pose_pin_expression"
3657 bl_options
= {'UNDO'}
3658 data
= StringProperty()
3660 def execute(self
, context
):
3661 rig
,mesh
= getMhxRigMesh(context
.object)
3662 words
= self
.data
.split(";")
3664 expression
= words
[1]
3666 props
= getProps(rig
, prefix
)
3667 if context
.tool_settings
.use_keyframe_insert_auto
:
3668 frame
= context
.scene
.frame_current
3671 if prop
== expression
:
3675 if abs(rig
[prop
] - old
) > 1e-3:
3676 rig
.keyframe_insert(prop
, frame
=frame
)
3679 if prop
== expression
:
3687 def getMhmShapekeys(rig
, mesh
):
3688 if rig
.MhxShapekeyDrivers
:
3691 return mesh
.data
.shape_keys
.key_blocks
3694 def setMhmProps(rig
, shapekeys
, prefix
, units
, factor
, auto
, frame
):
3695 clearMhmProps(rig
, shapekeys
, prefix
, auto
, frame
)
3696 for (prop
, value
) in units
:
3698 skey
= prop
[3:].replace("_","-")
3699 shapekeys
[skey
].value
= factor
*value
3701 shapekeys
[skey
].keyframe_insert("value", frame
=frame
)
3703 rig
[prop
] = factor
*value
3705 rig
.keyframe_insert(prop
, frame
=frame
)
3708 def clearMhmProps(rig
, shapekeys
, prefix
, auto
, frame
):
3709 props
= getProps(rig
, prefix
)
3712 skey
= prop
[3:].replace("_","-")
3713 shapekeys
[skey
].value
= 0.0
3715 shapekeys
[skey
].keyframe_insert("value", frame
=frame
)
3719 rig
.keyframe_insert(prop
, frame
=frame
)
3722 def getUnitsFromString(string
):
3723 words
= string
.split(";")
3726 for word
in words
[1:]:
3729 unit
= word
.split(":")
3730 prop
= "Mhs" + unit
[0]
3731 value
= float(unit
[1])
3732 units
.append((prop
, value
))
3736 class VIEW3D_OT_MhxMhmButton(bpy
.types
.Operator
):
3737 bl_idname
= "mhx.pose_mhm"
3739 bl_options
= {'UNDO'}
3740 data
= StringProperty()
3742 def execute(self
, context
):
3743 rig
,mesh
= getMhxRigMesh(context
.object)
3744 auto
= context
.tool_settings
.use_keyframe_insert_auto
3745 frame
= context
.scene
.frame_current
3746 shapekeys
= getMhmShapekeys(rig
, mesh
)
3747 prefix
,units
= getUnitsFromString(self
.data
)
3748 setMhmProps(rig
, shapekeys
, prefix
, units
, rig
.MhxStrength
, auto
, frame
)
3753 def getProps(rig
, prefix
):
3755 for prop
in rig
.keys():
3756 if prop
.startswith(prefix
):
3762 class MhxExpressionsPanel(bpy
.types
.Panel
):
3763 bl_label
= "MHX Expressions"
3764 bl_space_type
= "VIEW_3D"
3765 bl_region_type
= "UI"
3766 bl_options
= {'DEFAULT_CLOSED'}
3769 def poll(cls
, context
):
3770 return pollMhx(context
.object)
3772 def draw(self
, context
):
3773 layout
= self
.layout
3774 rig
,mesh
= getMhxRigMesh(context
.object)
3776 layout
.label("No MHX rig found")
3778 exprs
= getProps(rig
, "Mhe")
3780 layout
.label("No expressions found")
3783 layout
.operator("mhx.pose_reset_expressions").prefix
="Mhs"
3784 layout
.operator("mhx.pose_key_expressions").prefix
="Mhs"
3785 layout
.prop(rig
, "MhxStrength")
3788 layout
.operator("mhx.pose_mhm", text
=prop
[3:]).data
="Mhs;"+rig
[prop
]
3791 def drawShapePanel(self
, context
, prefix
, name
):
3792 layout
= self
.layout
3793 rig
,mesh
= getMhxRigMesh(context
.object)
3795 print("No MHX rig found")
3797 if not rig
.MhxShapekeyDrivers
:
3798 layout
.label("No shapekey drivers.")
3799 layout
.label("Set %s values in mesh context instead" % name
)
3801 props
= getProps(rig
, prefix
)
3803 layout
.label("No %ss found" % name
)
3806 layout
.operator("mhx.pose_reset_expressions", text
="Reset %ss" % name
).prefix
=prefix
3807 layout
.operator("mhx.pose_key_expressions", text
="Reset %ss" % name
).prefix
=prefix
3808 #layout.operator("mhx.update")
3812 row
= layout
.split(0.85)
3813 row
.prop(rig
, '["%s"]' % prop
, text
=prop
[3:])
3814 row
.operator("mhx.pose_pin_expression", text
="", icon
='UNPINNED').data
= (prefix
+ ";" + prop
)
3818 class MhxExpressionUnitsPanel(bpy
.types
.Panel
):
3819 bl_label
= "MHX Expression Units"
3820 bl_space_type
= "VIEW_3D"
3821 bl_region_type
= "UI"
3822 bl_options
= {'DEFAULT_CLOSED'}
3825 def poll(cls
, context
):
3826 return pollMhx(context
.object)
3828 def draw(self
, context
):
3829 drawShapePanel(self
, context
, "Mhs", "expression")
3832 class MhxCustomShapePanel(bpy
.types
.Panel
):
3833 bl_label
= "MHX Custom Shapes"
3834 bl_space_type
= "VIEW_3D"
3835 bl_region_type
= "UI"
3836 bl_options
= {'DEFAULT_CLOSED'}
3839 def poll(cls
, context
):
3840 return pollMhx(context
.object)
3842 def draw(self
, context
):
3843 drawShapePanel(self
, context
, "Mhc", "custom shape")
3846 #########################################
3850 #########################################
3852 def getPoseMatrix(mat
, pb
):
3853 restInv
= pb
.bone
.matrix_local
.inverted()
3855 parInv
= pb
.parent
.matrix
.inverted()
3856 parRest
= pb
.parent
.bone
.matrix_local
3857 return restInv
* (parRest
* (parInv
* mat
))
3859 return restInv
* mat
3862 def getGlobalMatrix(mat
, pb
):
3863 gmat
= pb
.bone
.matrix_local
* mat
3865 parMat
= pb
.parent
.matrix
3866 parRest
= pb
.parent
.bone
.matrix_local
3867 return parMat
* (parRest
.inverted() * gmat
)
3872 def matchPoseTranslation(pb
, fkPb
, auto
):
3873 mat
= getPoseMatrix(fkPb
.matrix
, pb
)
3874 insertLocation(pb
, mat
, auto
)
3877 def insertLocation(pb
, mat
, auto
):
3878 pb
.location
= mat
.to_translation()
3880 pb
.keyframe_insert("location", group
=pb
.name
)
3881 bpy
.ops
.object.mode_set(mode
='OBJECT')
3882 bpy
.ops
.object.mode_set(mode
='POSE')
3885 def matchPoseRotation(pb
, fkPb
, auto
):
3886 mat
= getPoseMatrix(fkPb
.matrix
, pb
)
3887 insertRotation(pb
, mat
, auto
)
3890 def insertRotation(pb
, mat
, auto
):
3891 q
= mat
.to_quaternion()
3892 if pb
.rotation_mode
== 'QUATERNION':
3893 pb
.rotation_quaternion
= q
3895 pb
.keyframe_insert("rotation_quaternion", group
=pb
.name
)
3897 pb
.rotation_euler
= q
.to_euler(pb
.rotation_mode
)
3899 pb
.keyframe_insert("rotation_euler", group
=pb
.name
)
3900 bpy
.ops
.object.mode_set(mode
='OBJECT')
3901 bpy
.ops
.object.mode_set(mode
='POSE')
3904 def matchPoseReverse(pb
, fkPb
, auto
):
3905 bpy
.ops
.object.mode_set(mode
='OBJECT')
3906 bpy
.ops
.object.mode_set(mode
='POSE')
3907 gmat
= fkPb
.matrix
* Matrix
.Rotation(math
.pi
, 4, 'Z')
3908 offs
= pb
.bone
.length
* fkPb
.matrix
.col
[1]
3909 gmat
[0][3] += offs
[0]
3910 gmat
[1][3] += offs
[1]
3911 gmat
[2][3] += offs
[2]
3912 mat
= getPoseMatrix(gmat
, pb
)
3913 pb
.matrix_basis
= mat
3914 insertLocation(pb
, mat
, auto
)
3915 insertRotation(pb
, mat
, auto
)
3918 def matchPoseScale(pb
, fkPb
, auto
):
3919 mat
= getPoseMatrix(fkPb
.matrix
, pb
)
3920 pb
.scale
= mat
.to_scale()
3922 pb
.keyframe_insert("scale", group
=pb
.name
)
3923 bpy
.ops
.object.mode_set(mode
='OBJECT')
3924 bpy
.ops
.object.mode_set(mode
='POSE')
3927 def fk2ikArm(context
, suffix
):
3928 rig
= context
.object
3929 auto
= context
.scene
.tool_settings
.use_keyframe_insert_auto
3930 print("Snap FK Arm%s" % suffix
)
3931 snapIk
,cnsIk
= getSnapBones(rig
, "ArmIK", suffix
)
3932 (uparmIk
, loarmIk
, elbow
, elbowPt
, wrist
) = snapIk
3933 snapFk
,cnsFk
= getSnapBones(rig
, "ArmFK", suffix
)
3934 (uparmFk
, loarmFk
, elbowPtFk
, handFk
) = snapFk
3935 muteConstraints(cnsFk
, True)
3937 matchPoseRotation(uparmFk
, uparmFk
, auto
)
3938 matchPoseScale(uparmFk
, uparmFk
, auto
)
3940 matchPoseRotation(loarmFk
, loarmFk
, auto
)
3941 matchPoseScale(loarmFk
, loarmFk
, auto
)
3943 if rig
["MhaHandFollowsWrist" + suffix
]:
3944 matchPoseRotation(handFk
, wrist
, auto
)
3945 matchPoseScale(handFk
, wrist
, auto
)
3947 muteConstraints(cnsFk
, False)
3951 def ik2fkArm(context
, suffix
):
3952 rig
= context
.object
3954 auto
= scn
.tool_settings
.use_keyframe_insert_auto
3955 print("Snap IK Arm%s" % suffix
)
3956 snapIk
,cnsIk
= getSnapBones(rig
, "ArmIK", suffix
)
3957 (uparmIk
, loarmIk
, elbow
, elbowPt
, wrist
) = snapIk
3958 snapFk
,cnsFk
= getSnapBones(rig
, "ArmFK", suffix
)
3959 (uparmFk
, loarmFk
, elbowPtFk
, handFk
) = snapFk
3960 muteConstraints(cnsIk
, True)
3962 #rig["MhaElbowFollowsShoulder" + suffix] = False
3963 #rig["MhaElbowFollowsWrist" + suffix] = False
3965 matchPoseTranslation(wrist
, handFk
, auto
)
3966 matchPoseRotation(wrist
, handFk
, auto
)
3967 matchPoseTranslation(elbow
, elbowPtFk
, auto
)
3968 matchPoseTranslation(elbowPt
, elbowPtFk
, auto
)
3969 setInverse(rig
, elbowPt
)
3970 muteConstraints(cnsIk
, False)
3974 def fk2ikLeg(context
, suffix
):
3975 rig
= context
.object
3976 auto
= context
.scene
.tool_settings
.use_keyframe_insert_auto
3977 print("Snap FK Leg%s" % suffix
)
3978 snapIk
,cnsIk
= getSnapBones(rig
, "LegIK", suffix
)
3979 (uplegIk
, lolegIk
, kneePt
, ankleIk
, legIk
, legFk
, footIk
, toeIk
) = snapIk
3980 snapFk
,cnsFk
= getSnapBones(rig
, "LegFK", suffix
)
3981 (uplegFk
, lolegFk
, kneePtFk
, footFk
, toeFk
) = snapFk
3982 muteConstraints(cnsFk
, True)
3984 if not rig
["MhaLegIkToAnkle" + suffix
]:
3985 matchPoseRotation(footFk
, footFk
, auto
)
3986 matchPoseRotation(toeFk
, toeFk
, auto
)
3988 matchPoseRotation(uplegFk
, uplegFk
, auto
)
3989 matchPoseScale(uplegFk
, uplegFk
, auto
)
3991 matchPoseRotation(lolegFk
, lolegFk
, auto
)
3992 matchPoseScale(lolegFk
, lolegFk
, auto
)
3994 muteConstraints(cnsFk
, False)
3998 def ik2fkLeg(context
, suffix
):
3999 rig
= context
.object
4001 auto
= scn
.tool_settings
.use_keyframe_insert_auto
4002 print("Snap IK Leg%s" % suffix
)
4003 snapIk
,cnsIk
= getSnapBones(rig
, "LegIK", suffix
)
4004 (uplegIk
, lolegIk
, kneePt
, ankleIk
, legIk
, legFk
, footIk
, toeIk
) = snapIk
4005 snapFk
,cnsFk
= getSnapBones(rig
, "LegFK", suffix
)
4006 (uplegFk
, lolegFk
, kneePtFk
, footFk
, toeFk
) = snapFk
4007 muteConstraints(cnsIk
, True)
4009 #rig["MhaKneeFollowsHip" + suffix] = False
4010 #rig["MhaKneeFollowsFoot" + suffix] = False
4012 legIkToAnkle
= rig
["MhaLegIkToAnkle" + suffix
]
4014 matchPoseTranslation(ankleIk
, footFk
, auto
)
4015 matchPoseTranslation(legIk
, legFk
, auto
)
4016 matchPoseRotation(legIk
, legFk
, auto
)
4017 matchPoseReverse(toeIk
, toeFk
, auto
)
4018 matchPoseReverse(footIk
, footFk
, auto
)
4019 setInverse(rig
, ankleIk
)
4020 matchPoseTranslation(kneePt
, kneePtFk
, auto
)
4021 setInverse(rig
, kneePt
)
4022 if not legIkToAnkle
:
4023 matchPoseTranslation(ankleIk
, footFk
, auto
)
4025 muteConstraints(cnsIk
, False)
4030 # setInverse(rig, pb):
4033 def setInverse(rig
, pb
):
4034 rig
.data
.bones
.active
= pb
.bone
4035 pb
.bone
.select
= True
4036 bpy
.ops
.object.mode_set(mode
='OBJECT')
4037 bpy
.ops
.object.mode_set(mode
='POSE')
4038 for cns
in pb
.constraints
:
4039 if cns
.type == 'CHILD_OF':
4040 bpy
.ops
.constraint
.childof_set_inverse(constraint
=cns
.name
, owner
='BONE')
4041 bpy
.ops
.object.mode_set(mode
='OBJECT')
4042 bpy
.ops
.object.mode_set(mode
='POSE')
4050 "ArmFK" : ["UpArm", "LoArm", "ElbowPTFK", "Hand"],
4051 "ArmIK" : ["UpArmIK", "LoArmIK", "Elbow", "ElbowPT", "Wrist"],
4052 "LegFK" : ["UpLeg", "LoLeg", "KneePTFK", "Foot", "Toe"],
4053 "LegIK" : ["UpLegIK", "LoLegIK", "KneePT", "Ankle", "LegIK", "LegFK", "FootRev", "ToeRev"],
4057 def getSnapBones(rig
, key
, suffix
):
4058 names
= SnapBones
[key
]
4062 pb
= rig
.pose
.bones
[name
+suffix
]
4064 for cns
in pb
.constraints
:
4065 if cns
.type == 'LIMIT_ROTATION' and not cns
.mute
:
4066 constraints
.append(cns
)
4067 return tuple(pbones
),constraints
4070 def muteConstraints(constraints
, value
):
4071 for cns
in constraints
:
4075 class VIEW3D_OT_MhxSnapFk2IkButton(bpy
.types
.Operator
):
4076 bl_idname
= "mhx.snap_fk_ik"
4077 bl_label
= "Snap FK"
4078 bl_options
= {'UNDO'}
4079 data
= StringProperty()
4081 def execute(self
, context
):
4082 bpy
.ops
.object.mode_set(mode
='POSE')
4083 rig
= context
.object
4084 if rig
.MhxSnapExact
:
4085 rig
["MhaRotationLimits"] = 0.0
4086 (prop
, old
) = setSnapProp(rig
, self
.data
, 1.0, context
, False)
4087 if prop
[:6] == "MhaArm":
4088 fk2ikArm(context
, prop
[-2:])
4089 elif prop
[:6] == "MhaLeg":
4090 fk2ikLeg(context
, prop
[-2:])
4091 restoreSnapProp(rig
, prop
, old
, context
)
4095 class VIEW3D_OT_MhxSnapIk2FkButton(bpy
.types
.Operator
):
4096 bl_idname
= "mhx.snap_ik_fk"
4097 bl_label
= "Snap IK"
4098 bl_options
= {'UNDO'}
4099 data
= StringProperty()
4101 def execute(self
, context
):
4102 bpy
.ops
.object.mode_set(mode
='POSE')
4103 rig
= context
.object
4104 if rig
.MhxSnapExact
:
4105 rig
["MhaRotationLimits"] = 0.0
4106 (prop
, old
) = setSnapProp(rig
, self
.data
, 0.0, context
, True)
4107 if prop
[:6] == "MhaArm":
4108 ik2fkArm(context
, prop
[-2:])
4109 elif prop
[:6] == "MhaLeg":
4110 ik2fkLeg(context
, prop
[-2:])
4111 restoreSnapProp(rig
, prop
, old
, context
)
4115 def setSnapProp(rig
, data
, value
, context
, isIk
):
4116 words
= data
.split()
4118 oldValue
= rig
[prop
]
4122 extra
= int(words
[3])
4123 oldIk
= rig
.data
.layers
[ik
]
4124 oldFk
= rig
.data
.layers
[fk
]
4125 oldExtra
= rig
.data
.layers
[extra
]
4126 rig
.data
.layers
[ik
] = True
4127 rig
.data
.layers
[fk
] = True
4128 rig
.data
.layers
[extra
] = True
4139 return (prop
, (oldValue
, ik
, fk
, extra
, oldIk
, oldFk
, oldExtra
))
4142 def restoreSnapProp(rig
, prop
, old
, context
):
4144 (oldValue
, ik
, fk
, extra
, oldIk
, oldFk
, oldExtra
) = old
4145 rig
[prop
] = oldValue
4146 rig
.data
.layers
[ik
] = oldIk
4147 rig
.data
.layers
[fk
] = oldFk
4148 rig
.data
.layers
[extra
] = oldExtra
4152 class VIEW3D_OT_MhxToggleFkIkButton(bpy
.types
.Operator
):
4153 bl_idname
= "mhx.toggle_fk_ik"
4154 bl_label
= "FK - IK"
4155 bl_options
= {'UNDO'}
4156 toggle
= StringProperty()
4158 def execute(self
, context
):
4159 words
= self
.toggle
.split()
4160 rig
= context
.object
4162 value
= float(words
[1])
4163 onLayer
= int(words
[2])
4164 offLayer
= int(words
[3])
4165 rig
.data
.layers
[onLayer
] = True
4166 rig
.data
.layers
[offLayer
] = False
4168 # Don't do autokey - confusing.
4169 #if context.tool_settings.use_keyframe_insert_auto:
4170 # rig.keyframe_insert('["%s"]' % prop, frame=scn.frame_current)
4176 # MHX FK/IK Switch panel
4179 class MhxFKIKPanel(bpy
.types
.Panel
):
4180 bl_label
= "MHX FK/IK Switch"
4181 bl_space_type
= "VIEW_3D"
4182 bl_region_type
= "UI"
4183 #bl_options = {'DEFAULT_CLOSED'}
4186 def poll(cls
, context
):
4187 return (context
.object and context
.object.MhxRig
== 'MHX')
4189 def draw(self
, context
):
4190 rig
= context
.object
4191 layout
= self
.layout
4198 layout
.label("FK/IK switch")
4201 self
.toggleButton(row
, rig
, "MhaArmIk_L", " 3", " 2")
4202 self
.toggleButton(row
, rig
, "MhaArmIk_R", " 19", " 18")
4205 self
.toggleButton(row
, rig
, "MhaLegIk_L", " 5", " 4")
4206 self
.toggleButton(row
, rig
, "MhaLegIk_R", " 21", " 20")
4208 layout
.label("IK Influence")
4211 row
.prop(rig
, '["MhaArmIk_L"]', text
="")
4212 row
.prop(rig
, '["MhaArmIk_R"]', text
="")
4215 row
.prop(rig
, '["MhaLegIk_L"]', text
="")
4216 row
.prop(rig
, '["MhaLegIk_R"]', text
="")
4219 ok
= (rig
["MhxVersion"] >= 12)
4223 layout
.label("Snapping only works with MHX version 1.12 and later.")
4227 layout
.label("Snapping")
4229 row
.label("Rotation Limits")
4230 row
.prop(rig
, '["MhaRotationLimits"]', text
="")
4231 row
.prop(rig
, "MhxSnapExact", text
="Exact Snapping")
4233 layout
.label("Snap Arm bones")
4236 row
.operator("mhx.snap_fk_ik", text
="Snap L FK Arm").data
= "MhaArmIk_L 2 3 12"
4237 row
.operator("mhx.snap_fk_ik", text
="Snap R FK Arm").data
= "MhaArmIk_R 18 19 28"
4240 row
.operator("mhx.snap_ik_fk", text
="Snap L IK Arm").data
= "MhaArmIk_L 2 3 12"
4241 row
.operator("mhx.snap_ik_fk", text
="Snap R IK Arm").data
= "MhaArmIk_R 18 19 28"
4243 layout
.label("Snap Leg bones")
4246 row
.operator("mhx.snap_fk_ik", text
="Snap L FK Leg").data
= "MhaLegIk_L 4 5 12"
4247 row
.operator("mhx.snap_fk_ik", text
="Snap R FK Leg").data
= "MhaLegIk_R 20 21 28"
4250 row
.operator("mhx.snap_ik_fk", text
="Snap L IK Leg").data
= "MhaLegIk_L 4 5 12"
4251 row
.operator("mhx.snap_ik_fk", text
="Snap R IK Leg").data
= "MhaLegIk_R 20 21 28"
4254 def toggleButton(self
, row
, rig
, prop
, fk
, ik
):
4256 row
.operator("mhx.toggle_fk_ik", text
="IK").toggle
= prop
+ " 0" + fk
+ ik
4258 row
.operator("mhx.toggle_fk_ik", text
="FK").toggle
= prop
+ " 1" + ik
+ fk
4261 ###################################################################################
4265 ###################################################################################
4267 # class MhxDriversPanel(bpy.types.Panel):
4270 class MhxDriversPanel(bpy
.types
.Panel
):
4271 bl_label
= "MHX Drivers"
4272 bl_space_type
= "VIEW_3D"
4273 bl_region_type
= "UI"
4274 bl_options
= {'DEFAULT_CLOSED'}
4277 def poll(cls
, context
):
4278 return (context
.object and context
.object.MhxRig
)
4280 def draw(self
, context
):
4285 plist
= list(context
.object.keys())
4288 if prop
[0:3] == 'Mha':
4289 if prop
[-2:] == '_L':
4290 lrProps
.append(prop
[:-2])
4291 elif prop
[-2:] != '_R':
4293 elif prop
[0:3] == 'Mhf':
4294 if prop
[-2:] == '_L':
4295 lrFaceProps
.append(prop
[:-2])
4296 elif prop
[-2:] != '_R':
4297 faceProps
.append(prop
)
4300 layout
= self
.layout
4302 layout
.prop(ob
, '["%s"]' % prop
, text
=prop
[3:])
4308 for prop
in lrProps
:
4310 row
.prop(ob
, '["%s"]' % (prop
+"_L"), text
=prop
[3:])
4311 row
.prop(ob
, '["%s"]' % (prop
+"_R"), text
=prop
[3:])
4315 layout
.label("Face shapes")
4316 for prop
in faceProps
:
4317 layout
.prop(ob
, '["%s"]' % prop
, text
=prop
[3:])
4323 for prop
in lrFaceProps
:
4325 row
.prop(ob
, '["%s"]' % (prop
+"_L"), text
=prop
[3:])
4326 row
.prop(ob
, '["%s"]' % (prop
+"_R"), text
=prop
[3:])
4330 ###################################################################################
4334 ###################################################################################
4336 # class MhxVisibilityPanel(bpy.types.Panel):
4339 class MhxVisibilityPanel(bpy
.types
.Panel
):
4340 bl_label
= "MHX Visibility"
4341 bl_space_type
= "VIEW_3D"
4342 bl_region_type
= "UI"
4343 bl_options
= {'DEFAULT_CLOSED'}
4346 def poll(cls
, context
):
4347 return (context
.object and context
.object.MhxRig
)
4349 def draw(self
, context
):
4351 layout
= self
.layout
4352 props
= list(ob
.keys())
4355 if prop
[0:3] == "Mhh":
4356 layout
.prop(ob
, '["%s"]' % prop
, text
="Hide %s" % prop
[3:])
4358 layout
.operator("mhx.update_textures")
4360 layout
.operator("mhx.add_hiders")
4361 layout
.operator("mhx.remove_hiders")
4364 class VIEW3D_OT_MhxUpdateTexturesButton(bpy
.types
.Operator
):
4365 bl_idname
= "mhx.update_textures"
4367 bl_options
= {'UNDO'}
4369 def execute(self
, context
):
4371 for mat
in bpy
.data
.materials
:
4372 if mat
.animation_data
:
4377 for driver
in mat
.animation_data
.drivers
:
4378 prop
= mat
.path_resolve(driver
.data_path
)
4379 value
= driver
.evaluate(scn
.frame_current
)
4380 #print("Update %s[%d] = %s" % (driver.data_path, driver.array_index, value))
4381 prop
[driver
.array_index
] = value
4384 class VIEW3D_OT_MhxAddHidersButton(bpy
.types
.Operator
):
4385 bl_idname
= "mhx.add_hiders"
4386 bl_label
= "Add Hide Property"
4387 bl_options
= {'UNDO'}
4389 def execute(self
, context
):
4390 rig
= context
.object
4391 for ob
in context
.scene
.objects
:
4392 if ob
.select
and ob
!= rig
:
4393 prop
= "Mhh%s" % ob
.name
4394 defNewProp(prop
, "Bool", "default=False")
4396 addHider(ob
, "hide", rig
, prop
)
4397 addHider(ob
, "hide_render", rig
, prop
)
4400 def addHider(ob
, attr
, rig
, prop
):
4401 fcu
= ob
.driver_add(attr
)
4403 drv
.type = 'SCRIPTED'
4404 drv
.expression
= "x"
4405 drv
.show_debug_info
= True
4406 var
= drv
.variables
.new()
4408 targ
= var
.targets
[0]
4410 targ
.data_path
= '["%s"]' % prop
4413 class VIEW3D_OT_MhxRemoveHidersButton(bpy
.types
.Operator
):
4414 bl_idname
= "mhx.remove_hiders"
4415 bl_label
= "Remove Hide Property"
4416 bl_options
= {'UNDO'}
4418 def execute(self
, context
):
4419 rig
= context
.object
4420 for ob
in context
.scene
.objects
:
4421 if ob
.select
and ob
!= rig
:
4422 ob
.driver_remove("hide")
4423 ob
.driver_remove("hide_render")
4424 del rig
["Mhh%s" % ob
.name
]
4427 ###################################################################################
4431 ###################################################################################
4434 (( 0, 'Root', 'MhxRoot'),
4435 ( 8, 'Face', 'MhxFace')),
4436 (( 9, 'Tweak', 'MhxTweak'),
4437 (10, 'Head', 'MhxHead')),
4438 (( 1, 'FK Spine', 'MhxFKSpine'),
4439 (17, 'IK Spine', 'MhxIKSpine')),
4440 ((13, 'Inv FK Spine', 'MhxInvFKSpine'),
4441 (16, 'Clothes', 'MhxClothes')),
4443 (( 2, 'IK Arm', 'MhxIKArm'),
4444 (18, 'IK Arm', 'MhxIKArm')),
4445 (( 3, 'FK Arm', 'MhxFKArm'),
4446 (19, 'FK Arm', 'MhxFKArm')),
4447 (( 4, 'IK Leg', 'MhxIKLeg'),
4448 (20, 'IK Leg', 'MhxIKLeg')),
4449 (( 5, 'FK Leg', 'MhxFKLeg'),
4450 (21, 'FK Leg', 'MhxFKLeg')),
4451 ((12, 'Extra', 'MhxExtra'),
4452 (28, 'Extra', 'MhxExtra')),
4453 (( 6, 'Fingers', 'MhxFingers'),
4454 (22, 'Fingers', 'MhxFingers')),
4455 (( 7, 'Links', 'MhxLinks'),
4456 (23, 'Links', 'MhxLinks')),
4457 ((11, 'Palm', 'MhxPalm'),
4458 (27, 'Palm', 'MhxPalm')),
4462 # class MhxLayersPanel(bpy.types.Panel):
4465 class MhxLayersPanel(bpy
.types
.Panel
):
4466 bl_label
= "MHX Layers"
4467 bl_space_type
= "VIEW_3D"
4468 bl_region_type
= "UI"
4469 #bl_options = {'DEFAULT_CLOSED'}
4472 def poll(cls
, context
):
4474 if (ob
and ob
.MhxRig
== 'MHX'):
4478 def draw(self
, context
):
4479 layout
= self
.layout
4480 layout
.operator("mhx.pose_enable_all_layers")
4481 layout
.operator("mhx.pose_disable_all_layers")
4482 amt
= context
.object.data
4483 for (left
,right
) in MhxLayers
:
4485 if type(left
) == str:
4489 for (n
, name
, prop
) in [left
,right
]:
4490 row
.prop(amt
, "layers", index
=n
, toggle
=True, text
=name
)
4493 class VIEW3D_OT_MhxEnableAllLayersButton(bpy
.types
.Operator
):
4494 bl_idname
= "mhx.pose_enable_all_layers"
4495 bl_label
= "Enable all layers"
4496 bl_options
= {'UNDO'}
4498 def execute(self
, context
):
4499 rig
,mesh
= getMhxRigMesh(context
.object)
4500 for (left
,right
) in MhxLayers
:
4501 if type(left
) != str:
4502 for (n
, name
, prop
) in [left
,right
]:
4503 rig
.data
.layers
[n
] = True
4506 class VIEW3D_OT_MhxDisableAllLayersButton(bpy
.types
.Operator
):
4507 bl_idname
= "mhx.pose_disable_all_layers"
4508 bl_label
= "Disable all layers"
4509 bl_options
= {'UNDO'}
4511 def execute(self
, context
):
4512 rig
,mesh
= getMhxRigMesh(context
.object)
4514 pb
= context
.active_pose_bone
4517 if pb
.bone
.layers
[n
]:
4522 rig
.data
.layers
= layers
4525 ###################################################################################
4529 ###################################################################################
4531 # getMhxRigMesh(ob):
4537 elif ob
.type == 'ARMATURE':
4539 elif ob
.type == 'MESH':
4541 return (par
and (par
.type == 'ARMATURE') and par
.MhxRig
)
4545 def getMhxRigMesh(ob
):
4546 if ob
.type == 'ARMATURE':
4547 for mesh
in ob
.children
:
4548 if mesh
.MhxMesh
and ob
.MhxRig
:
4551 elif ob
.type == 'MESH':
4553 if (par
and par
.type == 'ARMATURE' and par
.MhxRig
):
4564 # setInterpolation(rig):
4567 def setInterpolation(rig
):
4568 if not rig
.animation_data
:
4570 act
= rig
.animation_data
.action
4573 for fcu
in act
.fcurves
:
4574 for pt
in fcu
.keyframe_points
:
4575 pt
.interpolation
= 'LINEAR'
4576 fcu
.extrapolation
= 'CONSTANT'
4579 ###################################################################################
4581 # initialize and register
4583 ###################################################################################
4585 def menu_func(self
, context
):
4586 self
.layout
.operator(ImportMhx
.bl_idname
, text
="MakeHuman (.mhx)...")
4589 bpy
.types
.Object
.MhAlpha8
= BoolProperty(default
=True)
4590 bpy
.types
.Object
.MhxMesh
= BoolProperty(default
=False)
4591 bpy
.types
.Object
.MhxRig
= StringProperty(default
="")
4592 bpy
.types
.Object
.MhxRigify
= BoolProperty(default
=False)
4593 bpy
.types
.Object
.MhxSnapExact
= BoolProperty(default
=False)
4594 bpy
.types
.Object
.MhxShapekeyDrivers
= BoolProperty(default
=True)
4595 bpy
.types
.Object
.MhxStrength
= FloatProperty(
4596 name
= "Expression strength",
4597 description
= "Multiply expression with this factor",
4598 default
=1.0, min=-1.0, max=2.0
4600 bpy
.utils
.register_module(__name__
)
4601 bpy
.types
.INFO_MT_file_import
.append(menu_func
)
4605 bpy
.utils
.unregister_module(__name__
)
4609 bpy
.types
.INFO_MT_file_import
.remove(menu_func
)
4613 if __name__
== "__main__":