예제 #1
0
def post_load(scene):
    # get Blender Tools version from last blend file load
    last_load_bt_ver = _get_scs_globals().last_load_bt_version

    scs_roots = None
    """
    Applies fixes for v0.6 or less:
    1. fixes reflection textures tga's for tobjs as TOBJ load is now supported and unlock that textures
    2. calls update on all set textures to correct paths for them
    3. tries to fix active shader preset name for materials, because of new flavor system
    """
    if _info_utils.cmp_ver_str(last_load_bt_ver, "0.6") <= 0:

        print("INFO\t-  Applying fixes for version <= 0.6")

        for material in bpy.data.materials:

            # ignore materials not related to blender tools
            if material.scs_props.mat_effect_name == "":
                continue

            for tex_type in material.scs_props.get_texture_types().keys():

                texture_attr_str = "shader_texture_" + tex_type
                if texture_attr_str in material.scs_props.keys():

                    # 1. fix reflection textures
                    if tex_type == "reflection":

                        is_building_ref = material.scs_props[
                            texture_attr_str].endswith("/bulding_ref.tga")
                        is_generic_s = material.scs_props[
                            texture_attr_str].endswith(
                                "material/environment/generic_s.tga")
                        is_glass_interior = material.scs_props.active_shader_preset_name == "glass - interior"
                        is_dif_spec_weight_add_env = material.scs_props.active_shader_preset_name == "dif.spec.weight.add.env"
                        is_truckpaint = material.scs_props.active_shader_preset_name.startswith(
                            "truckpaint")

                        # fix paths
                        if is_building_ref:
                            material.scs_props[
                                texture_attr_str] = material.scs_props[
                                    texture_attr_str][:-4]
                            material.scs_props[texture_attr_str +
                                               "_locked"] = False
                        elif is_generic_s:
                            if is_glass_interior:
                                material.scs_props[
                                    texture_attr_str] = "//material/environment/interior_reflection"
                            elif is_dif_spec_weight_add_env:
                                material.scs_props[
                                    texture_attr_str] = "//material/environment/generic_reflection"
                            else:
                                material.scs_props[
                                    texture_attr_str] = "//material/environment/vehicle_reflection"

                            # unlock reflection textures everywhere except on truckpaint shader
                            if not is_truckpaint:
                                material.scs_props[texture_attr_str +
                                                   "_locked"] = False

                        # acquire roots on demand only once
                        scs_roots = _object_utils.gather_scs_roots(
                            bpy.data.objects) if not scs_roots else scs_roots

                        # propagate reflection texture change on all of the looks.
                        # NOTE: We can afford write through because old BT had all reflection textures locked
                        # meaning user had to use same texture on all looks
                        # NOTE#2: Printouts like:
                        # "Look with ID: X doesn't have entry for material 'X' in SCS Root 'X',
                        #  property 'shader_texture_reflection' won't be updated!"
                        # are expected here, because we don't use any safety check,
                        # if material is used on the mesh objects inside scs root
                        for scs_root in scs_roots:
                            _looks.write_through(scs_root, material,
                                                 texture_attr_str)

                    # 2. trigger update function for path reload and reload of possible missing textures
                    update_func = getattr(material.scs_props,
                                          "update_" + texture_attr_str, None)
                    if update_func:
                        update_func(material)

            # ignore already properly set materials
            if material.scs_props.active_shader_preset_name in _get_shader_presets_inventory(
            ):
                continue

            # 3. try to recover "active_shader_preset_name" from none flavor times Blender Tools
            material_textures = {}
            if "scs_shader_attributes" in material and "textures" in material[
                    "scs_shader_attributes"]:
                for texture in material["scs_shader_attributes"][
                        "textures"].values():
                    tex_id = texture["Tag"].split(":")[1]
                    tex_value = texture["Value"]
                    material_textures[tex_id] = tex_value

            (preset_name, preset_section) = _material_utils.find_preset(
                material.scs_props.mat_effect_name, material_textures)
            if preset_name:
                material.scs_props.active_shader_preset_name = preset_name

                # acquire roots on demand only once
                scs_roots = _object_utils.gather_scs_roots(
                    bpy.data.objects) if not scs_roots else scs_roots

                # make sure to fix active preset shader name in all looks
                # NOTE: Printouts like:
                # "Look with ID: X doesn't have entry for material 'X' in SCS Root 'X',
                #  property 'active_shader_preset_name' won't be updated!"
                # are expected here, because we don't use any safety check,
                # if material is used on the mesh objects inside scs root
                for scs_root in scs_roots:
                    _looks.write_through(scs_root, material,
                                         "active_shader_preset_name")

    # as last update "last load" Blender Tools version to current
    _get_scs_globals().last_load_bt_version = get_tools_version()
