Exemplo n.º 1
0
    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'}
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
    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'}
Exemplo n.º 5
0
 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()
Exemplo n.º 6
0
    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
Exemplo n.º 7
0
    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)
Exemplo n.º 8
0
    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'}
Exemplo n.º 9
0
    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'}
Exemplo n.º 10
0
    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")
Exemplo n.º 11
0
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'}
Exemplo n.º 12
0
    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'}
Exemplo n.º 13
0
 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()
Exemplo n.º 14
0
    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
Exemplo n.º 15
0
 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
Exemplo n.º 16
0
    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'}
Exemplo n.º 17
0
    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
Exemplo n.º 18
0
    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)
Exemplo n.º 19
0
    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)
Exemplo n.º 20
0
    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)
Exemplo n.º 21
0
    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
Exemplo n.º 22
0
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'}
Exemplo n.º 23
0
    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'}
Exemplo n.º 24
0
    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'}
Exemplo n.º 25
0
 def poll(cls, context):
     if context.active_object is not None:
         return ObjectService.object_is_basemesh(context.active_object)
     return False
Exemplo n.º 26
0
    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'}
Exemplo n.º 27
0
 def poll(cls, context):
     if context.active_object is not None:
         return ObjectService.object_is_skeleton(context.active_object)
     return False
Exemplo n.º 28
0
    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])
Exemplo n.º 29
0
    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
Exemplo n.º 30
0
    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)