def execute(self, context): _LOG.debug("filepath", self.filepath) from mpfb.ui.assetlibrary.assetsettingspanel import ASSET_SETTINGS_PROPERTIES # pylint: disable=C0415 scene = context.scene skin_type = ASSET_SETTINGS_PROPERTIES.get_value("skin_type", entity_reference=scene) material_instances = ASSET_SETTINGS_PROPERTIES.get_value( "material_instances", entity_reference=scene) blender_object = context.active_object basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives( blender_object, "Basemesh") bodyproxy = ObjectService.find_object_of_type_amongst_nearest_relatives( blender_object, "Proxymeshes") HumanService.set_character_skin(self.filepath, basemesh, bodyproxy=bodyproxy, skin_type=skin_type, material_instances=material_instances) self.report({'INFO'}, "Skin was loaded") return {'FINISHED'}
def poll(cls, context): obj = context.active_object if not obj: return False if ObjectService.object_is_basemesh_or_body_proxy(obj): return True if ObjectService.object_is_skeleton(obj): return True return False
def _create_material_instances(self, importer): _LOG.enter() blender = importer["blender_entities"] ui = importer["settings_from_ui"] derived = importer["derived_settings"] if not ui["extra_vertex_groups"]: _LOG.debug("Skipping instances since we haven't created extra vertex groups") return if not ui["material_instances"]: _LOG.debug("Skipping instances since it is disabled") return if ui["skin_material_type"] == "PLAIN": _LOG.debug("Skipping instances since material type is PLAIN") return base_material = None bodyproxy = None if derived["has_body_proxy"] and "bodyproxy" in blender: bodyproxy = blender["bodyproxy"] basemesh = None if "basemesh" in blender: basemesh = blender["basemesh"] if not bodyproxy and not basemesh: _LOG.debug("Skipping instances since neither basemesh nor proxy is available") return if basemesh: base_material = MaterialService.get_material(basemesh) else: if bodyproxy: base_material = MaterialService.get_material(bodyproxy) if not base_material: _LOG.error("Skipping instances since no base material could be found. This should not have happened.") return for group_name in ["nipple", "lips", "fingernails", "toenails", "ears", "genitals"]: _LOG.debug("About to create material instance for", group_name) material_instance = base_material.copy() material_instance.name = derived["prefix"] + group_name if basemesh and ObjectService.has_vertex_group(basemesh, group_name): self._assign_material_instance(importer, basemesh, material_instance, group_name) if bodyproxy and ObjectService.has_vertex_group(bodyproxy, group_name): self._assign_material_instance(importer, bodyproxy, material_instance, group_name)
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 _populate_human_info_with_proxy_info(human_info, basemesh): proxy = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Proxymeshes") if not proxy: return asset_source = GeneralObjectProperties.get_value("asset_source", entity_reference=proxy) if not asset_source is None: human_info["proxy"] = str(asset_source).strip()
def _populate_human_info_with_eye_material_info(human_info, basemesh): eyes = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Eyes") if not eyes: return if not MaterialService.has_materials(eyes): human_info["eyes_material_type"] = "NONE" return material_settings = dict() _LOG.debug("material_slots", eyes.material_slots) slot = eyes.material_slots[0] material = slot.material group_node = NodeService.find_first_node_by_type_name(material.node_tree, "ShaderNodeGroup") if group_node: material_settings = NodeService.get_socket_default_values(group_node) if "IrisMinorColor" not in material_settings: # Material exists, but does not seem procedural. Assume it is a MAKESKIN material human_info["eyes_material_type"] = "MAKESKIN" else: human_info["eyes_material_type"] = "PROCEDURAL_EYES" human_info["eyes_material_settings"] = material_settings
def convert_to_rigify(self, armature_object): _LOG.enter() self._setup_spine(armature_object) self._setup_arms(armature_object) self._setup_legs(armature_object) self._setup_shoulders(armature_object) self._setup_head(armature_object) self._setup_fingers(armature_object) bpy.ops.object.mode_set(mode='OBJECT', toggle=False) armature_object.data.rigify_rig_basename = armature_object.name + ".rigify" if self.produce: bpy.ops.pose.rigify_generate() rigify_object = bpy.context.active_object rigify_object.show_in_front = True child_meshes = ObjectService.get_list_of_children(armature_object) for child_mesh in child_meshes: self._adjust_mesh_for_rigify(child_mesh, rigify_object) if not self.keep_meta: bpy.data.objects.remove(armature_object, do_unlink=True)
def execute(self, context): _LOG.enter() if context.object is None or context.object.type != 'ARMATURE': self.report({'ERROR'}, "Must have armature as active object") return {'FINISHED'} armature_object = context.object basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives( armature_object, mpfb_type_name="Basemesh") if basemesh is None: self.report({ 'ERROR' }, "Could not find related basemesh. It should have been parent or child of armature object." ) return {'FINISHED'} absolute_file_path = bpy.path.abspath(self.filepath) _LOG.debug("absolute_file_path", absolute_file_path) weights = RigService.get_weights(armature_object, basemesh) with open(absolute_file_path, "w") as json_file: json.dump(weights, json_file, indent=4, sort_keys=True) self.report({'INFO'}, "JSON file written to " + absolute_file_path) return {'FINISHED'}
def execute(self, context): _LOG.enter() if context.object is None or context.object.type != 'ARMATURE': self.report({'ERROR'}, "Must have armature as active object") return {'FINISHED'} armature_object = context.object basemesh = ObjectService.find_object_of_type_amongst_nearest_relatives(armature_object, mpfb_type_name="Basemesh") if basemesh is None: self.report({'ERROR'}, "Could not find related base mesh. It should have been parent or child of armature object.") return {'FINISHED'} rig = Rig.from_given_basemesh_and_armature_as_active_object(basemesh) _LOG.dump("final rig_definition", rig.rig_definition) unmatched_bone_names = rig.list_unmatched_bones() unmatched = len(unmatched_bone_names) if unmatched > 0: self.report({'WARNING'}, "There were " + str(unmatched) + " bones that could not be matched to cube or vertex") _LOG.warn("Unmatched bone names:", unmatched_bone_names) absolute_file_path = bpy.path.abspath(self.filepath) _LOG.debug("absolute_file_path", absolute_file_path) with open(absolute_file_path, "w") as json_file: json.dump(rig.rig_definition, json_file, indent=4, sort_keys=True) self.report({'INFO'}, "JSON file written to " + absolute_file_path) return {'FINISHED'}
def _set_eyes(human_info, basemesh): _LOG.enter() eyes = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Eyes") if not eyes: _LOG.debug("There are no eyes") return if not "eyes_material_type" in human_info or not human_info["eyes_material_type"]: _LOG.debug("Eyes material type not specified") return if human_info["eyes_material_type"] != "PROCEDURAL_EYES": _LOG.debug("Eyes material is not procedural") return if not "eyes_material_settings" in human_info or not human_info["eyes_material_settings"]: _LOG.debug("There are no eye material overrides, going with the default") return settings = human_info["eyes_material_settings"] _LOG.dump("Eye material overrides", settings) slot = eyes.material_slots[0] material = slot.material group_node = NodeService.find_first_node_by_type_name(material.node_tree, "ShaderNodeGroup") if group_node: material_settings = NodeService.get_socket_default_values(group_node) if "IrisMinorColor" in material_settings: _LOG.dump("will try to apply settings", settings) NodeService.set_socket_default_values(group_node, settings) else: _LOG.warn("Material group node did not have expected key -> not procedural eyes") else: _LOG.warn("Material had no group node -> not procedural eyes")
def _save_material(self, context, file_name): body = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Basemesh") if not body: body = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Proxymesh") if not body: self.report( {'ERROR'}, "Could not find basemesh or body proxy amongst nearest relatives") return {'FINISHED'} if not MaterialService.has_materials(body): self.report({'ERROR'}, "Body does not have a material") return {'FINISHED'} material_settings = dict() _LOG.debug("material_slots", body.material_slots) for slot in body.material_slots: material = slot.material group_node = NodeService.find_first_node_by_type_name( material.node_tree, "ShaderNodeGroup") if group_node: values = NodeService.get_socket_default_values(group_node) if "colorMixIn" in values: # This seems to be an enhanced skin material name = material.name if "." in name: (prefix, name) = name.split(".", 2) if "." in name: (name, number) = name.split(".", 2) material_settings[name] = values _LOG.dump("material_settings", material_settings) with open(file_name, "w") as json_file: json.dump(material_settings, json_file, indent=4, sort_keys=True) UiService.rebuild_enhanced_settings_panel_list() #UiService.rebuild_importer_panel_list() self.report({'INFO'}, "Presets were written to " + file_name) return {'FINISHED'}
def execute(self, context): scene = context.scene if not ObjectService.object_is_skeleton(context.active_object): self.report({'ERROR'}, "Must have armature object selected") return {'FINISHED'} from mpfb.ui.addrig.addrigpanel import ADD_RIG_PROPERTIES # pylint: disable=C0415 armature_object = context.active_object delete_after_generate = ADD_RIG_PROPERTIES.get_value( "delete_after_generate", entity_reference=scene) bpy.ops.pose.rigify_generate() rigify_object = context.active_object rigify_object.show_in_front = True _LOG.debug("rigify", rigify_object) for child in ObjectService.get_list_of_children(armature_object): child.parent = rigify_object for bone in armature_object.data.bones: name = bone.name if name in child.vertex_groups and not "teeth" in name: vertex_group = child.vertex_groups.get(name) vertex_group.name = "DEF-" + name for modifier in child.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 generated") return {'FINISHED'}
def _populate_human_info_with_bodyparts_info(human_info, basemesh): for bodypart in ["Eyes", "Eyelashes", "Eyebrows", "Tongue", "Teeth", "Hair"]: bodypart_obj = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, bodypart) _LOG.debug(bodypart, bodypart_obj) if not bodypart_obj is None: asset_source = GeneralObjectProperties.get_value("asset_source", entity_reference=bodypart_obj) if not asset_source is None: human_info[str(bodypart).lower()] = str(asset_source).strip()
def create_human(mask_helpers=True, detailed_helpers=True, extra_vertex_groups=True, feet_on_ground=True, scale=0.1, macro_detail_dict=None): exclude = [] if not detailed_helpers: groups = ObjectService.get_base_mesh_vertex_group_definition() for group_name in groups.keys(): if str(group_name).startswith("helper-") or str(group_name).startswith("joint-"): exclude.append(str(group_name)) if not extra_vertex_groups: # rather than extend in order to explicitly cast to str for group_name in BASEMESH_EXTRA_GROUPS.keys(): exclude.append(str(group_name)) exclude.extend(["Mid", "Right", "Left"]) basemesh = ObjectService.load_base_mesh(context=bpy.context, scale_factor=scale, load_vertex_groups=True, exclude_vertex_groups=exclude) if macro_detail_dict is None: macro_detail_dict = TargetService.get_default_macro_info_dict() for key in macro_detail_dict.keys(): name = str(key) if name != "race": HumanObjectProperties.set_value(name, macro_detail_dict[key], entity_reference=basemesh) for key in macro_detail_dict["race"].keys(): name = str(key) HumanObjectProperties.set_value(name, macro_detail_dict["race"][key], entity_reference=basemesh) TargetService.reapply_macro_details(basemesh) if mask_helpers: modifier = basemesh.modifiers.new("Hide helpers", 'MASK') modifier.vertex_group = "body" modifier.show_in_editmode = True modifier.show_on_cage = True HumanObjectProperties.set_value("is_human_project", True, entity_reference=basemesh) if feet_on_ground: lowest_point = ObjectService.get_lowest_point(basemesh) basemesh.location = (0.0, 0.0, abs(lowest_point)) bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) return basemesh
def _populate_human_info_with_rig_info(human_info, basemesh): armature_object = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Skeleton") if not armature_object is None: rig_type = RigService.identify_rig(armature_object) if rig_type is None or rig_type == "unkown": raise ValueError("Could not identify rig type. Custom rigs cannot be serialized.") if rig_type is None or rig_type == "rigify_generated": raise ValueError("Generated rigify rigs cannot be serialized. If you want to serialize the rig you have to do it before generating the final rig.") human_info["rig"] = rig_type
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 load_mesh(self, context): if self.obj_file == "" or not self.obj_file: raise ValueError('No obj file has been specified') _LOG.debug("Will try to load wavefront file", self.obj_file) obj = ObjectService.load_wavefront_file(self.obj_file, context) _LOG.debug("Loaded object:", obj) if obj is not None: self.clothes = obj else: raise IOError("Failed to load clothes mesh") return obj
def _assign_material_instance(self, importer, blender_object, material, group_name): _LOG.enter() _LOG.debug("blender_object, material, group_name", (blender_object, material, group_name)) if not ObjectService.has_vertex_group(blender_object, group_name): return ObjectService.activate_blender_object(blender_object) bpy.ops.object.mode_set(mode='OBJECT', toggle=False) blender_object.data.materials.append(material) slot_number = blender_object.material_slots.find(material.name) _LOG.dump("slot_number", slot_number) bpy.context.object.active_material_index = slot_number bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.vertex_group_set_active(group=group_name) bpy.ops.object.vertex_group_select() bpy.ops.object.material_slot_assign() bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
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 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 _populate_human_info_with_skin_info(human_info, basemesh): proxymesh = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Proxymeshes") bodyobject = basemesh if proxymesh and not proxymesh is None: bodyobject = proxymesh skin = HumanObjectProperties.get_value("material_source", entity_reference=bodyobject) if skin is None: skin = "" human_info["skin_mhmat"] = skin slots = bodyobject.material_slots if not slots or len(slots) < 1: return material = slots[0].material group_node = NodeService.find_first_node_by_type_name(material.node_tree, "ShaderNodeGroup") values = None if group_node: values = NodeService.get_socket_default_values(group_node) if values is None or not "colorMixIn" in values: human_info["skin_material_type"] = "MAKESKIN" return human_info["skin_material_type"] = "ENHANCED" if "SSS Color" in values: human_info["skin_material_type"] = "ENHANCED_SSS" for slot in slots: material = slot.material group_node = NodeService.find_first_node_by_type_name(material.node_tree, "ShaderNodeGroup") if group_node: values = NodeService.get_socket_default_values(group_node) if "colorMixIn" in values: # This seems to be an enhanced skin material name = material.name if "." in name: name = str(name).split(".", maxsplit=1)[1] if "." in name: name = str(name).split(".", maxsplit=1)[0] human_info["skin_material_settings"][name] = values
def _save_material(self, context, file_name): eyes = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Eyes") if not eyes: self.report({'ERROR'}, "Could not find eyes amongst nearest relatives") return {'FINISHED'} if not MaterialService.has_materials(eyes): self.report({'ERROR'}, "Eyes do not have a material") return {'FINISHED'} material_settings = dict() _LOG.debug("material_slots", eyes.material_slots) slot = eyes.material_slots[0] material = slot.material group_node = NodeService.find_first_node_by_type_name( material.node_tree, "ShaderNodeGroup") if group_node: material_settings = NodeService.get_socket_default_values(group_node) if "IrisMinorColor" not in material_settings: self.report({'ERROR'}, "Eyes do not seem to have procedural eyes material") return {'FINISHED'} else: self.report({'ERROR'}, "Eyes do not seem to have procedural eyes material") return {'FINISHED'} _LOG.dump("material_settings", material_settings) with open(file_name, "w") as json_file: json.dump(material_settings, json_file, indent=4, sort_keys=True) UiService.rebuild_eye_settings_panel_list() UiService.rebuild_importer_eye_settings_panel_list() self.report({'INFO'}, "Settings were written to " + 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 execute(self, context): _LOG.enter() if context.object is None: self.report({'ERROR'}, "Must have a selected object") return {'FINISHED'} name = ENHANCED_SETTINGS_PROPERTIES.get_value("available_settings", entity_reference=context) if not name: self.report({'ERROR'}, "Must select settings to load") return {'FINISHED'} file_name = LocationService.get_user_config("enhanced_settings." + name + ".json") if not os.path.exists(file_name): _LOG.error("Settings did not exist despite being in list:", file_name) self.report({'ERROR'}, "Settings did not exist!?") return {'FINISHED'} settings = dict() _LOG.debug("Will attempt to load", file_name) with open(file_name, "r") as json_file: settings = json.load(json_file) body = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Basemesh") if not body: body = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Proxymesh") if not body: self.report({ 'ERROR' }, "Could not find basemesh or body proxy amongst nearest relatives" ) return {'FINISHED'} if not MaterialService.has_materials(body): self.report({'ERROR'}, "Body does not have a material") return {'FINISHED'} _LOG.debug("material_slots", body.material_slots) for slot in body.material_slots: material = slot.material group_node = NodeService.find_first_node_by_type_name( material.node_tree, "ShaderNodeGroup") if group_node: values = NodeService.get_socket_default_values(group_node) if "colorMixIn" in values: # This seems to be an enhanced skin material name = material.name if "." in name: (prefix, name) = str(name).split(".", maxsplit=1) if "." in name: (name, number) = str(name).split(".", maxsplit=1) _LOG.debug("final name", name) if name in settings: _LOG.debug("will try to apply settings", settings[name]) NodeService.set_socket_default_values( group_node, settings[name]) self.report({'INFO'}, "Presets were loaded from " + file_name) return {'FINISHED'}
def poll(cls, context): if context.active_object is not None: return ObjectService.object_is_basemesh(context.active_object) return False
def execute(self, context): _LOG.enter() if context.object is None: self.report({'ERROR'}, "Must have a selected object") return {'FINISHED'} name = EYE_SETTINGS_PROPERTIES.get_value("available_settings", entity_reference=context) if not name: self.report({'ERROR'}, "Must select settings to load") return {'FINISHED'} file_name = LocationService.get_user_config("eye_settings." + name + ".json") if not os.path.exists(file_name): _LOG.error("Settings did not exist despite being in list:", file_name) self.report({'ERROR'}, "Settings did not exist!?") return {'FINISHED'} settings = dict() _LOG.debug("Will attempt to load", file_name) with open(file_name, "r") as json_file: settings = json.load(json_file) eyes = ObjectService.find_object_of_type_amongst_nearest_relatives( context.object, "Eyes") if not eyes: self.report({'ERROR'}, "Could not find eyes amongst nearest relatives") return {'FINISHED'} if not MaterialService.has_materials(eyes): self.report({'ERROR'}, "Eyes do not have a material") return {'FINISHED'} _LOG.debug("material_slots", eyes.material_slots) slot = eyes.material_slots[0] material = slot.material group_node = NodeService.find_first_node_by_type_name( material.node_tree, "ShaderNodeGroup") if group_node: material_settings = NodeService.get_socket_default_values( group_node) if "IrisMinorColor" in material_settings: _LOG.debug("will try to apply settings", settings) NodeService.set_socket_default_values(group_node, settings) else: self.report( {'ERROR'}, "Eyes do not seem to have procedural eyes material") return {'FINISHED'} else: self.report({'ERROR'}, "Eyes do not seem to have procedural eyes material") return {'FINISHED'} self.report({'INFO'}, "Settings were loaded from " + file_name) return {'FINISHED'}
def poll(cls, context): if context.active_object is not None: return ObjectService.object_is_skeleton(context.active_object) return False
def set_character_skin(mhmat_file, basemesh, bodyproxy=None, skin_type="ENHANCED_SSS", material_instances=True, slot_overrides=None): if bodyproxy is None: bodyproxy = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Proxymeshes") material_source = os.path.basename(os.path.dirname(mhmat_file)) + "/" + os.path.basename(mhmat_file) _LOG.debug("material_source", material_source) HumanObjectProperties.set_value("material_source", material_source, entity_reference=basemesh) if not bodyproxy is None: HumanObjectProperties.set_value("material_source", material_source, entity_reference=bodyproxy) MaterialService.delete_all_materials(basemesh) if bodyproxy: MaterialService.delete_all_materials(bodyproxy) name = basemesh.name if not str(name).endswith(".body"): name = name + ".body" if skin_type == "MAKESKIN": makeskin_material = MakeSkinMaterial() makeskin_material.populate_from_mhmat(mhmat_file) blender_material = MaterialService.create_empty_material(name, basemesh) makeskin_material.apply_node_tree(blender_material) if skin_type in ["ENHANCED", "ENHANCED_SSS"]: presets = dict() presets["skin_material_type"] = skin_type scale_name = "METER" scale_factor = GeneralObjectProperties.get_value("scale_factor", entity_reference=basemesh) if scale_factor > 0.9: scale_name = "DECIMETER" if scale_factor > 9: scale_name = "CENTIMETER" presets["scale_factor"] = scale_name enhanced_material = EnhancedSkinMaterial(presets) enhanced_material.populate_from_mhmat(mhmat_file) blender_material = MaterialService.create_empty_material(name, basemesh) enhanced_material.apply_node_tree(blender_material) if material_instances: _LOG.debug("Will now attempt to create material slots for", (basemesh, bodyproxy)) MaterialService.create_and_assign_material_slots(basemesh, bodyproxy) file_name = LocationService.get_user_config("enhanced_settings.default.json") settings = dict() _LOG.debug("Will attempt to load", file_name) with open(file_name, "r") as json_file: settings = json.load(json_file) _LOG.dump("Settings before overrides", settings) _LOG.dump("Overrides", slot_overrides) if not slot_overrides is None: for slot_name in slot_overrides.keys(): _LOG.debug("Reading overrides for slot", slot_name) if not slot_name in settings: settings[slot_name] = dict() for key_name in slot_overrides[slot_name].keys(): _LOG.dump("Reading overrides for slot key", (slot_name, key_name, slot_overrides[slot_name][key_name])) settings[slot_name][key_name] = slot_overrides[slot_name][key_name] _LOG.dump("Settings after overrides", settings) for slot in basemesh.material_slots: material = slot.material group_node = NodeService.find_first_node_by_type_name(material.node_tree, "ShaderNodeGroup") if group_node: values = NodeService.get_socket_default_values(group_node) if "colorMixIn" in values: # This seems to be an enhanced skin material name = material.name _LOG.debug("Material name", name) if "." in name: name = str(name).split(".", maxsplit=1)[1] if "." in name: name = str(name).split(".", maxsplit=1)[0] _LOG.debug("final name", name) if name in settings: _LOG.debug("will try to apply settings", settings[name]) NodeService.set_socket_default_values(group_node, settings[name])
def add_mhclo_asset(mhclo_file, basemesh, asset_type="Clothes", subdiv_levels=1, material_type="MAKESKIN"): mhclo = Mhclo() mhclo.load(mhclo_file) # pylint: disable=E1101 clothes = mhclo.load_mesh(bpy.context) clothes.location = (0.0, 0.0, 0.0) if not clothes or clothes is None: raise IOError("failed to import the clothes mesh: object was None after import") afn = os.path.abspath(mhclo_file) asset_source = os.path.basename(os.path.dirname(afn)) + "/" + os.path.basename(afn) GeneralObjectProperties.set_value("asset_source", asset_source, entity_reference=clothes) atype = str(asset_type).lower().capitalize() GeneralObjectProperties.set_value("object_type", atype, entity_reference=clothes) bpy.ops.object.shade_smooth() name = basemesh.name if "." in name: name = str(name).split(".")[0] name = name + "." + str(os.path.basename(mhclo_file)).replace(".mhclo", "").replace(".proxy", "") clothes.name = name _LOG.debug("Given name (basemesh, variable, clothes)", (basemesh.name, name, clothes.name)) colors = MaterialService.get_diffuse_colors() _LOG.dump("Colors, atype, exists, mhclo.material, material_type", (colors, atype, atype in colors, mhclo.material, material_type)) color = (0.8, 0.8, 0.8, 1.0) if atype in colors: color = colors[atype] if not mhclo.material: _LOG.debug("Material is not set in mhclo") if not mhclo.material is None and material_type == "MAKESKIN": _LOG.debug("Setting up MAKESKIN material", mhclo.material) MaterialService.delete_all_materials(clothes) makeskin_material = MakeSkinMaterial() makeskin_material.populate_from_mhmat(mhclo.material) blender_material = MaterialService.create_empty_material(name, clothes) makeskin_material.apply_node_tree(blender_material) blender_material.diffuse_color = color if material_type == "PROCEDURAL_EYES": MaterialService.delete_all_materials(clothes) _LOG.debug("Setting up procedural eyes") tree_dir = LocationService.get_mpfb_data("node_trees") json_file_name = os.path.join(tree_dir, "procedural_eyes.json") with open(json_file_name, "r") as json_file: node_tree_dict = json.load(json_file) _LOG.dump("procedural_eyes", node_tree_dict) blender_material = MaterialService.create_empty_material(name, clothes) NodeService.apply_node_tree_from_dict(blender_material.node_tree, node_tree_dict, True) blender_material.blend_method = "BLEND" blender_material.show_transparent_back = True blender_material.diffuse_color = color ClothesService.fit_clothes_to_human(clothes, basemesh, mhclo) mhclo.set_scalings(bpy.context, basemesh) delete_name = str(os.path.basename(mhclo_file)) # 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) rig = ObjectService.find_object_of_type_amongst_nearest_relatives(basemesh, "Skeleton") if rig: clothes.parent = rig modifier = clothes.modifiers.new("Armature", 'ARMATURE') modifier.object = rig ClothesService.interpolate_weights(basemesh, clothes, rig, mhclo) else: clothes.parent = basemesh ClothesService.set_makeclothes_object_properties_from_mhclo(clothes, mhclo, delete_group_name=delete_name) if subdiv_levels > 0: modifier = clothes.modifiers.new("Subdivision", 'SUBSURF') modifier.levels = 0 modifier.render_levels = subdiv_levels if mhclo.uuid: GeneralObjectProperties.set_value("uuid", mhclo.uuid, entity_reference=clothes) return clothes
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)