def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) self.autoScaleBVH(bvh_file) # TODO scaling once is probably not enough, every time the height of the human changes significantly the animation needs to be rescaled anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) _, _, _, license = self.getMetadata(filepath) anim.license = license return anim
def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) self.autoScaleBVH(bvh_file) anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) _, _, _, license = self.getMetadata(filepath) anim.license = license return anim
def _load_pose_units(self): from collections import OrderedDict self.base_bvh = bvh.load( getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") self.base_anim = self.base_bvh.createAnimationTrack( self.human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(open( getpath.getSysDataPath('poseunits/face-poseunits.json'), 'r', encoding='utf-8'), object_pairs_hook=OrderedDict) self.poseunit_names = poseunit_json['framemapping'] log.message('unit pose frame count:%s', len(self.poseunit_names)) self.modifiers = dict( list(zip(self.poseunit_names, len(self.poseunit_names) * [0.0]))) self.base_poseunit = animation.PoseUnit( self.base_anim.name, self.base_anim.data[:self.base_anim.nBones * len(self.poseunit_names)], self.poseunit_names) self._load_gui()
def loadMixPose(self, filename): log.debug("Loading special mix pose from %s", filename) self.selectedFile = filename if not filename: # Unload current pose self.selectedFile = None self.selectedPose = None # Remove the special pose from existing pose by restoring the original org_pose = self._get_current_unmodified_pose() if org_pose is None: self.human.setActiveAnimation(None) elif self.human.hasAnimation(org_pose.name): self.human.setActiveAnimation(org_pose.name) else: self.human.addAnimation(org_pose) self.human.setActiveAnimation(org_pose.name) # Remove pose reserved for ... pose library from human if self.human.hasAnimation('special-mix-pose'): self.human.removeAnimation('special-mix-pose') self.human.refreshPose(updateIfInRest=True) return # Load pose #bvh_file = animation.loadPoseFromMhpFile(filename,self.human.getBaseSkeleton()) #bvh.load(filename, convertFromZUp="auto") #anim = animation.loadPoseFromMhpFile(filename,self.human.getBaseSkeleton()) #bvh.load(filename, convertFromZUp="auto") skel=self.human.getBaseSkeleton() bvh_file = bvh.load(filename, convertFromZUp="auto") anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) self.affected_bone_idxs=[] with open(filename[0:-4]+".bones") as fp: for line in fp: self.affected_bone_idxs.append(skel.getBone(line.strip('\n')).index) self.applyMixPose(anim)
def loadFootPose(self, filename): log.debug("Loading special foot pose from %s", filename) self.selectedFile = filename if not filename: # Unload current pose self.selectedFile = None self.selectedPose = None # Remove the special pose from existing pose by restoring the original org_pose = self._get_current_unmodified_pose() if org_pose is None: self.human.setActiveAnimation(None) elif self.human.hasAnimation(org_pose.name): self.human.setActiveAnimation(org_pose.name) else: self.human.addAnimation(org_pose) self.human.setActiveAnimation(org_pose.name) # Remove pose reserved for foot pose library from human if self.human.hasAnimation('special-foot-pose'): self.human.removeAnimation('special-foot-pose') self.human.refreshPose(updateIfInRest=True) return # Load pose bvh_file = bvh.load(filename, convertFromZUp="auto") anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) self.applyFootPose(anim)
def _load_pose_units(self): from collections import OrderedDict self.base_bvh = bvh.load( getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") self.base_anim = self.base_bvh.createAnimationTrack( self.human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(io.open( getpath.getSysDataPath('poseunits/face-poseunits.json'), 'r', encoding='utf-8'), object_pairs_hook=OrderedDict) self.poseunit_names = poseunit_json['framemapping'] if len(self.poseunit_names) != self.base_bvh.frameCount: self.base_anim = None raise RuntimeError( "Face units BVH has wrong number of frames (%s) while face-poseunits.json defines %s poses, they should be equal." % (self.base_bvh.frameCount, len(self.poseunit_names))) self.base_anim = animation.PoseUnit(self.base_anim.name, self.base_anim._data, self.poseunit_names) log.message('unit pose frame count:%s', len(self.poseunit_names)) # Store indexes of all bones affected by face unit poses, should be all face bones self.face_bone_idxs = sorted( list( set([ bIdx for l in self.base_anim.getAffectedBones() for bIdx in l ])))
def onClicked(file): #if os.path.isdir(path): print '[BVHAnimLibrary: onClicked] File value changed:' + file self.path.setText(file) if os.path.isfile(file): self.BVH = bvh.load(file) #self.BVH.fromFile(file) print '[BVHAnimLibrary: onClicked] Loaded BVH file'
def onClicked(file): # if os.path.isdir(path): print "[BVHAnimLibrary: onClicked] File value changed:" + file self.path.setText(file) if os.path.isfile(file): self.BVH = bvh.load(file) # self.BVH.fromFile(file) print "[BVHAnimLibrary: onClicked] Loaded BVH file"
def loadAnimationTrack(anim): """ Load animation from a BVH file specified by anim. """ if "z_is_up" in anim.options: swapYZ = True else: swapYZ = False human = gui3d.app.selectedHuman log.debug("Loading BVH %s", anim.getPath()) # Load BVH data bvhRig = bvh.load(anim.getPath(), swapYZ) if anim.collection.scale != 1.0: # Scale rig bvhRig.scale(scale) # Scale is only useful when using the joint locations of the BVH rig # or when drawing the BVH rig. if human.getSkeleton().name == anim.collection.rig: # Skeleton and joint rig in BVH match, do a straight mapping of the # motion: # Load animation data from BVH file and add it to AnimatedMesh # This is a list that references a joint name in the BVH for each # bone in the skeleton (breadth-first order): jointToBoneMap = [bone.name for bone in human.getSkeleton().getBones()] animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) gui3d.app.statusPersist("") else: # Skeleton and joint rig in BVH are not the same, retarget/remap # the motion data: gui3d.app.statusPersist( "Currently, animation are only working with soft1 rig, please choose the soft1 rig from the skeleton chooser." ) return None if not os.path.isfile( "tools/blender26x/mh_mocap_tool/target_rigs/%s.trg" % human.getSkeleton().name): gui3d.app.statusPersist( "Cannot apply motion on the selected skeleton %s because there is no target mapping file for it.", human.getSkeleton().name) return None jointToBoneMap = skeleton.loadJointsMapping(human.getSkeleton().name, human.getSkeleton()) animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) log.debug("Created animation track for %s rig.", human.getSkeleton().name) log.debug("Frames: %s", animTrack.nFrames) log.debug("Playtime: %s", animTrack.getPlaytime()) return animTrack
def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) self.autoScaleBVH( bvh_file ) # TODO scaling once is probably not enough, every time the height of the human changes significantly the animation needs to be rescaled anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) _, _, _, license = self.getMetadata(filepath) anim.license = license return anim
def get_blank_pose(): human = gui3d.app.selectedHuman base_bvh = bvh.load(getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") base_anim = base_bvh.createAnimationTrack(human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(open(getpath.getSysDataPath('poseunits/face-poseunits.json'),'rb'), object_pairs_hook=OrderedDict) # the names of the changeable facial expression features poseunit_names = poseunit_json['framemapping'] modifiers = dict(zip(poseunit_names, len(poseunit_names)*[0.0])) base_poseunit = animation.PoseUnit(base_anim.name, base_anim.data[:base_anim.nBones*len(poseunit_names)], poseunit_names) return modifiers, base_poseunit
def setExpressionFromFile(self, mhposeFile): """Set the expression from a mhpose file""" if mhposeFile is None: # clear expression original_pose = self.getPoseAsAnimation() if original_pose and hasattr(original_pose, 'pose_backref'): original_pose = original_pose.pose_backref if original_pose is None: self.human.setActiveAnimation(None) else: if self.human.hasAnimation(original_pose.name): self.human.setActiveAnimation(original_pose.name) else: self.human.addAnimation(original_pose) self.human.setActiveAnimation(orgiginal_pose.name) if self.human.hasAnimation('expr-lib-pose'): self.human.removeAnimation('expr-lib-pose') else: # Assign expression base_bvh = bvh.load(getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") base_anim = base_bvh.createAnimationTrack(self.human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(open(getpath.getSysDataPath('poseunits/face-poseunits.json'), 'r', encoding='utf-8'), object_pairs_hook=OrderedDict) poseunit_names = poseunit_json['framemapping'] base_anim = animation.PoseUnit(base_anim.name, base_anim._data, poseunit_names) face_bone_idxs = sorted(list(set([bIdx for l in base_anim.getAffectedBones() for bIdx in l]))) new_pose = animation.poseFromUnitPose('expr-lib-pose', mhposeFile, base_anim) current_pose = self.getPoseAsAnimation() if current_pose is None: current_pose = new_pose current_pose.pose_backref = None else: if hasattr(current_pose,'pose_backref') and not current_pose.pose_backref is None: current_pose = current_pose.pose_backref org_pose = current_pose current_pose = animation.mixPoses(org_pose, new_pose, face_bone_idxs) current_pose.name = 'expr-lib-pose' self.human.addAnimation(current_pose) self.human.setActiveAnimation(current_pose.name) self.human.setPosed(True) self.human.refreshPose()
def _load_pose_units(self): from collections import OrderedDict self.base_bvh = bvh.load(getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") self.base_anim = self.base_bvh.createAnimationTrack(self.human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(open(getpath.getSysDataPath('poseunits/face-poseunits.json'),'rb'), object_pairs_hook=OrderedDict) self.poseunit_names = poseunit_json['framemapping'] log.message('unit pose frame count:%s', len(self.poseunit_names)) self.modifiers = dict(zip(self.poseunit_names, len(self.poseunit_names)*[0.0])) self.base_poseunit = animation.PoseUnit(self.base_anim.name, self.base_anim.data[:self.base_anim.nBones*len(self.poseunit_names)], self.poseunit_names) self._load_gui()
def loadAnimation(self, filename): global SPARSIFY log.message("Loading BVH animation %s", filename) animName = unicode(os.path.splitext(os.path.basename(filename))[0]) self.stopPlayback() if not self.animated.hasAnimation(animName): # TODO cache bvh file (and mappings) bvhRig = bvh.load(filename) # TODO scale bvh by comparing upper leg length bvhRig.scale(0.7) bvhRig.filename = filename # TODO cache mapping #jointToBoneMap = skeleton.loadJointsMapping("soft1", self.skel) retargetMapping = skeleton.getRetargetMapping( 'mb', 'soft1', self.skel) #retargetMapping = skeleton.getRetargetMappingFromBVH(bvhRig, 'soft1', self.skel) # TODO guess format of source rig animTrack = bvhRig.createAnimationTrack(retargetMapping, animName) if SPARSIFY: if animTrack.frameRate > 30: animTrack.sparsify(30) self.animated.addAnimation(animTrack) #self.__bvhRigCache['mb'] # TODO cache rig for all BVH rig types, for now we assume all BVHs are mb format else: animTrack = self.animated.getAnimation(animName) if not self.bvhAnimated or not self.bvhAnimated.hasAnimation(animName): # Draw BVH rig and/or add animation self.loadBVHRig(bvhRig) self.animated.setActiveAnimation(animName) self.anim = animTrack self.anim.interpolationType = 0 self.createPlaybackControl() self.animated.setAnimateInPlace(self.animateInPlaceTggl.selected) self.animated.setToFrame(0) self.setShowRig(self.showMHXRigTggl.selected) self.bvhAnimated.setActiveAnimation(animName) self.bvhAnimated.setAnimateInPlace(self.animateInPlaceTggl.selected) self.bvhAnimated.setToFrame(0) self.setShowBVHRig(self.showBVHRigTggl.selected) self.__setSelectedAnimation(filename) self.startPlayback()
def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) if "root" in bvh_file.joints: posedata = anim.getAtFramePos(0, noBake=True) root_bone_idx = 0 self.bvh_root_translation = posedata[root_bone_idx, :3, 3].copy() else: self.bvh_root_translation = np.asarray(3 * [0.0], dtype=np.float32) self.bvh_bone_length = self.calculateBvhBoneLength(bvh_file) self.autoScaleAnim(anim) _, _, _, license = self.getMetadata(filepath) anim.license = license return anim
def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) if "root" in bvh_file.joints: posedata = anim.getAtFramePos(0, noBake=True) root_bone_idx = 0 self.bvh_root_translation = posedata[root_bone_idx, :3, 3].copy() else: self.bvh_root_translation = np.asarray(3*[0.0], dtype=np.float32) self.bvh_bone_length = self.calculateBvhBoneLength(bvh_file) self.autoScaleAnim(anim) _, _, _, license = self.getMetadata(filepath) anim.license = license return anim
def loadAnimationTrack(anim): """ Load animation from a BVH file specified by anim. """ if "z_is_up" in anim.options: swapYZ = True else: swapYZ = False human = gui3d.app.selectedHuman log.debug("Loading BVH %s", anim.getPath()) # Load BVH data bvhRig = bvh.load(anim.getPath(), swapYZ) if anim.collection.scale != 1.0: # Scale rig bvhRig.scale(scale) # Scale is only useful when using the joint locations of the BVH rig # or when drawing the BVH rig. if human.getSkeleton().name == anim.collection.rig: # Skeleton and joint rig in BVH match, do a straight mapping of the # motion: # Load animation data from BVH file and add it to AnimatedMesh # This is a list that references a joint name in the BVH for each # bone in the skeleton (breadth-first order): jointToBoneMap = [bone.name for bone in human.getSkeleton().getBones()] animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) gui3d.app.statusPersist("") else: # Skeleton and joint rig in BVH are not the same, retarget/remap # the motion data: gui3d.app.statusPersist("Currently, animation are only working with soft1 rig, please choose the soft1 rig from the skeleton chooser.") return None if not os.path.isfile("tools/blender26x/mh_mocap_tool/target_rigs/%s.trg" % human.getSkeleton().name): gui3d.app.statusPersist("Cannot apply motion on the selected skeleton %s because there is no target mapping file for it.", human.getSkeleton().name) return None jointToBoneMap = skeleton.loadJointsMapping(human.getSkeleton().name, human.getSkeleton()) animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) log.debug("Created animation track for %s rig.", human.getSkeleton().name) log.debug("Frames: %s", animTrack.nFrames) log.debug("Playtime: %s", animTrack.getPlaytime()) return animTrack
def loadAnimation(self, filename): global SPARSIFY log.message("Loading BVH animation %s", filename) animName = unicode(os.path.splitext(os.path.basename(filename))[0]) self.stopPlayback() if not self.animated.hasAnimation(animName): # TODO cache bvh file (and mappings) bvhRig = bvh.load(filename) # TODO scale bvh by comparing upper leg length bvhRig.scale(0.7) bvhRig.filename = filename # TODO cache mapping #jointToBoneMap = skeleton.loadJointsMapping("soft1", self.skel) retargetMapping = skeleton.getRetargetMapping('mb', 'soft1', self.skel) #retargetMapping = skeleton.getRetargetMappingFromBVH(bvhRig, 'soft1', self.skel) # TODO guess format of source rig animTrack = bvhRig.createAnimationTrack(retargetMapping, animName) if SPARSIFY: if animTrack.frameRate > 30: animTrack.sparsify(30) self.animated.addAnimation(animTrack) #self.__bvhRigCache['mb'] # TODO cache rig for all BVH rig types, for now we assume all BVHs are mb format else: animTrack = self.animated.getAnimation(animName) if not self.bvhAnimated or not self.bvhAnimated.hasAnimation(animName): # Draw BVH rig and/or add animation self.loadBVHRig(bvhRig) self.animated.setActiveAnimation(animName) self.anim = animTrack self.anim.interpolationType = 0 self.createPlaybackControl() self.animated.setAnimateInPlace(self.animateInPlaceTggl.selected) self.animated.setToFrame(0) self.setShowRig(self.showMHXRigTggl.selected) self.bvhAnimated.setActiveAnimation(animName) self.bvhAnimated.setAnimateInPlace(self.animateInPlaceTggl.selected) self.bvhAnimated.setToFrame(0) self.setShowBVHRig(self.showBVHRigTggl.selected) self.__setSelectedAnimation(filename) self.startPlayback()
def __init__(self, category): gui3d.TaskView.__init__(self, category, 'Expressions') self.human = gui3d.app.selectedHuman # TODO defer loading to first onShow() bvhfile = bvh.load(getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") self.base_bvh = bvhfile from collections import OrderedDict poseunit_json = json.load(open(getpath.getSysDataPath('poseunits/face-poseunits.json'),'rb'), object_pairs_hook=OrderedDict) self.poseunit_names = poseunit_json['framemapping'] self.sliders = [] self.modifiers = dict(zip(self.poseunit_names, len(self.poseunit_names)*[0.0]))
def _load_pose_units(self): from collections import OrderedDict self.base_bvh = bvh.load(getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") self.base_anim = self.base_bvh.createAnimationTrack(self.human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(open(getpath.getSysDataPath('poseunits/face-poseunits.json'),'rb'), object_pairs_hook=OrderedDict) self.poseunit_names = poseunit_json['framemapping'] if len(self.poseunit_names) != self.base_bvh.frameCount: self.base_anim = None raise RuntimeError("Face units BVH has wrong number of frames (%s) while face-poseunits.json defines %s poses, they should be equal." % (self.base_bvh.frameCount, len(self.poseunit_names))) self.base_anim = animation.PoseUnit(self.base_anim.name, self.base_anim._data, self.poseunit_names) log.message('unit pose frame count:%s', len(self.poseunit_names)) # Store indexes of all bones affected by face unit poses, should be all face bones self.face_bone_idxs = sorted(list(set([bIdx for l in self.base_anim.getAffectedBones() for bIdx in l])))
def setExpression(expression): if expression == "None": modifiers, _ = get_blank_pose() return modifiers with open(expression, 'r') as f: human = G.app.objects[0] base_bvh = bvh.load( getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") base_anim = base_bvh.createAnimationTrack( human.getBaseSkeleton(), name="Expression-Face-PoseUnits") poseunit_json = json.load(open( getpath.getSysDataPath('poseunits/face-poseunits.json'), 'rb'), object_pairs_hook=OrderedDict) # the names of the changeable facial expression features poseunit_names = poseunit_json['framemapping'] modifiers = dict(zip(poseunit_names, len(poseunit_names) * [0.0])) base_poseunit = animation.PoseUnit( base_anim.name, base_anim.data[:base_anim.nBones * len(poseunit_names)], poseunit_names) pose_modifiers = json.load(f, object_pairs_hook=OrderedDict)['unit_poses'] for key in modifiers: if key in pose_modifiers: modifiers[key] = pose_modifiers[key] # see which values are different so only those are updated posenames = [] posevalues = [] for pname, pval in modifiers.items(): #if pval != 0: posenames.append(pname) posevalues.append(pval) if len(posenames) > 0: panim = base_poseunit.getBlendedPose(posenames, posevalues) panim.disableBaking = False human.addAnimation(panim) human.setActiveAnimation(panim.name) human.refreshPose() return modifiers
def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) if COMPARE_BONE not in bvh_file.joints: msg = 'The pose file cannot be used. It uses a rig different from MakeHuman\'s defualt rig' G.app.prompt('Error', msg, 'OK') log.error('Pose file %s does not use the default rig.' % filepath) return None anim = bvh_file.createAnimationTrack(self.human.getBaseSkeleton()) if "root" in bvh_file.joints: posedata = anim.getAtFramePos(0, noBake=True) root_bone_idx = 0 self.bvh_root_translation = posedata[root_bone_idx, :3, 3].copy() else: self.bvh_root_translation = np.asarray(3*[0.0], dtype=np.float32) self.bvh_bone_length = self.calculateBvhBoneLength(bvh_file) self.autoScaleAnim(anim) _, _, _, license = self.getMetadata(filepath) anim.license = license return anim
def __init__(self, category): gui3d.TaskView.__init__(self, category, 'Expressions') self.human = gui3d.app.selectedHuman # TODO defer loading to first onShow() bvhfile = bvh.load( getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") self.base_bvh = bvhfile from collections import OrderedDict poseunit_json = json.load(open( getpath.getSysDataPath('poseunits/face-poseunits.json'), 'rb'), object_pairs_hook=OrderedDict) self.poseunit_names = poseunit_json['framemapping'] self.sliders = [] self.modifiers = dict( zip(self.poseunit_names, len(self.poseunit_names) * [0.0]))
def loadAnimationTrack(anim): """ Load animation from a BVH file specified by anim. """ global _jointMappingCache if "z_is_up" in anim.options: swapYZ = True else: swapYZ = False human = gui3d.app.selectedHuman log.debug("Loading BVH %s", anim.getPath()) # Load BVH data bvhRig = bvh.load(anim.getPath(), swapYZ) if anim.collection.scale != 1.0: # Scale rig bvhRig.scale(anim.collection.scale) # Scale is only useful when using the joint locations of the BVH rig # or when drawing the BVH rig. if human.getSkeleton().name == anim.collection.rig: # Skeleton and joint rig in BVH match, do a straight mapping of the # motion: # Load animation data from BVH file and add it to AnimatedMesh # This is a list that references a joint name in the BVH for each # bone in the skeleton (breadth-first order): jointToBoneMap = [bone.name for bone in human.getSkeleton().getBones()] animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) gui3d.app.statusPersist("") else: # Skeleton and joint rig in BVH are not the same, retarget/remap # the motion data: if not os.path.isfile( mh.getSysPath( "tools/blender26x/mh_mocap_tool/target_rigs/%s.trg") % human.getSkeleton().name): gui3d.app.statusPersist( "Cannot apply motion on the selected skeleton %s because there is no target mapping file for it.", human.getSkeleton().name) return None # Load source skeleton of animation for remapping cacheName = anim.collection.rig + "_" + human.getSkeleton().name if cacheName in _jointMappingCache: # Load from cache jointToBoneMap = _jointMappingCache[cacheName] else: # Create and cache mapping srcSkel, _ = skeleton.loadRig( os.path.join(mh.getSysDataPath('rigs'), '%s.rig' % anim.collection.rig), human.meshData) tgtSkel = human.getSkeleton() # Load mapping from reference rig to target rig # TODO this only works if anim.collection.rig == soft1! We cannot do reverse target mappings jointToBoneMap = skeleton.getRetargetMapping( None, human.getSkeleton().name, human.getSkeleton()) # We dont use the compensation angles from the retarget map, instead we calculate the difference between reference and target rig ourselves excludeFromCompensation = ["Root", "Spine1", "Spine2", "Spine3"] jointToBoneMap = skeleton.getRestPoseCompensation( srcSkel, tgtSkel, jointToBoneMap, excludeFromCompensation) _jointMappingCache[cacheName] = jointToBoneMap animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) gui3d.app.statusPersist("") log.debug("Created animation track for %s rig.", human.getSkeleton().name) log.debug("Frames: %s", animTrack.nFrames) log.debug("Playtime: %s", animTrack.getPlaytime()) return animTrack
def exportCollada(filepath, config): progress = Progress() time1 = time.perf_counter() human = config.human config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = config.goodName(os.path.splitext(filename)[0]) progress(0, 0.5, "Preparing") objects = human.getObjects(excludeZeroFaceObjs=not config.hiddenGeom) # Clone meshes with desired scale and hidden faces/vertices filtered out meshes = [ obj.mesh.clone(config.scale, filterMaskedVerts=not config.hiddenGeom) for obj in objects ] if config.hiddenGeom: import numpy as np # Disable the face masking on copies of the input meshes for m in meshes: # Disable the face masking on the mesh face_mask = np.ones(m.face_mask.shape, dtype=bool) m.changeFaceMask(face_mask) m.calcNormals() m.updateIndexBuffer() # Scale skeleton skel = human.getSkeleton() if skel: if config.scale != 1: skel = skel.scaled(config.scale) # TODO a shared method for properly naming meshes would be a good idea for mesh in meshes: if mesh.object.proxy: mesh.name = mesh.object.proxy.name mesh.name = os.path.splitext(mesh.name)[0] mesh.name = name + '-' + config.goodName(mesh.name) try: progress(0.5, 0.55, "Exporting %s", filepath) try: fp = io.open(filepath, 'w', encoding="utf-8") log.message("Writing Collada file %s" % filepath) except: fp = None log.error("Unable to open file for writing %s" % filepath) date = time.strftime("%Y-%m-%dT%H:%M:%S+00:00", time.gmtime()) # TODO revise to make this enum-like if config.yUpFaceZ or config.yUpFaceX: upvector = "Y_UP" else: upvector = "Z_UP" fp.write( '<?xml version="1.0" encoding="utf-8"?>\n' + '<COLLADA version="1.4.1" xmlns="http://www.collada.org/2005/11/COLLADASchema">\n' + ' <asset>\n' + ' <contributor>\n' + ' <author>www.makehumancommunity.org</author>\n' + ' </contributor>\n' + ' <created>%s</created>\n' % date + ' <modified>%s</modified>\n' % date + ' <unit meter="%.4f" name="%s"/>\n' % (0.1 / config.scale, config.unit) + ' <up_axis>%s</up_axis>\n' % upvector + ' </asset>\n') progress(0.55, 0.6, "Exporting images") dae_materials.writeLibraryImages(fp, objects, config) progress(0.6, 0.65, "Exporting effects") dae_materials.writeLibraryEffects(fp, objects, config) progress(0.65, 0.7, "Exporting materials") dae_materials.writeLibraryMaterials(fp, objects, config) progress(0.7, 0.75, "Exporting controllers") dae_controller.writeLibraryControllers(fp, human, meshes, skel, config) progress(0.75, 0.8, "Exporting animations") #animations = [human.getAnimation(name) for name in human.getAnimations()] # TODO distinguish poses from animations if skel and config.facePoseUnits: bvhfile = bvh.load( getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") # TODO compensate for rest pose faceunit_anim = bvhfile.createAnimationTrack( skel, name="Expression-Face-PoseUnits") animations = [ human.getAnimation(name) for name in human.getAnimations() ] + [faceunit_anim] dae_animation.writeLibraryAnimations(fp, human, skel, animations, config) progress(0.75, 0.9, "Exporting geometry") dae_geometry.writeLibraryGeometry(fp, meshes, config) progress(0.9, 0.99, "Exporting scene") dae_node.writeLibraryVisualScenes(fp, meshes, skel, config, name) fp.write(' <scene>\n' + ' <instance_visual_scene url="#Scene"/>\n' + ' </scene>\n' + '</COLLADA>\n') progress(1, None, "Export finished.") time2 = time.perf_counter() log.message("Wrote Collada file in %g s: %s", time2 - time1, filepath) finally: if fp: fp.close()
def loadAnimationTrack(anim): """ Load animation from a BVH file specified by anim. """ global _jointMappingCache if "z_is_up" in anim.options: swapYZ = True else: swapYZ = False human = gui3d.app.selectedHuman log.debug("Loading BVH %s", anim.getPath()) # Load BVH data bvhRig = bvh.load(anim.getPath(), swapYZ) if anim.collection.scale != 1.0: # Scale rig bvhRig.scale(scale) # Scale is only useful when using the joint locations of the BVH rig # or when drawing the BVH rig. if human.getSkeleton().name == anim.collection.rig: # Skeleton and joint rig in BVH match, do a straight mapping of the # motion: # Load animation data from BVH file and add it to AnimatedMesh # This is a list that references a joint name in the BVH for each # bone in the skeleton (breadth-first order): jointToBoneMap = [bone.name for bone in human.getSkeleton().getBones()] animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) gui3d.app.statusPersist("") else: # Skeleton and joint rig in BVH are not the same, retarget/remap # the motion data: if not os.path.isfile(mh.getSysPath("tools/blender26x/mh_mocap_tool/target_rigs/%s.trg") % human.getSkeleton().name): gui3d.app.statusPersist("Cannot apply motion on the selected skeleton %s because there is no target mapping file for it.", human.getSkeleton().name) return None # Load source skeleton of animation for remapping cacheName = anim.collection.rig + "_" + human.getSkeleton().name if cacheName in _jointMappingCache: # Load from cache jointToBoneMap = _jointMappingCache[cacheName] else: # Create and cache mapping srcSkel, _ = skeleton.loadRig(os.path.join(mh.getSysDataPath('rigs'), '%s.rig' % anim.collection.rig), human.meshData) tgtSkel = human.getSkeleton() # Load mapping from reference rig to target rig # TODO this only works if anim.collection.rig == soft1! We cannot do reverse target mappings jointToBoneMap = skeleton.getRetargetMapping(None, human.getSkeleton().name, human.getSkeleton()) # We dont use the compensation angles from the retarget map, instead we calculate the difference between reference and target rig ourselves excludeFromCompensation = ["Root", "Spine1", "Spine2", "Spine3"] jointToBoneMap = skeleton.getRestPoseCompensation(srcSkel, tgtSkel, jointToBoneMap, excludeFromCompensation) _jointMappingCache[cacheName] = jointToBoneMap animTrack = bvhRig.createAnimationTrack(jointToBoneMap, anim.getAnimationTrackName()) gui3d.app.statusPersist("") log.debug("Created animation track for %s rig.", human.getSkeleton().name) log.debug("Frames: %s", animTrack.nFrames) log.debug("Playtime: %s", animTrack.getPlaytime()) return animTrack
def loadBvh(self, filepath, convertFromZUp="auto"): bvh_file = bvh.load(filepath, convertFromZUp) self.autoScaleBVH(bvh_file) return bvh_file.createAnimationTrack(self.human.getSkeleton())
def exportCollada(filepath, config): progress = Progress() time1 = time.clock() human = config.human config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = config.goodName(os.path.splitext(filename)[0]) progress(0, 0.5, "Preparing") objects = human.getObjects(excludeZeroFaceObjs=True) # Clone meshes with desired scale and hidden faces/vertices filtered out meshes = [obj.mesh.clone(config.scale, True) for obj in objects] # Scale skeleton skel = human.getSkeleton() if skel: if config.scale != 1: skel = skel.scaled(config.scale) if not skel.isInRestPose(): # Export skeleton with the current pose as rest pose skel = skel.createFromPose() # TODO a shared method for properly naming meshes would be a good idea for mesh in meshes: if mesh.object.proxy: mesh.name = mesh.object.proxy.name mesh.name = os.path.splitext(mesh.name)[0] mesh.name = name + '-' + config.goodName(mesh.name) try: progress(0.5, 0.55, "Exporting %s", filepath) try: fp = codecs.open(filepath, 'w', encoding="utf-8") log.message("Writing Collada file %s" % filepath) except: fp = None log.error("Unable to open file for writing %s" % filepath) date = time.strftime(u"%a, %d %b %Y %H:%M:%S +0000".encode('utf-8'), time.localtime()).decode('utf-8') # TODO revise to make this enum-like if config.yUpFaceZ or config.yUpFaceX: upvector = "Y_UP" else: upvector = "Z_UP" fp.write('<?xml version="1.0" encoding="utf-8"?>\n' + '<COLLADA version="1.4.0" xmlns="http://www.collada.org/2005/11/COLLADASchema">\n' + ' <asset>\n' + ' <contributor>\n' + ' <author>www.makehuman.org</author>\n' + ' </contributor>\n' + ' <created>%s</created>\n' % date + ' <modified>%s</modified>\n' % date + ' <unit meter="%.4f" name="%s"/>\n' % (0.1/config.scale, config.unit) + ' <up_axis>%s</up_axis>\n' % upvector + ' </asset>\n') progress(0.55, 0.6, "Exporting images") dae_materials.writeLibraryImages(fp, objects, config) progress(0.6, 0.65, "Exporting effects") dae_materials.writeLibraryEffects(fp, objects, config) progress(0.65, 0.7, "Exporting materials") dae_materials.writeLibraryMaterials(fp, objects, config) progress(0.7, 0.75, "Exporting controllers") dae_controller.writeLibraryControllers(fp, human, meshes, skel, config) progress(0.75, 0.8, "Exporting animations") #animations = [human.getAnimation(name) for name in human.getAnimations()] # TODO distinguish poses from animations if skel and config.facePoseUnits: bvhfile = bvh.load(getpath.getSysDataPath('poseunits/face-poseunits.bvh'), allowTranslation="none") # TODO compensate for rest pose faceunit_anim = bvhfile.createAnimationTrack(skel, name="Expression-Face-PoseUnits") animations = [faceunit_anim] dae_animation.writeLibraryAnimations(fp, human, skel, animations, config) progress(0.75, 0.9, "Exporting geometry") dae_geometry.writeLibraryGeometry(fp, meshes, config) progress(0.9, 0.99, "Exporting scene") dae_node.writeLibraryVisualScenes(fp, meshes, skel, config, name) fp.write( ' <scene>\n' + ' <instance_visual_scene url="#Scene"/>\n' + ' </scene>\n' + '</COLLADA>\n') progress(1, None, "Export finished.") time2 = time.clock() log.message("Wrote Collada file in %g s: %s", time2-time1, filepath) finally: if fp: fp.close()