예제 #2
0
def _create_scs_root_object(name, loaded_variants, loaded_looks, mats_info,
                            objects, locators, armature):
    """Creates an 'SCS Root Object' (Empty Object) for currently imported
    'SCS Game Object' and parent all import content to it.

    :param name:
    :type name: str
    :param loaded_variants: X
    :type loaded_variants: list
    :param loaded_looks: X
    :type loaded_looks: list
    :param mats_info: list of material info, one material info consists of list: [ blend_mat_name, mat_effect, original_mat_alias ]
    :type mats_info: list of list
    :param objects: X
    :type objects: list
    :param locators: X
    :type locators: list
    :param armature: Armature Object
    :type armature: bpy.types.Object
    :return: SCS Root Object
    :rtype: bpy.types.Object
    """

    context = bpy.context

    # MAKE THE 'SCS ROOT OBJECT' NAME UNIQUE
    name = _name_utils.get_unique(name, bpy.data.objects)

    # CREATE EMPTY OBJECT & MAKE A PROPER SETTINGS TO THE 'SCS Game Object' OBJECT
    scs_root_object = bpy.data.objects.new(name, None)
    bpy.context.view_layer.active_layer_collection.collection.objects.link(
        scs_root_object)
    bpy.context.view_layer.objects.active = scs_root_object
    scs_root_object.scs_props.scs_root_object_export_enabled = True
    scs_root_object.scs_props.empty_object_type = 'SCS_Root'

    # print('LOD.pos: %s' % str(scs_root_object.location))
    # print('CUR.pos: %s' % str(context.space_data.cursor_location))

    # PARENTING
    bpy.ops.object.select_all(action='DESELECT')

    if armature:

        # if armature is present we can specify our game object as animated
        scs_root_object.scs_props.scs_root_animated = "anim"

        # print('ARM.pos: %s' % str(armature.location))
        armature.select_set(True)
        armature.scs_props.parent_identity = scs_root_object.name

    for obj in objects:
        # print('OBJ.pos: %s' % str(object.location))
        obj.select_set(True)
        obj.scs_props.parent_identity = scs_root_object.name

    for obj in locators:
        obj.select_set(True)
        obj.scs_props.parent_identity = scs_root_object.name

    bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)
    bpy.ops.object.parent_clear(type='CLEAR_INVERSE')

    # LOCATION
    scs_root_object.location = context.scene.cursor.location

    # MAKE ONLY 'SCS GAME OBJECT' SELECTED
    bpy.ops.object.select_all(action='DESELECT')
    scs_root_object.select_set(True)
    context.view_layer.objects.active = scs_root_object

    # MAKE PART RECORD
    part_inventory = scs_root_object.scs_object_part_inventory
    parts_dict = _object_utils.collect_parts_on_root(scs_root_object)
    for part_name in parts_dict:
        _inventory.add_item(part_inventory, part_name)

    # MAKE VARIANT RECORD
    variant_inventory = scs_root_object.scs_object_variant_inventory
    for variant_i, variant_record in enumerate(loaded_variants):
        variant_name = variant_record[0]
        variantparts = variant_record[1]

        variant = _inventory.add_item(variant_inventory, variant_name)

        # for every variant create all of the part entries and mark them included properly
        for part in part_inventory:

            part = _inventory.add_item(variant.parts, part.name)
            if part.name in variantparts:
                part.include = True

                # cleanup generated terrain points vertex layers by variant
                for obj in parts_dict[part.name]:

                    if obj.type != "MESH":
                        continue

                    vg_to_delete = []
                    accepted_vg_nodes = {}
                    for vertex_group in obj.vertex_groups:

                        # ignore any vertex group which isn't from terrain points
                        # (others might come from skinning)
                        if _OP_consts.TerrainPoints.vg_name_prefix not in vertex_group.name:
                            continue

                        # ignore already fixed vertex group
                        if vertex_group.name.startswith(
                                _OP_consts.TerrainPoints.vg_name_prefix):
                            continue

                        # get variant index from first 6 chars -> check PIM importer for more info
                        vg_var_index = int(vertex_group.name[:6])
                        # ignore other variant vertex groups and add them to delete list
                        if vg_var_index >= 0 and vg_var_index != variant_i:
                            vg_to_delete.append(vertex_group)
                            continue

                        # finally remove variant prefixing name if variant is not defined (-1)
                        # or index matches current one
                        vertex_group.name = vertex_group.name[6:]

                        # log accepted node index for identifying which vertex groups
                        # really have to be deleted
                        accepted_vg_nodes[vertex_group.name[-1]] = 1

                    # cleanup possible duplicates for the same node
                    # because one object anyway can not have terrain points vertex groups for multiple variants
                    while len(vg_to_delete) > 0 and len(accepted_vg_nodes) > 0:
                        curr_vg = vg_to_delete.pop()

                        # extra caution step where group can be deleted
                        # only if one of vertex groups for this node was accepted
                        if curr_vg.name[-1] in accepted_vg_nodes:
                            obj.vertex_groups.remove(curr_vg)

            else:
                part.include = False

    # MAKE LOOK RECORDS
    for look_i, look in enumerate(loaded_looks):

        look_name = look[0]
        look_mat_settings = look[1]

        # setup all the materials. NOTE: They should be already created by PIM import.
        for mat_info in mats_info:
            mat = bpy.data.materials[mat_info[0]]
            if mat_info[2] in look_mat_settings:

                # extract imported shader data
                material_effect, material_attributes, material_textures, material_section = _get_shader_data(
                    look_mat_settings[mat_info[2]])

                # try to find suitable preset
                (preset_name, preset_section) = _material_utils.find_preset(
                    material_effect, material_textures)

                # we don't support effect mismatch between looks, even if game works with it, somehow.
                # most probably imported model is result of third party software, thus let user know and skip look for this material
                if look_i != 0 and material_effect != mat.scs_props.mat_effect_name:
                    lprint(
                        "E Look %r skipped on material %r, mismatched material effect: %r but should be %r.",
                        (look_name, mat.name, material_effect,
                         mat.scs_props.mat_effect_name))
                    continue

                # preset name is found & shader data are compatible with found preset
                if preset_name and _are_shader_data_compatible(
                        preset_section, material_attributes, material_textures,
                        mat_info[0]):

                    mat.scs_props.active_shader_preset_name = preset_name

                    if preset_section:

                        preset_effect = preset_section.get_prop_value("Effect")
                        mat.scs_props.mat_effect_name = preset_effect

                        if look_i == 0:
                            # apply default shader settings
                            _material_utils.set_shader_data_to_material(
                                mat, preset_section, is_import=True)

                        # reapply settings from material
                        _material_utils.set_shader_data_to_material(
                            mat,
                            material_section,
                            is_import=True,
                            override_back_data=False)

                        lprint("D Using shader preset on material %r.",
                               (mat.name, ))

                    else:
                        print('''NO "preset_section"! (Shouldn't happen!)''')

                else:  # import shader directly from material and mark it as imported

                    mat.scs_props.active_shader_preset_name = "<imported>"
                    _material_utils.set_shader_data_to_material(
                        mat, material_section, is_import=True)

                    lprint(
                        "W Using imported shader on material %r, effect: %r.",
                        (mat.name, mat.scs_props.mat_effect_name))

                if look_i == len(loaded_looks) - 1:
                    # delete not needed data on material
                    if "scs_tex_aliases" in mat:
                        del mat["scs_tex_aliases"]

        # create new look entry on root
        bpy.ops.object.scs_tools_add_look(look_name=look_name,
                                          instant_apply=False)

    # apply first look after everything is done
    scs_root_object.scs_props.active_scs_look = 0

    # fix scs root children objects count so it won't trigger persistent cycle
    scs_root_object.scs_cached_num_children = len(scs_root_object.children)

    return scs_root_object
