def print_stats(): print '.' * 70 # Checks naming print '\nPlese, rename:' bad = get_bad_naming(meshes + grps) if bad: for item, bad_data in bad.iteritems(): print '{:.<40} {}'.format(item, ', '.join([b for b in bad_data])) # Checks skin on meshes # Checks saved skin print '\nCheck skin cluster on meshes:' for mesh in meshes: if f.get_skin_cluster(mesh): continue elif os.path.exists(skin_data_path + mesh + txt_ext): print '{:.<40} {}'.format(mesh, 'no skin cluster, but saved skin') else: print '{:.<40} {}'.format(mesh, 'no skin cluster') # Checks scale in non keyed print '\nFix scale on objects greater than 1:' over_scaled = check_over_scale(meshes + jnts + grps) if over_scaled: for item, attrs in over_scaled.iteritems(): print '{:.<40} {}'.format(item, ', '.join(str(at) for at in attrs)) print '\n', '.' * 70, '\n'
def create_div_mesh(source='', target=''): if not cmds.objExists(target): cmds.duplicate(source, name=target) if not f.get_skin_cluster(target): cmds.select(target) sie.create_bones = True sie.import_weights_sp()
def get_bad_joints_distance_based(mesh, fit_len=11, infl_limit=0.2): # Gets vertices under every joint in skin cluster sc = f.get_skin_cluster(mesh) jnts = cmds.skinCluster(sc, query=True, inf=True) jnts_vtxs_infl = f.get_sc_multi(mesh) jnt_vtx_data = {} zero_infl_jnts = get_zero_weight_jnts(mesh) infl_jnts = [jnt for jnt in jnts if jnt not in zero_infl_jnts] for jnt in infl_jnts: vtxs_infl = jnts_vtxs_infl[jnt] cmds.select(clear=True) cmds.skinCluster(sc, e=True, selectInfluenceVerts=jnt) jnt_vtxs = cmds.ls(sl=True, fl=True) # Filters anything else except vtxs jnt_vtxs = [i for i in jnt_vtxs if cmds.objectType(i) == 'mesh'] # Gets out vertex digit id only jnt_vtxs = [ ''.join(c for c in vtx_id.split('.')[-1] if c.isdigit()) for vtx_id in jnt_vtxs ] jnt_vtxs = [int(vtx_id) for vtx_id in jnt_vtxs] # Removes low infl vertex from the list jnt_vtxs = [ vtx_id for vtx_id in jnt_vtxs if vtxs_infl[str(vtx_id)] > infl_limit ] if jnt_vtxs: jnt_vtx_data[jnt] = jnt_vtxs else: zero_infl_jnts.append(jnt) # pprint.pprint(jnt_vtx_data) jnt_vtxs_length = {} for jnt, vtxs in jnt_vtx_data.iteritems(): vtxs_pos = [f.get_pos('%s.vtx[%s]' % (mesh, vtx)) for vtx in vtxs] jnt_pos = f.get_pos(jnt) jnt_vtx_len = [f.get_length(jnt_pos, vtx_pos) for vtx_pos in vtxs_pos] # print jnt, jnt_vtx_len av_len = average(jnt_vtx_len) jnt_vtxs_length[jnt] = av_len # pprint.pprint(jnt_vtxs_length) ''' for jnt, av in jnt_vtxs_length.iteritems(): if av >= fit_len: print jnt, av ''' cmds.select(clear=True) return [jnt for jnt, av in jnt_vtxs_length.iteritems() if av >= fit_len ] + zero_infl_jnts '''
def get_zero_weight_jnts(mesh): sc = f.get_skin_cluster(mesh) jnts = cmds.skinCluster(sc, query=True, inf=True) bad_sc_jnts = [] for jnt in jnts: infl = cmds.skinPercent(sc, '%s.vtx[*]' % mesh, transform=jnt, query=True) if infl < 0.001: bad_sc_jnts.append(jnt) return bad_sc_jnts
def setup_head(head_mesh, teeth_mesh, gender='male', skeleton='new'): '''Gets or set bone mapping for a character, bone per vertex correspondance. Since bones are constrained to vertices. And vertices are driven with a blendshapes. Args: folder (str): path to bone mapping files that contain dictionary, dumped with a pickle set_mapping (bool, optional): used with cubes and mapping params. Defaults to False Sets custom mapping for a character cubes (list, optional): used with set and mapping params. Cubes that visualize joint placement mapping (dict, optional): used with set and cubes params. Bone per vertex correspondance Returns: dict: default or custom bone per vertex correspondance for a '*_head' mesh Examples: >>> print([i for i in example_generator(4)]) [0, 1, 2, 3] ''' bls_suffix = '_bls' combined_bls_grp = head_mesh + bls_suffix complex_template = '%s_head_complex' % gender simple_template = '%s_head_simple' % gender tmp_bones = 'tmp_bones' facefx_combined_meshes = [ u'anger', u'disgust', u'fear', u'happiness', u'jaw_open', u'low_lip_down', u'phoneme_CH', u'phoneme_CH_delta', u'phoneme_F', u'phoneme_F_delta', u'phoneme_P', u'phoneme_P_delta', u'phoneme_U', u'phoneme_U_delta', u'phoneme_W', u'phoneme_W_delta', u'phoneme_Y', u'phoneme_Y_delta', u'smile', u'sadness', u'surprise', u'up_lip_up', u'wide_pose' ] teeth_bls = [ 'Teeth_Backwards', 'Teeth_Forwards', 'Teeth_Left', 'Teeth_Open', 'Teeth_Right', 'Tongue_Down', 'Tongue_In', 'Tongue_Narrow', 'Tongue_Out', 'Tongue_Pressed_Upwards', 'Tongue_Rolled_Down', 'Tongue_Rolled_Up', 'Tongue_Up', 'Tongue_Wide' ] solved_suffix = '_solved' divided_suffix = '*_divided' root_meshes = '*_root' not_all = False divided_bls = 'divided_bls' cm_rig = 'cm_rig' jnts_grp = '_jnt_grp' # Checks all meshes in scene for f_mesh in facefx_combined_meshes + [combined_bls_grp] + teeth_bls: if not cmds.objExists(f_mesh): print f_mesh not_all = True if not_all: sys.exit('Not all objects for facefx division present in scene.') # Creates complex and simple meshes from head # Adds skin for complex and simple create_div_mesh(source=head_mesh, target=complex_template) create_div_mesh(source=head_mesh, target=simple_template) spl = split_blendshapes.SplitBlendshapes(gender=gender) spl.blendshapes_in_scene() spl.prepare_blendshapes() spl.elements_in_scene(select=False) # For now dir stores not used meshes. cmds.delete(simple_template) cmds.select(facefx_combined_meshes + [complex_template]) for f_mesh in facefx_combined_meshes: f.split_blendshape(complex_template, f_mesh) cmds.group(divided_suffix, name=divided_bls) cmds.delete(root_meshes) cmds.delete(complex_template) cmds.delete(combined_bls_grp) cmds.delete(tmp_bones) # Checks for neutral head duplicates in scene cmds.select(head_mesh) f.find_static_blendshapes(rounded=0) static_meshes = cmds.ls(sl=True) static_meshes.remove(head_mesh) cmds.delete(static_meshes) # Collects all suitable head topology meshes blendshape_meshes = f.find_identical_meshes('.*', vtxs_check=True) blendshape_meshes.remove(head_mesh) cmds.blendShape(sorted(blendshape_meshes), head_mesh) # Keys blendshapes f.key_blendshapes(head_mesh, start=0) # Skin computation f.dls(head_mesh, num_jnts=220, infls=4, iters=10) # Checks if solved mesh created bad_meshes = select_bad_joints_distance_based.get_bad_joints_distance_based( head_mesh + solved_suffix, fit_len=11, infl_limit=0.2) cmds.delete(bad_meshes) # Second pass on deleing useless joints # cmds.skinCluster(f.get_skin_cluster(head_mesh), unbind=True, edit=True) left_jnts = cmds.skinCluster(f.get_skin_cluster(head_mesh + solved_suffix), inf=True, q=True) root_jnt = cmds.duplicate(left_jnts[0])[0] left_jnts.append(root_jnt) sc = cmds.skinCluster(left_jnts, head_mesh, tsb=True)[0] cmds.setAttr("%s.envelope" % sc, 0) f.dls(head_mesh, num_jnts=220, infls=4, iters=10) bad_meshes = select_bad_joints_distance_based.get_bad_joints_distance_based( head_mesh, fit_len=11, infl_limit=0.2) cmds.delete(bad_meshes) set_fxgraph.set_fxgraph(head_mesh=head_mesh, teeth_mesh=teeth_mesh, sex=gender, skeleton=skeleton) # Cleanup # Add export combined meshes and teeth to "bls" directory cmds.delete(head_mesh + solved_suffix) cmds.delete(divided_bls) cmds.delete(cm_rig) cmds.delete(head_mesh + solved_suffix + jnts_grp) # Scene cleanup try: execfile(r'u:\face\scripts\scene_check.py') except: print 'Scene check failed. Skipped'