def execute(self, context): scene = context.scene if not ObjectService.object_is_basemesh(context.active_object): self.report({'ERROR'}, "Rigs can only be added to the base mesh") return {'FINISHED'} basemesh = context.active_object from mpfb.ui.addrig.addrigpanel import ADD_RIG_PROPERTIES # pylint: disable=C0415 import_weights = ADD_RIG_PROPERTIES.get_value("import_weights", entity_reference=scene) standard_rig = ADD_RIG_PROPERTIES.get_value("standard_rig", entity_reference=scene) rigs_dir = LocationService.get_mpfb_data("rigs") standard_dir = os.path.join(rigs_dir, "standard") rig_file = os.path.join(standard_dir, "rig." + standard_rig + ".json") rig = Rig.from_json_file_and_basemesh(rig_file, basemesh) armature_object = rig.create_armature_and_fit_to_basemesh() basemesh.parent = armature_object if import_weights: weights_file = os.path.join(standard_dir, "weights." + standard_rig + ".json") weights = dict() with open(weights_file, 'r') as json_file: weights = json.load(json_file) RigService.apply_weights(armature_object, basemesh, weights) self.report({'INFO'}, "A rig was added") return {'FINISHED'}
def draw(self, context): _LOG.enter() layout = self.layout scene = context.scene if not context.object: return if not ObjectService.object_is_basemesh(context.object): return basemesh = context.object for category_name in _MACROTARGETS.keys(): targets = _MACROTARGETS[category_name] self._draw_category(scene, layout, category_name, targets, basemesh)
def draw(self, context): _LOG.enter() layout = self.layout scene = context.scene if not context.object: return if not ObjectService.object_is_basemesh(context.object): return basemesh = context.object _LOG.dump("target_dir", self.target_dir) for category in self.section["categories"]: self._draw_category(scene, layout, category, basemesh)
def execute(self, context): _LOG.enter() if context.object is None: self.report({'ERROR'}, "Must have a selected object") return {'FINISHED'} name = HUMAN_PRESETS_PROPERTIES.get_value("name", entity_reference=context) if not name is None: name = str(name).strip() if name == "" or name is None: self.report({'ERROR'}, "A valid name must be given") return {'FINISHED'} if " " in str(name): self.report({'ERROR'}, "Human presets names should not contain spaces") return {'FINISHED'} confdir = LocationService.get_user_config() file_name = os.path.join(confdir, "human." + name + ".json") if os.path.exists(file_name): self.report({'ERROR'}, "Presets with that name already exist") return {'FINISHED'} basemesh = None if ObjectService.object_is_basemesh(context.object): basemesh = context.object else: basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Basemesh") if basemesh is None: self.report( {'ERROR'}, "Could not find basemesh amongst relatives of selected object") return {'FINISHED'} HumanService.serialize_to_json_file(basemesh, file_name, True) self.report({'INFO'}, "Human saved as " + file_name) return {'FINISHED'}
def execute(self, context): scene = context.scene if not ObjectService.object_is_basemesh(context.active_object): self.report({'ERROR'}, "Rigs can only be added to the base mesh") return {'FINISHED'} basemesh = context.active_object from mpfb.ui.addrig.addrigpanel import ADD_RIG_PROPERTIES # pylint: disable=C0415 import_weights = ADD_RIG_PROPERTIES.get_value("import_weights_rigify", entity_reference=scene) generate = ADD_RIG_PROPERTIES.get_value("generate", entity_reference=scene) delete_after_generate = ADD_RIG_PROPERTIES.get_value( "delete_after_generate", entity_reference=scene) rigs_dir = LocationService.get_mpfb_data("rigs") rigify_dir = os.path.join(rigs_dir, "rigify") rig_file = os.path.join(rigify_dir, "rig.human.json") rig = Rig.from_json_file_and_basemesh(rig_file, basemesh) armature_object = rig.create_armature_and_fit_to_basemesh() armature_object.data.rigify_rig_basename = "Human.rigify" rigify_ui = dict() layer_file = os.path.join(rigify_dir, "rigify_layers.json") with open(layer_file, "r") as json_file: rigify_ui = json.load(json_file) bpy.ops.armature.rigify_add_bone_groups() bpy.ops.pose.rigify_layer_init() armature_object.data.rigify_colors_lock = rigify_ui[ "rigify_colors_lock"] armature_object.data.rigify_selection_colors.select = rigify_ui[ "selection_colors"]["select"] armature_object.data.rigify_selection_colors.active = rigify_ui[ "selection_colors"]["active"] i = 0 for color in armature_object.data.rigify_colors: col = rigify_ui["colors"][i] color.name = col["name"] color.normal = col["normal"] i = i + 1 i = 0 for rigify_layer in armature_object.data.layers: armature_object.data.layers[i] = rigify_ui["layers"][i] i = i + 1 i = 0 for rigify_layer in armature_object.data.rigify_layers: layer = rigify_ui["rigify_layers"][i] rigify_layer.name = layer["name"] rigify_layer.row = layer["row"] rigify_layer.selset = layer["selset"] rigify_layer.group = layer["group"] i = i + 1 if not generate: basemesh.parent = armature_object if import_weights: weights_file = os.path.join(rigify_dir, "weights.human.json") weights = dict() with open(weights_file, 'r') as json_file: weights = json.load(json_file) RigService.apply_weights(armature_object, basemesh, weights) if generate: bpy.ops.pose.rigify_generate() rigify_object = context.active_object rigify_object.show_in_front = True _LOG.debug("rigify", rigify_object) basemesh.parent = rigify_object for bone in armature_object.data.bones: name = bone.name if name in basemesh.vertex_groups and not "teeth" in name: vertex_group = basemesh.vertex_groups.get(name) vertex_group.name = "DEF-" + name for modifier in basemesh.modifiers: if modifier.type == 'ARMATURE': modifier.object = rigify_object if delete_after_generate: objs = bpy.data.objects objs.remove(objs[armature_object.name], do_unlink=True) bpy.ops.object.mode_set(mode='EDIT', toggle=False) teethb = RigService.find_edit_bone_by_name("teeth.B", rigify_object) teethb.use_deform = True bpy.ops.object.mode_set(mode='OBJECT', toggle=False) self.report({'INFO'}, "A rig was added") return {'FINISHED'}
def poll(cls, context): if context.active_object is not None: return ObjectService.object_is_basemesh(context.active_object) return False
def fit_clothes_to_human(clothes, basemesh, mhclo=None): """Move clothes vertices so they fit the current shape of the base mesh.""" if basemesh is None: raise ValueError('Cannot refit to None basemesh') if clothes is None: raise ValueError('Cannot refit to None clothes') if not ObjectService.object_is_basemesh(basemesh): raise ValueError('The provided object is not a basemesh') if mhclo is None: raise NotImplemented( "Searching for MHCLO info is not implemented yet, you must provide the MHCLO object" ) # We cannot rely on the vertex position data directly, since it represent positions # as they are *before* targets are applied. We want the shape of the mesh *after* # targets are applied. # # We will therefore create a new shape key "from mix". This means it will have the # combined state of all current shape keys. Then we will use that shape key for # getting vertex positions. key_name = "temporary_fitting_key." + str(random.randrange(1000, 9999)) basemesh.shape_key_add(name=key_name, from_mix=True) shape_key = basemesh.data.shape_keys.key_blocks[key_name] human_vertices = shape_key.data human_vertices_count = len(human_vertices) scale_factor = GeneralObjectProperties.get_value( "scale_factor", entity_reference=basemesh) if not scale_factor: scale_factor = 1.0 # Fallback for if no scale is specified in mhclo z_size = y_size = x_size = scale_factor if mhclo.x_scale: if mhclo.x_scale[0] >= human_vertices_count or mhclo.x_scale[1] > human_vertices_count \ or mhclo.y_scale[0] >= human_vertices_count or mhclo.y_scale[1] >= human_vertices_count \ or mhclo.z_scale[0] >= human_vertices_count or mhclo.z_scale[1] >= human_vertices_count: _LOG.warn("Giving up refitting, not inside") raise ValueError("Cannot refit as we are not inside") x_size = abs( human_vertices[mhclo.x_scale[0]].co[0] - human_vertices[mhclo.x_scale[1]].co[0]) / mhclo.x_scale[2] y_size = abs( human_vertices[mhclo.y_scale[0]].co[2] - human_vertices[mhclo.y_scale[1]].co[2]) / mhclo.y_scale[2] z_size = abs( human_vertices[mhclo.z_scale[0]].co[1] - human_vertices[mhclo.z_scale[1]].co[1]) / mhclo.z_scale[2] _LOG.debug("x_scale, y_scale, z_scale", (mhclo.x_scale, mhclo.y_scale, mhclo.z_scale)) _LOG.debug("x_size, y_size, z_size", (x_size, y_size, z_size)) clothes_vertices = mhclo.clothes.data.vertices _LOG.debug("About to try to match vertices: ", len(clothes_vertices)) _LOG.dump("Verts", mhclo.verts) for clothes_vertex_number in range(len(clothes_vertices)): vertex_match_info = mhclo.verts[clothes_vertex_number] (human_vertex1, human_vertex2, human_vertex3) = vertex_match_info["verts"] # test if we inside mesh, if not, no chance # if human_vertex1 >= human_vertices_count or human_vertex2 > human_vertices_count or human_vertex3 >= human_vertices_count: continue offset = [ vertex_match_info["offsets"][0] * x_size, vertex_match_info["offsets"][1] * z_size, vertex_match_info["offsets"][2] * y_size ] clothes_vertices[clothes_vertex_number].co = \ vertex_match_info["weights"][0] * human_vertices[human_vertex1].co + \ vertex_match_info["weights"][1] * human_vertices[human_vertex2].co + \ vertex_match_info["weights"][2] * human_vertices[human_vertex3].co + \ Vector(offset) # We need to take into account that the base mesh might be rigged. If it is, we'll want the rig position # rather than the basemesh position if basemesh.parent: clothes.location = (0.0, 0.0, 0.0) clothes.parent = basemesh.parent else: clothes.location = basemesh.location # As we are finished with the combined shape key we can now remove it basemesh.shape_key_remove(shape_key)
def poll(cls, context): if not ObjectService.object_is_basemesh(context.active_object): return False if context.active_object.data.shape_keys: return True return False
def execute(self, context): _LOG.debug("filepath", self.filepath) _LOG.debug("object_type", self.object_type) _LOG.debug("material_type", self.material_type) from mpfb.ui.assetlibrary.assetsettingspanel import ASSET_SETTINGS_PROPERTIES # pylint: disable=C0415 scene = context.scene fit_to_body = ASSET_SETTINGS_PROPERTIES.get_value( "fit_to_body", entity_reference=scene) delete_group = ASSET_SETTINGS_PROPERTIES.get_value( "delete_group", entity_reference=scene) # TODO: specific_delete_group = ASSET_SETTINGS_PROPERTIES.get_value("specific_delete_group", entity_reference=scene) set_up_rigging = ASSET_SETTINGS_PROPERTIES.get_value( "set_up_rigging", entity_reference=scene) interpolate_weights = ASSET_SETTINGS_PROPERTIES.get_value( "interpolate_weights", entity_reference=scene) # TODO: makeclothes_metadata = ASSET_SETTINGS_PROPERTIES.get_value("makeclothes_metadata", entity_reference=scene) add_subdiv_modifier = ASSET_SETTINGS_PROPERTIES.get_value( "add_subdiv_modifier", entity_reference=scene) subdiv_levels = ASSET_SETTINGS_PROPERTIES.get_value( "subdiv_levels", entity_reference=scene) blender_object = context.active_object rig = None basemesh = None if blender_object and not blender_object is None: if ObjectService.object_is_basemesh(blender_object): basemesh = blender_object else: basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives( blender_object, "Basemesh") rig = ObjectService.find_object_of_type_amongst_nearest_relatives( blender_object, "Skeleton") if fit_to_body and basemesh is None: self.report( {'ERROR'}, "Fit to body is enabled, but active object is not a base mesh") return {'FINISHED'} if delete_group and basemesh is None: self.report({ 'ERROR' }, "Set up delete group is enabled, but active object is not a base mesh" ) return {'FINISHED'} if interpolate_weights and basemesh is None: self.report({ 'ERROR' }, "interpolate weights is enabled, but active object is not a base mesh" ) return {'FINISHED'} if set_up_rigging and rig is None: self.report({ 'ERROR' }, "set up rigging is enabled, but could not find a rig to attach to" ) return {'FINISHED'} if not add_subdiv_modifier: subdiv_levels = 0 _LOG.debug("Will call add_mhclo_asset: (asset_type, material_type)", (self.object_type, self.material_type)) HumanService.add_mhclo_asset(self.filepath, basemesh, asset_type=self.object_type, subdiv_levels=subdiv_levels, material_type=self.material_type) self.report({'INFO'}, "Clothes were loaded") return {'FINISHED'}
def execute(self, context): from mpfb.ui.loadclothes.loadclothespanel import LOAD_CLOTHES_PROPERTIES # pylint: disable=C0415 scene = context.scene object_type = LOAD_CLOTHES_PROPERTIES.get_value("object_type", entity_reference=scene) material_type = LOAD_CLOTHES_PROPERTIES.get_value( "material_type", entity_reference=scene) fit_to_body = LOAD_CLOTHES_PROPERTIES.get_value("fit_to_body", entity_reference=scene) delete_group = LOAD_CLOTHES_PROPERTIES.get_value( "delete_group", entity_reference=scene) specific_delete_group = LOAD_CLOTHES_PROPERTIES.get_value( "specific_delete_group", entity_reference=scene) set_up_rigging = LOAD_CLOTHES_PROPERTIES.get_value( "set_up_rigging", entity_reference=scene) interpolate_weights = LOAD_CLOTHES_PROPERTIES.get_value( "interpolate_weights", entity_reference=scene) makeclothes_metadata = LOAD_CLOTHES_PROPERTIES.get_value( "makeclothes_metadata", entity_reference=scene) blender_object = context.active_object rig = None basemesh = None if blender_object and not blender_object is None: if ObjectService.object_is_basemesh(blender_object): basemesh = blender_object else: basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives( blender_object, "Basemesh") rig = ObjectService.find_object_of_type_amongst_nearest_relatives( blender_object, "Skeleton") if fit_to_body and basemesh is None: self.report( {'ERROR'}, "Fit to body is enabled, but active object is not a base mesh") return {'FINISHED'} if delete_group and basemesh is None: self.report({ 'ERROR' }, "Set up delete group is enabled, but active object is not a base mesh" ) return {'FINISHED'} if interpolate_weights and basemesh is None: self.report({ 'ERROR' }, "interpolate weights is enabled, but active object is not a base mesh" ) return {'FINISHED'} if set_up_rigging and rig is None: self.report({ 'ERROR' }, "set up rigging is enabled, but could not find a rig to attach to" ) return {'FINISHED'} mhclo = Mhclo() mhclo.load(self.filepath) # pylint: disable=E1101 clothes = mhclo.load_mesh(context) if not clothes or clothes is None: self.report({'ERROR'}, "failed to import the clothes mesh") return {'FINISHED'} GeneralObjectProperties.set_value("object_type", object_type, entity_reference=clothes) bpy.ops.object.shade_smooth() if not material_type == "PRINCIPLED": MaterialService.delete_all_materials(clothes) if material_type == "MAKESKIN" and not mhclo.material is None: makeskin_material = MakeSkinMaterial() makeskin_material.populate_from_mhmat(mhclo.material) name = os.path.basename(mhclo.material) blender_material = MaterialService.create_empty_material( name, clothes) makeskin_material.apply_node_tree(blender_material) if fit_to_body: ClothesService.fit_clothes_to_human(clothes, basemesh, mhclo) mhclo.set_scalings(context, basemesh) delete_name = "Delete" if delete_group: if specific_delete_group: delete_name = str(os.path.basename(self.filepath)) # pylint: disable=E1101 delete_name = delete_name.replace(".mhclo", "") delete_name = delete_name.replace(".MHCLO", "") delete_name = delete_name.replace(" ", "_") delete_name = "Delete." + delete_name ClothesService.update_delete_group(mhclo, basemesh, replace_delete_group=False, delete_group_name=delete_name) if set_up_rigging: clothes.location = (0.0, 0.0, 0.0) clothes.parent = rig modifier = clothes.modifiers.new("Armature", 'ARMATURE') modifier.object = rig if interpolate_weights: ClothesService.interpolate_weights(basemesh, clothes, rig, mhclo) if makeclothes_metadata: ClothesService.set_makeclothes_object_properties_from_mhclo( clothes, mhclo, delete_group_name=delete_name) self.report({'INFO'}, "Clothes were loaded") return {'FINISHED'}
def execute(self, context): _LOG.debug("filepath", self.filepath) from mpfb.ui.assetlibrary.assetsettingspanel import ASSET_SETTINGS_PROPERTIES # pylint: disable=C0415 scene = context.scene object_type = self.object_type material_type = "MAKESKIN" # TODO: some kind of operator argument fit_to_body = ASSET_SETTINGS_PROPERTIES.get_value("fit_to_body", entity_reference=scene) delete_group = ASSET_SETTINGS_PROPERTIES.get_value("delete_group", entity_reference=scene) specific_delete_group = ASSET_SETTINGS_PROPERTIES.get_value("specific_delete_group", entity_reference=scene) set_up_rigging = ASSET_SETTINGS_PROPERTIES.get_value("set_up_rigging", entity_reference=scene) interpolate_weights = ASSET_SETTINGS_PROPERTIES.get_value("interpolate_weights", entity_reference=scene) makeclothes_metadata = ASSET_SETTINGS_PROPERTIES.get_value("makeclothes_metadata", entity_reference=scene) add_subdiv_modifier = ASSET_SETTINGS_PROPERTIES.get_value("add_subdiv_modifier", entity_reference=scene) subdiv_levels = ASSET_SETTINGS_PROPERTIES.get_value("subdiv_levels", entity_reference=scene) mask_base_mesh = ASSET_SETTINGS_PROPERTIES.get_value("mask_base_mesh", entity_reference=scene) blender_object = context.active_object rig = None basemesh = None if blender_object and not blender_object is None: if ObjectService.object_is_basemesh(blender_object): basemesh = blender_object else: basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives(blender_object, "Basemesh") rig = ObjectService.find_object_of_type_amongst_nearest_relatives(blender_object, "Skeleton") if fit_to_body and basemesh is None: self.report({'ERROR'}, "Fit to body is enabled, but active object is not a base mesh") return {'FINISHED'} if delete_group and basemesh is None: self.report({'ERROR'}, "Set up delete group is enabled, but active object is not a base mesh") return {'FINISHED'} if interpolate_weights and basemesh is None: self.report({'ERROR'}, "interpolate weights is enabled, but active object is not a base mesh") return {'FINISHED'} if set_up_rigging and rig is None: self.report({'ERROR'}, "set up rigging is enabled, but could not find a rig to attach to") return {'FINISHED'} mhclo = Mhclo() mhclo.load(self.filepath) # pylint: disable=E1101 clothes = mhclo.load_mesh(context) if not clothes or clothes is None: self.report({'ERROR'}, "failed to import the proxy") return {'FINISHED'} asset_dir = os.path.basename(os.path.dirname(os.path.realpath(self.filepath))) asset_source = asset_dir + "/" + os.path.basename(self.filepath) GeneralObjectProperties.set_value("object_type", "Proxymeshes", entity_reference=clothes) GeneralObjectProperties.set_value("asset_source", asset_source, entity_reference=clothes) bpy.ops.object.shade_smooth() if not material_type == "PRINCIPLED": MaterialService.delete_all_materials(clothes) if material_type == "MAKESKIN" and not mhclo.material is None: makeskin_material = MakeSkinMaterial() makeskin_material.populate_from_mhmat(mhclo.material) name = os.path.basename(mhclo.material) blender_material = MaterialService.create_empty_material(name, clothes) makeskin_material.apply_node_tree(blender_material) if fit_to_body: ClothesService.fit_clothes_to_human(clothes, basemesh, mhclo) mhclo.set_scalings(context, basemesh) if set_up_rigging: clothes.location = (0.0, 0.0, 0.0) clothes.parent = rig modifier = clothes.modifiers.new("Armature", 'ARMATURE') modifier.object = rig if interpolate_weights: ClothesService.interpolate_weights(basemesh, clothes, rig, mhclo) if add_subdiv_modifier: modifier = clothes.modifiers.new("Subdivision", 'SUBSURF') modifier.levels = 0 modifier.render_levels = subdiv_levels if mask_base_mesh: modifier = basemesh.modifiers.new("Hide base mesh", 'MASK') modifier.vertex_group = "body" modifier.invert_vertex_group = True #if makeclothes_metadata: # ClothesService.set_makeclothes_object_properties_from_mhclo(clothes, mhclo, delete_group_name=delete_name) _LOG.debug("clothes, uuid", (clothes, mhclo.uuid)) if clothes and mhclo.uuid: GeneralObjectProperties.set_value("uuid", mhclo.uuid, entity_reference=clothes) _LOG.debug("Has extra vgroups", mhclo.uuid in ALL_EXTRA_GROUPS) if mhclo.uuid in ALL_EXTRA_GROUPS: for vgroup_name in ALL_EXTRA_GROUPS[mhclo.uuid].keys(): _LOG.debug("Will create vgroup", vgroup_name) vgroup = clothes.vertex_groups.new(name=vgroup_name) vgroup.add(ALL_EXTRA_GROUPS[mhclo.uuid][vgroup_name], 1.0, 'ADD') self.report({'INFO'}, "Proxy was loaded") return {'FINISHED'}