예제 #3
0
        def execute(self, context):

            # find group names created by Blender Tools with
            # dynamic importing of all modules from "internals/shaders" folder
            # and checking if module has "get_node_group" functions which indicates that
            # module creates node group
            groups_to_remove = [
                "AddEnvGroup",  # from v0.6
                "FresnelGroup",  # from v0.6
                "LampmaskMixerGroup",  # from v0.6
                "ReflectionNormalGroup",  # from v0.6
            ]
            for root, dirs, files in os.walk(
                    _path_utils.get_addon_installation_paths()[0] + os.sep +
                    "internals/shaders"):

                for file in files:

                    if not file.endswith(".py"):
                        continue

                    module = SourceFileLoader(root + os.sep + file, root +
                                              os.sep + file).load_module()
                    if "get_node_group" in dir(module):

                        ng = module.get_node_group()
                        groups_to_remove.append(ng.name)

            # 1. clear nodes on materials
            for mat in bpy.data.materials:

                if not mat.node_tree:
                    continue

                # also check none blender tools materials just to remove possible nodes usage of our groups
                if mat.scs_props.active_shader_preset_name == "<none>":

                    nodes_to_remove = []

                    # check for possible leftover usage of our node groups
                    for node in mat.node_tree.nodes:

                        # filter out nodes which are not node group and node groups without node tree
                        if node.type != "GROUP" or not node.node_tree:
                            continue

                        if node.node_tree.name in groups_to_remove:
                            nodes_to_remove.append(node.node_tree.name)

                    # remove possible leftover used node group nodes
                    for node_name in nodes_to_remove:
                        mat.node_tree.nodes.remove(
                            mat.node_tree.nodes[node_name])

                    continue

                mat.node_tree.nodes.clear()

            # 2. clear nodes on node groups
            for ng_name in groups_to_remove:

                if ng_name not in bpy.data.node_groups:
                    continue

                ng = bpy.data.node_groups[ng_name]
                ng.nodes.clear()

            # 3. remove node groups from blender data blocks
            for ng_name in groups_to_remove:

                if ng_name not in bpy.data.node_groups:
                    continue

                bpy.data.node_groups.remove(bpy.data.node_groups[ng_name],
                                            do_unlink=True)

            # 4. finally set preset to material again, which will update nodes and possible input interface changes
            scs_roots = _object_utils.gather_scs_roots(bpy.data.objects)
            for mat in bpy.data.materials:

                # ignore none blender tools materials
                if mat.scs_props.active_shader_preset_name == "<none>":
                    continue

                material_textures = {}
                if "scs_shader_attributes" in mat and "textures" in mat[
                        "scs_shader_attributes"]:
                    for texture in mat["scs_shader_attributes"][
                            "textures"].values():
                        tex_id = texture["Tag"].split(":")[1]
                        tex_value = texture["Value"]
                        material_textures[tex_id] = tex_value

                (preset_name, preset_section) = _material_utils.find_preset(
                    mat.scs_props.mat_effect_name, material_textures)

                if preset_section:
                    _material_utils.set_shader_data_to_material(
                        mat, preset_section)

                    # sync shader types on all scs roots by updating looks on them
                    # without this call we might end up with outdated looks raising errors once user will switch to them
                    for scs_root in scs_roots:
                        _looks.update_look_from_material(scs_root, mat, True)

            return {'FINISHED'}
예제 #4
0
def _create_scs_root_object(name, loaded_variants, loaded_looks, mats_info, objects, locators, armature):
    """Creates an 'SCS Root Object' (Empty Object) for currently imported
    'SCS Game Object' and parent all import content to it.

    :param name:
    :type name: str
    :param loaded_variants: X
    :type loaded_variants: list
    :param loaded_looks: X
    :type loaded_looks: list
    :param mats_info: list of material info, one material info consists of list: [ blend_mat_name, mat_effect, original_mat_alias ]
    :type mats_info: list of list
    :param objects: X
    :type objects: list
    :param locators: X
    :type locators: list
    :param armature: Armature Object
    :type armature: bpy.types.Object
    :return: SCS Root Object
    :rtype: bpy.types.Object
    """

    context = bpy.context

    # MAKE THE 'SCS ROOT OBJECT' NAME UNIQUE
    name = _name_utils.get_unique(name, bpy.data.objects)

    # CREATE EMPTY OBJECT
    bpy.ops.object.empty_add(
        view_align=False,
        location=(0.0, 0.0, 0.0),
        # rotation=rot,
    )  # , layers=(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,
    # False, False))

    # MAKE A PROPER SETTINGS TO THE 'SCS Game Object' OBJECT
    scs_root_object = context.active_object
    scs_root_object.name = name
    scs_root_object.scs_props.scs_root_object_export_enabled = True
    scs_root_object.scs_props.empty_object_type = 'SCS_Root'

    # print('LOD.pos: %s' % str(scs_root_object.location))
    # print('CUR.pos: %s' % str(context.space_data.cursor_location))

    # PARENTING
    if armature:

        # if armature is present we can specify our game object as animated
        scs_root_object.scs_props.scs_root_animated = "anim"

        # print('ARM.pos: %s' % str(armature.location))
        bpy.ops.object.select_all(action='DESELECT')
        armature.select = True
        bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)
        armature.scs_props.parent_identity = scs_root_object.name

    for obj in objects:
        # print('OBJ.pos: %s' % str(object.location))
        bpy.ops.object.select_all(action='DESELECT')
        obj.select = True
        bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)
        obj.scs_props.parent_identity = scs_root_object.name

    for obj in locators:
        bpy.ops.object.select_all(action='DESELECT')
        obj.select = True
        bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)
        obj.scs_props.parent_identity = scs_root_object.name

    # LOCATION
    scs_root_object.location = context.scene.cursor_location

    # MAKE ONLY 'SCS GAME OBJECT' SELECTED
    bpy.ops.object.select_all(action='DESELECT')
    for obj in bpy.data.objects:
        obj.select = False
    scs_root_object.select = True
    context.scene.objects.active = scs_root_object

    # MAKE PART RECORD
    part_inventory = scs_root_object.scs_object_part_inventory
    parts_dict = _object_utils.collect_parts_on_root(scs_root_object)
    for part_name in parts_dict:
        _inventory.add_item(part_inventory, part_name)

    # MAKE VARIANT RECORD
    variant_inventory = scs_root_object.scs_object_variant_inventory
    for variant_i, variant_record in enumerate(loaded_variants):
        variant_name = variant_record[0]
        variantparts = variant_record[1]

        variant = _inventory.add_item(variant_inventory, variant_name)

        # for every variant create all of the part entries and mark them included properly
        for part in part_inventory:

            part = _inventory.add_item(variant.parts, part.name)
            if part.name in variantparts:
                part.include = True

                # cleanup generated terrain points vertex layers by variant
                for obj in parts_dict[part.name]:

                    if obj.type != "MESH":
                        continue

                    vg_to_delete = []
                    accepted_vg_nodes = {}
                    for vertex_group in obj.vertex_groups:

                        # ignore any vertex group which isn't from terrain points
                        # (others might come from skinning)
                        if _OP_consts.TerrainPoints.vg_name_prefix not in vertex_group.name:
                            continue

                        # ignore already fixed vertex group
                        if vertex_group.name.startswith(_OP_consts.TerrainPoints.vg_name_prefix):
                            continue

                        # get variant index from first 6 chars -> check PIM importer for more info
                        vg_var_index = int(vertex_group.name[:6])
                        # ignore other variant vertex groups and add them to delete list
                        if vg_var_index >= 0 and vg_var_index != variant_i:
                            vg_to_delete.append(vertex_group)
                            continue

                        # finally remove variant prefixing name if variant is not defined (-1)
                        # or index matches current one
                        vertex_group.name = vertex_group.name[6:]

                        # log accepted node index for identifying which vertex groups
                        # really have to be deleted
                        accepted_vg_nodes[vertex_group.name[-1]] = 1

                    # cleanup possible duplicates for the same node
                    # because one object anyway can not have terrain points vertex groups for multiple variants
                    while len(vg_to_delete) > 0 and len(accepted_vg_nodes) > 0:
                        curr_vg = vg_to_delete.pop()

                        # extra caution step where group can be deleted
                        # only if one of vertex groups for this node was accepted
                        if curr_vg.name[-1] in accepted_vg_nodes:
                            obj.vertex_groups.remove(curr_vg)

            else:
                part.include = False

    # MAKE LOOK RECORDS
    for look_i, look in enumerate(loaded_looks):

        look_name = look[0]
        look_mat_settings = look[1]

        # SETUP ALL THE MATERIALS, NOTE: They should be already created by PIM import.
        for mat_info in mats_info:
            mat = bpy.data.materials[mat_info[0]]
            if mat_info[2] in look_mat_settings:

                # ASSIGN IMPORTED SHADER DATA
                material_effect, material_attributes, material_textures, material_section = _get_shader_data(look_mat_settings[mat_info[2]])

                # TRY TO FIND SUITABLE PRESET
                (preset_name, preset_section) = _material_utils.find_preset(material_effect, material_textures)

                if preset_name:  # preset name is found within presets shaders

                    mat.scs_props.active_shader_preset_name = preset_name

                    if preset_section:

                        preset_effect = preset_section.get_prop_value("Effect")
                        mat.scs_props.mat_effect_name = preset_effect

                        if look_i == 0:
                            # apply default shader settings
                            _material_utils.set_shader_data_to_material(mat, preset_section, is_import=True)

                        # reapply settings from material
                        _material_utils.set_shader_data_to_material(mat, material_section, is_import=True, override_back_data=False)

                        lprint("D Using shader preset on material %r.", (mat.name,))

                    else:
                        print('''NO "preset_section"! (Shouldn't happen!)''')

                else:  # import shader directly from material and mark it as imported

                    mat.scs_props.active_shader_preset_name = "<imported>"
                    _material_utils.set_shader_data_to_material(mat, material_section, is_import=True)

                    lprint("W Using imported shader on material %r, effect: %r.", (mat.name, mat.scs_props.mat_effect_name))

                if look_i == len(loaded_looks) - 1:
                    # delete not needed data on material
                    if "scs_tex_aliases" in mat:
                        del mat["scs_tex_aliases"]

        # CREATE NEW LOOK ENTRY ON ROOT
        bpy.ops.object.add_scs_look(look_name=look_name, instant_apply=False)

    # apply first look after everything is done
    scs_root_object.scs_props.active_scs_look = 0

    # fix scs root children objects count so it won't trigger persistent cycle
    scs_root_object.scs_cached_num_children = len(scs_root_object.children)

    return scs_root_object
예제 #5
0
def post_load(scene):
    # get Blender Tools version from last blend file load
    last_load_bt_ver = _get_scs_globals().last_load_bt_version

    scs_roots = None

    """
    Applies fixes for v0.6 or less:
    1. fixes reflection textures tga's for tobjs as TOBJ load is now supported and unlock that textures
    2. calls update on all set textures to correct paths for them
    3. tries to fix active shader preset name for materials, because of new flavor system
    """
    if _info_utils.cmp_ver_str(last_load_bt_ver, "0.6") <= 0:

        print("INFO\t-  Applying fixes for version <= 0.6")

        for material in bpy.data.materials:

            # ignore materials not related to blender tools
            if material.scs_props.mat_effect_name == "":
                continue

            for tex_type in material.scs_props.get_texture_types().keys():

                texture_attr_str = "shader_texture_" + tex_type
                if texture_attr_str in material.scs_props.keys():

                    # 1. fix reflection textures
                    if tex_type == "reflection":

                        is_building_ref = material.scs_props[texture_attr_str].endswith("/bulding_ref.tga")
                        is_generic_s = material.scs_props[texture_attr_str].endswith("material/environment/generic_s.tga")
                        is_glass_interior = material.scs_props.active_shader_preset_name == "glass - interior"
                        is_dif_spec_weight_add_env = material.scs_props.active_shader_preset_name == "dif.spec.weight.add.env"
                        is_truckpaint = material.scs_props.active_shader_preset_name.startswith("truckpaint")

                        # fix paths
                        if is_building_ref:
                            material.scs_props[texture_attr_str] = material.scs_props[texture_attr_str][:-4]
                            material.scs_props[texture_attr_str + "_locked"] = False
                        elif is_generic_s:
                            if is_glass_interior:
                                material.scs_props[texture_attr_str] = "//material/environment/interior_reflection"
                            elif is_dif_spec_weight_add_env:
                                material.scs_props[texture_attr_str] = "//material/environment/generic_reflection"
                            else:
                                material.scs_props[texture_attr_str] = "//material/environment/vehicle_reflection"

                            # unlock reflection textures everywhere except on truckpaint shader
                            if not is_truckpaint:
                                material.scs_props[texture_attr_str + "_locked"] = False

                        # acquire roots on demand only once
                        scs_roots = _object_utils.gather_scs_roots(bpy.data.objects) if not scs_roots else scs_roots

                        # propagate reflection texture change on all of the looks.
                        # NOTE: We can afford write through because old BT had all reflection textures locked
                        # meaning user had to use same texture on all looks
                        # NOTE#2: Printouts like:
                        # "Look with ID: X doesn't have entry for material 'X' in SCS Root 'X',
                        #  property 'shader_texture_reflection' won't be updated!"
                        # are expected here, because we don't use any safety check,
                        # if material is used on the mesh objects inside scs root
                        for scs_root in scs_roots:
                            _looks.write_through(scs_root, material, texture_attr_str)

                    # 2. trigger update function for path reload and reload of possible missing textures
                    update_func = getattr(material.scs_props, "update_" + texture_attr_str, None)
                    if update_func:
                        update_func(material)

            # ignore already properly set materials
            if material.scs_props.active_shader_preset_name in _get_shader_presets_inventory():
                continue

            # 3. try to recover "active_shader_preset_name" from none flavor times Blender Tools
            material_textures = {}
            if "scs_shader_attributes" in material and "textures" in material["scs_shader_attributes"]:
                for texture in material["scs_shader_attributes"]["textures"].values():
                    tex_id = texture["Tag"].split(":")[1]
                    tex_value = texture["Value"]
                    material_textures[tex_id] = tex_value

            (preset_name, preset_section) = _material_utils.find_preset(material.scs_props.mat_effect_name, material_textures)
            if preset_name:
                material.scs_props.active_shader_preset_name = preset_name

                # acquire roots on demand only once
                scs_roots = _object_utils.gather_scs_roots(bpy.data.objects) if not scs_roots else scs_roots

                # make sure to fix active preset shader name in all looks
                # NOTE: Printouts like:
                # "Look with ID: X doesn't have entry for material 'X' in SCS Root 'X',
                #  property 'active_shader_preset_name' won't be updated!"
                # are expected here, because we don't use any safety check,
                # if material is used on the mesh objects inside scs root
                for scs_root in scs_roots:
                    _looks.write_through(scs_root, material, "active_shader_preset_name")

    # as last update "last load" Blender Tools version to current
    _get_scs_globals().last_load_bt_version = get_tools_version()
예제 #6
0
        def execute(self, context):

            # find group names created by Blender Tools with
            # dynamic importing of all modules from "internals/shaders" folder
            # and checking if module has "get_node_group" functions which indicates that
            # module creates node group
            groups_to_remove = [
                "AddEnvGroup",  # from v0.6
                "FresnelGroup",  # from v0.6
                "LampmaskMixerGroup",  # from v0.6
                "ReflectionNormalGroup",  # from v0.6
            ]
            for root, dirs, files in os.walk(_path_utils.get_addon_installation_paths()[0] + os.sep + "internals/shaders"):

                for file in files:

                    if not file.endswith(".py"):
                        continue

                    module = SourceFileLoader(root + os.sep + file, root + os.sep + file).load_module()
                    if "get_node_group" in dir(module):

                        ng = module.get_node_group()
                        groups_to_remove.append(ng.name)

            # 1. clear nodes on materials
            for mat in bpy.data.materials:

                if not mat.node_tree:
                    continue

                if mat.scs_props.active_shader_preset_name == "<none>":

                    nodes_to_remove = []

                    # check for possible leftover usage of our node groups
                    for node in mat.node_tree.nodes:

                        # filter out nodes which are not node group and node groups without node tree
                        if node.type != "GROUP" or not node.node_tree:
                            continue

                        if node.node_tree.name in groups_to_remove:
                            nodes_to_remove.append(node.node_tree.name)

                    # remove possible leftover used node group nodes
                    for node_name in nodes_to_remove:
                        mat.node_tree.nodes.remove(mat.node_tree.nodes[node_name])

                    continue

                mat.node_tree.nodes.clear()

            # 2. clear nodes on node groups
            for ng_name in groups_to_remove:

                if ng_name not in bpy.data.node_groups:
                    continue

                ng = bpy.data.node_groups[ng_name]
                ng.nodes.clear()

            # 3. remove node groups from blender data blocks
            for ng_name in groups_to_remove:

                if ng_name not in bpy.data.node_groups:
                    continue

                bpy.data.node_groups.remove(bpy.data.node_groups[ng_name])

            # 4. finally set preset to material again, which will update nodes and possible input interface changes
            for mat in bpy.data.materials:

                if mat.scs_props.active_shader_preset_name == "<none>":
                    continue

                material_textures = {}
                if "scs_shader_attributes" in mat and "textures" in mat["scs_shader_attributes"]:
                    for texture in mat["scs_shader_attributes"]["textures"].values():
                        tex_id = texture["Tag"].split(":")[1]
                        tex_value = texture["Value"]
                        material_textures[tex_id] = tex_value

                (preset_name, preset_section) = _material_utils.find_preset(mat.scs_props.mat_effect_name, material_textures)

                if preset_section:
                    _material_utils.set_shader_data_to_material(mat, preset_section)

            return {'FINISHED'}