diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 index 34951eb..cc8d06e --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All changes will be documented here +# MB-Lab 1.8.0 + +## Requirements + +- Requires Blender 4.0.0 + + +## Added + +## Changed + +- MBLabSkin3 is a now based off of the 1.7.6 shader +- AutoUpdater is disabled + +## Bug Fixes + +- Fixed bugs in various files to make it work with Blender 4.0 +- + +## Known Issues + +- MB-Dev tools may contain bugs that are unknown at this time +- Importing BVH animation files is buggy +- Hair presets have the old PrincipledHairBSDF which will result in incorrect rendering +- Skin color and bump mapping change slightly when finalizing + # MB-Lab 1.7.8 ## Added diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 5ab76a7..4d22b1d --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ Character creation tool for Blender -## Blender 2.8 Support +## Blender 4.0 Support -MB-Lab has been developed to work with Blender 2.80 +MB-Lab has been developed to work with Blender 4.0 ## Contributors wanted! @@ -12,51 +12,33 @@ We are a small bunch of developers and artists but we always need more! MB-Lab's ## About -MB-Lab is a community developed and supported project based off ManuelBastioniLAB. - -If you're interested in helping this project Financially or to see behind the scenes information of this plugin's Development, Please support our [**Patreon**](https://www.patreon.com/mblab_development). +MB-Lab is a community developed project based off ManuelBastioniLAB. This fork is an attempt to keep this addon going forward as the original author is no longer developing ManuelBastioniLAB -# MB-Lab 1.7.8 +# MB-Lab 1.8.0 + +## Requirements + +- MB-Lab now requires Blender 4.0.0 + ## Added -- MB-Dev Character Development Framework introduced -- Hair Engine now adds hair shaders to Cycles and EEVEE +- ## Changed -- MBLabSkin2 uses Principled BSDF yet again -- Removed SSS scale group, replaced with Vector Math node -- Bump map added, Thickness map removed -- Modified skin oil maps -- Eyelash shader now has bump and gloss -- ExpressionEngine class now in it's own file -- Blush map converted to grayscale -- Modified Albedo maps -- Bump maps now 4k resolution -- Modified Freckle masks -- Modified Material Engine -- Changed lighting code -- MB-Lab has new version numbering scheme. Last number for dev purposes -- Sliders are now highlighted -- GUI update -- MBLab Pupil use Diffuse Node instead of Emission -- SSS Radius changed to more accurate values -- Freckles now include two colors +- ## Bug Fixes -- Poses don't show when user selects IK model -- Preserve Phenotype random function code fix -- Typo: Hands_Lenght, fixed in transformation and measurements JSON -- Typo: Various names in transformation files fixed -- Hair Dynamics bug fix for Nvidia GPU cards +- ## Known Issues - MB-Dev tools may contain bugs that are unknown at this time +- Importing BVH animation files is buggy +- Hair presets have the old PrincipledHairBSDF which will result in incorrect rendering ## ManuelBastioniLAB 1.6.1a diff --git a/__init__.py b/__init__.py old mode 100644 new mode 100755 index fe9ed41..4475172 --- a/__init__.py +++ b/__init__.py @@ -38,7 +38,7 @@ from bpy.app.handlers import persistent from bpy_extras.io_utils import ExportHelper, ImportHelper -from . import addon_updater_ops +#from . import addon_updater_ops from . import algorithms from . import animationengine from . import creation_tools_ops @@ -68,17 +68,17 @@ logger = logging.getLogger(__name__) # MB-Lab Blender Info -# 3/22 added new version number to MB-Lab, internal dev purposes +# bl_info = { "name": "MB-Lab", "author": "Manuel Bastioni, MB-Lab Community", - "version": (1, 7, 8, 50), - "blender": (2, 81, 16), + "version": (1, 8, 0), + "blender": (4, 0, 0), "location": "View3D > Tools > MB-Lab", - "description": "A complete lab for character creation", + "description": "Character creation tool based off of ManuelbastioniLAB", "warning": "", - 'wiki_url': "https://mb-lab-docs.readthedocs.io/en/latest/index.html", + 'doc_url': "https://mb-lab-docs.readthedocs.io/en/latest/index.html", 'tracker_url': 'https://github.com/animate1978/MB-Lab/issues', "category": "Characters" } @@ -2597,7 +2597,7 @@ def draw(self, context): icon_collapse = "DISCLOSURE_TRI_DOWN" box_info = self.layout.box() - box_info.label(text="https://www.mblab.dev") + #box_info.label(text="https://www.mblab.dev") if gui_status == "ERROR_SESSION": box_err = self.layout.box() @@ -2692,7 +2692,7 @@ def draw(self, context): box_asts_t.label(text="use the proxy fitting tool", icon='BLANK1') # Add Particle Hair box_asts = self.layout.box() - box_asts.label(text="Hair") + box_asts.label(text="Hair", icon='OUTLINER_OB_CURVES') box_asts.prop(scn, 'mblab_hair_color') box_asts_a = box_asts.column(align=True) box_asts_a.operator("mbast.particle_hair", icon='USER') @@ -3110,7 +3110,7 @@ def draw(self, context): icon_collapse = "DISCLOSURE_TRI_DOWN" box_general = self.layout.box() - box_general.label(text="https://www.mblab.dev") + #box_general.label(text="https://www.mblab.dev") #box_general.operator('mbcrea.button_for_tests', icon='BLENDER') box_tools = self.layout.box() @@ -3759,9 +3759,17 @@ def draw(self, context): else: b_m_c_c.prop(scn, "mbcrea_texture_sebum") if creation_tools_ops.get_content(key, "texture_roughness") != "": - b_m_c_c.label(text="Sebum : " + creation_tools_ops.get_content(key, "texture_sebum"), icon='CHECKMARK') + b_m_c_c.label(text="Roughness : " + creation_tools_ops.get_content(key, "texture_roughness"), icon='CHECKMARK') else: b_m_c_c.prop(scn, "mbcrea_texture_roughness") + if creation_tools_ops.get_content(key, "texture_thickness") != "": + b_m_c_c.label(text="Thickness : " + creation_tools_ops.get_content(key, "texture_thickness"), icon='CHECKMARK') + else: + b_m_c_c.prop(scn, "mbcrea_texture_thickness") + if creation_tools_ops.get_content(key, "texture_melanin") != "": + b_m_c_c.label(text="Melanin : " + creation_tools_ops.get_content(key, "texture_melanin"), icon='CHECKMARK') + else: + b_m_c_c.prop(scn, "mbcrea_texture_melanin") if creation_tools_ops.get_content(key, "texture_eyes") != "": b_m_c_c.label(text="Eyes : " + creation_tools_ops.get_content(key, "texture_eyes"), icon='CHECKMARK') else: @@ -3770,14 +3778,6 @@ def draw(self, context): b_m_c_c.label(text="Eyelash albedo : " + creation_tools_ops.get_content(key, "texture_eyelash_albedo"), icon='CHECKMARK') else: b_m_c_c.prop(scn, "mbcrea_texture_eyelash_albedo") - if creation_tools_ops.get_content(key, "texture_iris_color") != "": - b_m_c_c.label(text="Iris color : " + creation_tools_ops.get_content(key, "texture_iris_color"), icon='CHECKMARK') - else: - b_m_c_c.prop(scn, "mbcrea_texture_iris_color") - if creation_tools_ops.get_content(key, "texture_iris_bump") != "": - b_m_c_c.label(text="Iris bump : " + creation_tools_ops.get_content(key, "texture_iris_bump"), icon='CHECKMARK') - else: - b_m_c_c.prop(scn, "mbcrea_texture_iris_bump") if creation_tools_ops.get_content(key, "texture_sclera_color") != "": b_m_c_c.label(text="Sclera color : " + creation_tools_ops.get_content(key, "texture_sclera_color"), icon='CHECKMARK') else: @@ -4660,6 +4660,16 @@ def update_texture_items(self, context): name="Roughness", default=None) +bpy.types.Scene.mbcrea_texture_thickness = bpy.props.EnumProperty( + items=update_texture_items, + name="Thickness", + default=None) + +bpy.types.Scene.mbcrea_texture_melanin = bpy.props.EnumProperty( + items=update_texture_items, + name="Melanin", + default=None) + bpy.types.Scene.mbcrea_texture_frecklemask = bpy.props.EnumProperty( items=update_texture_items, name="Freckle mask", @@ -5141,13 +5151,13 @@ def execute(self, context): creation_tools_ops.add_content(key, "texture_frecklemask", decide_which(key, "texture_frecklemask", scn.mbcrea_texture_frecklemask)) creation_tools_ops.add_content(key, "texture_blush", decide_which(key, "texture_blush", scn.mbcrea_texture_blush)) creation_tools_ops.add_content(key, "texture_sebum", decide_which(key, "texture_sebum", scn.mbcrea_texture_sebum)) + creation_tools_ops.add_content(key, "texture_roughness", decide_which(key, "texture_roughness", scn.mbcrea_texture_roughness)) + creation_tools_ops.add_content(key, "texture_thickness", decide_which(key, "texture_thickness", scn.mbcrea_texture_thickness)) + creation_tools_ops.add_content(key, "texture_melanin", decide_which(key, "texture_melanin", scn.mbcrea_texture_melanin)) creation_tools_ops.add_content(key, "texture_lipmap", decide_which(key, "texture_lipmap", scn.mbcrea_texture_lipmap)) - creation_tools_ops.add_content(key, "texture_iris_color", decide_which(key, "texture_iris_color", scn.mbcrea_texture_iris_color)) - creation_tools_ops.add_content(key, "texture_iris_bump", decide_which(key, "texture_iris_bump", scn.mbcrea_texture_iris_bump)) creation_tools_ops.add_content(key, "texture_sclera_color", decide_which(key, "texture_sclera_color", scn.mbcrea_texture_sclera_color)) creation_tools_ops.add_content(key, "texture_translucent_mask", decide_which(key, "texture_translucent_mask", scn.mbcrea_texture_translucent_mask)) creation_tools_ops.add_content(key, "texture_sclera_mask", decide_which(key, "texture_sclera_mask", scn.mbcrea_texture_sclera_mask)) - creation_tools_ops.add_content(key, "texture_roughness", decide_which(key, "texture_roughness", scn.mbcrea_texture_roughness)) # The rest creation_tools_ops.add_content(key, "bounding_boxes_file", decide_which(key, "bounding_boxes_file", scn.mbcrea_bboxes_file)) creation_tools_ops.add_content(key, "joints_base_file", decide_which(key, "joints_base_file", scn.mbcrea_joints_base_file)) @@ -6835,4 +6845,4 @@ def unregister(): if __name__ == "__main__": register() -# +# \ No newline at end of file diff --git a/addon_updater_ops.py b/addon_updater_ops.py old mode 100644 new mode 100755 index e42b370..c5b9a61 --- a/addon_updater_ops.py +++ b/addon_updater_ops.py @@ -1353,16 +1353,16 @@ def register(bl_info): updater.private_token = None # "tokenstring" # Choose your own username, must match website (not needed for GitLab). - updater.user = "cgcookie" + updater.user = "animate1978" # Choose your own repository, must match git name for GitHUb and Bitbucket, # for GitLab use project ID (numbers only). - updater.repo = "blender-addon-updater" + updater.repo = "MB-Lab" # updater.addon = # define at top of module, MUST be done first # Website for manual addon download, optional but recommended to set. - updater.website = "https://github.com/CGCookie/blender-addon-updater/" + updater.website = "https://mb-lab-community.github.io/MB-Lab.github.io/" # Addon subfolder path. # "sample/path/to/addon" @@ -1391,7 +1391,7 @@ def register(bl_info): updater.backup_current = True # True by default # Sample ignore patterns for when creating backup of current during update. - updater.backup_ignore_patterns = ["__pycache__"] + updater.backup_ignore_patterns = [".git", "__pycache__", ".gitignore"] # Alternate example patterns: # updater.backup_ignore_patterns = [".git", "__pycache__", "*.bat", ".gitignore", "*.exe"] @@ -1405,7 +1405,7 @@ def register(bl_info): # update. If a pattern file is not found in new update, no action is taken # NOTE: This does NOT delete anything proactively, rather only defines what # is allowed to be overwritten during an update execution. - updater.overwrite_patterns = ["*.png", "*.jpg", "README.md", "LICENSE.txt"] + updater.overwrite_patterns = ["*.png","*.jpg","*.blend","*.json","README.md","LICENSE.txt"] # updater.overwrite_patterns = [] # other examples: # ["*"] means ALL files/folders will be overwritten by update, was the diff --git a/algorithms.py b/algorithms.py old mode 100644 new mode 100755 index e73855e..735cd21 --- a/algorithms.py +++ b/algorithms.py @@ -335,7 +335,7 @@ def check_mesh(obj): config_data = file_ops.get_configuration() model_config = config_data.get(obj.get("manuellab_id")) if not model_config: - logger.debug("check_obj %s model %s is not found", obj.name, obj.get("manuellab_id")) + logger.debug("check_obj %s model %s is not found", obj.name, obj.obj.get("manuellab_id")) return False templates = {} @@ -360,8 +360,8 @@ def looking_for_humanoid_obj(): Looking for a mesh that is OK for the lab """ logger.info("Looking for a humanoid object ...") - if bpy.app.version < (2, 81, 16): - msg = "Sorry, MB-Lab requires Blender 2.81.16 Minimum" + if bpy.app.version < (4, 0, 0): + msg = "Sorry, MB-Lab 1.8.0 requires Blender 4.0.0" logger.warning(msg) return("ERROR", msg) @@ -1145,7 +1145,7 @@ def remove_censors(): if char_name in("f_an01","f_an02","m_an01","m_an02"): swap_material("MBlab_generic", "MBLab_anime_skin",char_name) else: - swap_material("MBlab_generic", "MBLab_skin2",char_name) + swap_material("MBlab_generic", "MBLab_skin3",char_name) return None diff --git a/animationengine.py b/animationengine.py old mode 100644 new mode 100755 index bdad0ea..c9dfbd8 --- a/animationengine.py +++ b/animationengine.py @@ -1023,7 +1023,7 @@ def bake_animation(self, target_armat, source_armat): if source_armat.animation_data: source_action = source_armat.animation_data.action f_range = source_action.frame_range - +# BUG bpy.ops.nla.bake(frame_start=f_range[0], frame_end=f_range[1], only_selected=False, visual_keying=True, clear_constraints=False, use_current_action=True, bake_types={'POSE'}) self.remove_armature_constraints(target_armat) diff --git a/creation_tools_ops.py b/creation_tools_ops.py old mode 100644 new mode 100755 index cf3d8bb..cf25a41 --- a/creation_tools_ops.py +++ b/creation_tools_ops.py @@ -179,8 +179,8 @@ def add_content(key, key_in, content): "texture_nails_albedo": "", "texture_eyelash_albedo": "", "texture_frecklemask": "", "texture_blush": "", "texture_sebum": "", "texture_lipmap": "", - "texture_roughness": "", "texture_iris_color": "", - "texture_iris_bump": "", "texture_sclera_color": "", + "texture_roughness": "", "texture_melanin": "", + "texture_sclera_color": "", "texture_thickness":"", "texture_translucent_mask": "", "texture_sclera_mask": "", "morphs_extra_file": "", "shared_morphs_file": "", "shared_morphs_extra_file": "", "bounding_boxes_file": "", diff --git a/data/humanoid_library.blend b/data/humanoid_library.blend index 8c697fa..b54ad03 100644 Binary files a/data/humanoid_library.blend and b/data/humanoid_library.blend differ diff --git a/data/textures/human_female_melanin.png b/data/textures/human_female_melanin.png new file mode 100755 index 0000000..143357a Binary files /dev/null and b/data/textures/human_female_melanin.png differ diff --git a/data/textures/human_female_thickness.png b/data/textures/human_female_thickness.png new file mode 100644 index 0000000..dca30d7 Binary files /dev/null and b/data/textures/human_female_thickness.png differ diff --git a/data/textures/human_male_melanin.png b/data/textures/human_male_melanin.png new file mode 100755 index 0000000..19a8763 Binary files /dev/null and b/data/textures/human_male_melanin.png differ diff --git a/data/textures/human_male_thickness.png b/data/textures/human_male_thickness.png new file mode 100644 index 0000000..39f3282 Binary files /dev/null and b/data/textures/human_male_thickness.png differ diff --git a/hairengine.py b/hairengine.py old mode 100644 new mode 100755 index bca20f2..3d5a474 --- a/hairengine.py +++ b/hairengine.py @@ -94,7 +94,7 @@ def add_hair(hair_object, mat_name, style): p_sys.settings.root_radius = 0.03 p_sys.settings.count = 1000 p_sys.settings.hair_step = 5 - p_sys.settings.child_nbr = 20 + #p_sys.settings.child_nbr = 20 p_sys.settings.rendered_child_count = 20 p_sys.settings.child_length = 0.895 bpy.context.object.show_instancer_for_viewport = False @@ -216,7 +216,7 @@ def add_pHair(hair_object): p_sys.settings.root_radius = 0.03 p_sys.settings.count = 1000 p_sys.settings.hair_step = 5 - p_sys.settings.child_nbr = 20 + #p_sys.settings.child_nbr = 20 p_sys.settings.rendered_child_count = 20 p_sys.settings.child_length = 0.895 bpy.context.scene.render.hair_type = 'STRIP' diff --git a/humanoid.py b/humanoid.py old mode 100644 new mode 100755 index 3eb130d..3271950 --- a/humanoid.py +++ b/humanoid.py @@ -514,8 +514,6 @@ def remove_modifiers(self): if "armature" not in modf.name: obj.modifiers.remove(modf) -#TODO Move to file_ops.py - def save_body_displacement_texture(self, filepath): self.mat_engine.save_texture(filepath, "body_displ") @@ -523,7 +521,7 @@ def save_body_dermal_texture(self, filepath): self.mat_engine.save_texture(filepath, "body_derm") def save_all_textures(self, filepath): - targets = ["body_derm", "body_displ", "teeth_albedo", "eyes_albedo", "tongue_albedo", "freckle_mask", "blush", "sebum", "roughness", "lipmap", "iris_color", "iris_bump", "sclera_color", "translucent_mask", "sclera_mask", "body_bump"] + targets = ["body_derm", "body_displ", "teeth_albedo", "eyes_albedo", "tongue_albedo", "freckle_mask", "blush", "sebum", "roughness", "thickness","melanin", "lipmap", "iris_color", "iris_bump", "sclera_color", "translucent_mask", "sclera_mask", "body_bump"] for target in targets: dir_path = os.path.dirname(filepath) filename = os.path.basename(filepath) @@ -860,8 +858,9 @@ def update_character(self, category_name=None, mode="update_all"): self.sync_gui_according_measures() if update_armature: self.sk_engine.fit_joints() - if update_normals: - obj.data.calc_normals() + # + # if update_normals: + # obj.data.normal_update() if update_proxy: self.fit_proxy() @@ -1230,10 +1229,11 @@ def combine_morphings(self, modifier, refresh_only=False, add_vertices_to_update values = [] for prop in modifier.properties: val = self.character_data[prop] - if val > 1.0: - val = 1.0 - if val < 0: - val = 0 + + #if val > 1.0: + # val = 1.0 + #if val < 0: + # val = 0 val1 = algorithms.function_modifier_a(val) val2 = algorithms.function_modifier_b(val) values.append([val1, val2]) diff --git a/materialengine.py b/materialengine.py old mode 100644 new mode 100755 index cf2e71b..4678e52 --- a/materialengine.py +++ b/materialengine.py @@ -64,6 +64,8 @@ def __init__(self, obj_name, character_config): "blush": character_config["texture_blush"], "sebum": character_config["texture_sebum"], "roughness": character_config["texture_roughness"], + "thickness": character_config["texture_thickness"], + "melanin": character_config["texture_melanin"], "lipmap": character_config["texture_lipmap"], "iris_color": character_config["texture_iris_color"], "iris_bump": character_config["texture_iris_bump"], @@ -134,6 +136,12 @@ def texture_sebum_exist(self): def texture_roughness_exist(self): return os.path.isfile(self.image_file_paths["roughness"]) @property + def texture_melanin_exist(self): + return os.path.isfile(self.image_file_paths["melanin"]) + @property + def texture_thickness_exist(self): + return os.path.isfile(self.image_file_paths["thickness"]) + @property def texture_lipmap_exist(self): return os.path.isfile(self.image_file_paths["lipmap"]) @property @@ -246,6 +254,10 @@ def update_shaders(self, material_parameters=[], update_textures_nodes=True): self.assign_image_to_node(material.name, node.name, self.image_file_names["sebum"]) if "_skn_roughness" in node.name: self.assign_image_to_node(material.name, node.name, self.image_file_names["roughness"]) + if "_skn_melanin" in node.name: + self.assign_image_to_node(material.name, node.name, self.image_file_names["melanin"]) + if "_skn_thickness" in node.name: + self.assign_image_to_node(material.name, node.name, self.image_file_names["thickness"]) if "_skn_lipmap" in node.name: self.assign_image_to_node(material.name, node.name, self.image_file_names["lipmap"]) if "_iris_color" in node.name: diff --git a/preferences.py b/preferences.py old mode 100644 new mode 100755 index 783f62c..73eba2a --- a/preferences.py +++ b/preferences.py @@ -33,39 +33,40 @@ class MBPreferences(bpy.types.AddonPreferences): ''' bl_idname = __package__ # addon updater preferences - auto_check_update = bpy.props.BoolProperty( - name="Auto-check for Update", - description="If enabled, auto-check for updates using an interval", - default=False, - ) - updater_interval_months = bpy.props.IntProperty( - name='Months', - description="Number of months between checking for updates", - default=0, - min=0 - ) - updater_interval_days = bpy.props.IntProperty( - name='Days', - description="Number of days between checking for updates", - default=7, - min=0, - max=31 - ) - updater_interval_hours = bpy.props.IntProperty( - name='Hours', - description="Number of hours between checking for updates", - default=0, - min=0, - max=23 - ) - updater_interval_minutes = bpy.props.IntProperty( - name='Minutes', - description="Number of minutes between checking for updates", - default=0, - min=0, - max=59 - ) - +# Auto updater disabled for now +# auto_check_update = bpy.props.BoolProperty( +# name="Auto-check for Update", +# description="If enabled, auto-check for updates using an interval", +# default=False, +# ) +# updater_interval_months = bpy.props.IntProperty( +# name='Months', +# description="Number of months between checking for updates", +# default=0, +# min=0 +# ) +# updater_interval_days = bpy.props.IntProperty( +# name='Days', +# description="Number of days between checking for updates", +# default=7, +# min=0, +# max=31 +# ) +# updater_interval_hours = bpy.props.IntProperty( +# name='Hours', +# description="Number of hours between checking for updates", +# default=0, +# min=0, +# max=23 +# ) +# updater_interval_minutes = bpy.props.IntProperty( +# name='Minutes', +# description="Number of minutes between checking for updates", +# default=0, +# min=0, +# max=59 +# ) +# use_censors = bpy.props.BoolProperty( name='censors', description="Use censors to cover genitals and breasts", @@ -81,7 +82,7 @@ def draw(self, context): col.prop(self, 'use_censors') # updater draw function - addon_updater_ops.update_settings_ui(self, context) + # addon_updater_ops.update_settings_ui(self, context) # Alternate draw function, which is more condensed and can be # placed within an existing draw function. Only contains: