def _disable_all_denoiser():
    """ Disables all denoiser.

    At the moment this includes the cycles and the intel denoiser.
    """
    # Disable cycles denoiser
    bpy.context.view_layer.cycles.use_denoising = False

    # Disable intel denoiser
    if bpy.context.scene.use_nodes:
        nodes = bpy.context.scene.node_tree.nodes
        links = bpy.context.scene.node_tree.links

        # Go through all existing denoiser nodes
        for denoiser_node in Utility.get_nodes_with_type(nodes, 'CompositorNodeDenoise'):
            in_node = denoiser_node.inputs['Image']
            out_node = denoiser_node.outputs['Image']

            # If it is fully included into the node tree
            if in_node.is_linked and out_node.is_linked:
                # There is always only one input link
                in_link = in_node.links[0]
                # Connect from_socket of the incoming link with all to_sockets of the out going links
                for link in out_node.links:
                    links.new(in_link.from_socket, link.to_socket)

            # Finally remove the denoiser node
            nodes.remove(denoiser_node)
Beispiel #2
0
    def get_nodes_with_type(self, node_type: str) -> List[bpy.types.Node]:
        """ Returns all nodes which are of the given node_type

        :param node_type: The note type to look for.
        :return: The list of nodes with the given type.
        """
        return Utility.get_nodes_with_type(self.nodes, node_type)
Beispiel #3
0
def add_nodes_to_group(nodes: bpy.types.Node,
                       group_name: str) -> bpy.types.ShaderNodeTree:
    """
    Creates the node group, copies all attributes and links and adds the group input and output
    https://blender.stackexchange.com/a/175604

    :param nodes: Nodes, which should be used
    :param group_name: Name of the group
    :return bpy.types.ShaderNodeTree: the group which can be used inside of a bpy.types.ShaderNodeGroup
    """
    # create new node group
    group = bpy.data.node_groups.new(name=group_name, type="ShaderNodeTree")

    # copy all nodes from the list to the created group with all their attributes
    copy_nodes(nodes, group.nodes)

    # copy the links between the nodes to the created groups nodes
    copy_links(nodes, group.nodes, group.links)

    # add the group input and output node to the created group
    group_input, group_output = add_group_nodes(group)

    # check if the selection of nodes goes over a material, if so replace the material output with the output of
    # the group
    material_outputs = Utility.get_nodes_with_type(group.nodes,
                                                   "OutputMaterial")
    if len(material_outputs) == 1:
        for input in material_outputs[0].inputs:
            group.outputs.new(input.bl_idname, input.name)
            for link in input.links:
                group.links.new(link.from_socket,
                                group_output.inputs[input.name])
        # remove the material output, the material output should never be inside of a group
        group.nodes.remove(material_outputs[0])
    return group
Beispiel #4
0
    def _rename_materials():
        """
        Rename all materials based on their texture if they have one

        This makes the accessing later on easier
        """
        # TODO: should only be done to suncg materials
        for material in bpy.data.materials:
            if material.use_nodes:
                nodes = material.node_tree.nodes
                textures = Utility.get_nodes_with_type(nodes,
                                                       "ShaderNodeTexImage")
                if len(textures) == 1:
                    material.name = textures[0].image.name
    def _set_textures(self, ground_tile, images, uv_scaling, ambient_occlusion,
                      displacement_strength):
        """ Sets available loaded images to a texture of a current processed ground tile.

        :param ground_tile: Ground tile (plane). Type: bpy.types.Object.
        :param images: Loaded images of a chosen texture. Type: dict.
        :param uv_scaling: Scaling factor for the UV layer of the tile. Type: float.
        """
        # get a target material in case ground tile has more than one
        for material in ground_tile.data.materials.items():
            if re.fullmatch(self.target_material, material[0]):
                mat_obj = bpy.data.materials[material[0]]
            else:
                raise Exception(
                    "No RE material " + self.target_material +
                    " found in selected objects. Check if "
                    "constructor.RockEssentialsGroundConstructor module was run at least once and created "
                    "at least one ground tile!")

        # get the node tree of the current material
        nodes = mat_obj.node_tree.nodes
        # get all Image Texture nodes in the tree
        image_texture_nodes = Utility.get_nodes_with_type(
            nodes, 'ShaderNodeTexImage')
        # for each Image Texture node set a texture (image) if one was loaded
        for node in image_texture_nodes:
            if node.label in images.keys():
                node.image = images[node.label]

        # get texture name for a displacement modifier of the current ground tile
        texture_name = ground_tile.name + "_texture"
        # if displacement map (image) was provided and loaded - set it to the modifier
        if "displacement" in images.keys():
            bpy.data.textures[texture_name].image = images['displacement']

        # set ambient occlusion
        nodes.get("Group").inputs["AO"].default_value = ambient_occlusion

        # set displacement modifier strength
        bpy.context.object.modifiers[
            "Displace"].strength = displacement_strength

        # and scale the texture
        for point in ground_tile.data.uv_layers.active.data[:]:
            point.uv = point.uv * uv_scaling
Beispiel #6
0
    def perform_and_condition_check(and_condition,
                                    materials,
                                    used_materials_to_check=None):
        """ Checks for all materials in the scene if all given conditions are true, collects them in the return list.

        :param and_condition: Given conditions. Type: dict.
        :param materials: Materials, that are already in the return list. Type: list.
        :param used_materials_to_check: a list of materials to perform the check on. Type: list. Default: all materials
        :return: Materials that fulfilled given conditions. Type: list.
        """
        new_materials = []
        if used_materials_to_check is None:
            used_materials_to_check = get_all_materials()

        # through every material
        for material in used_materials_to_check:
            if material in new_materials or material in materials or material is None:
                continue

            select_material = True
            for key, value in and_condition.items():
                # check if the key is a requested custom property
                requested_custom_property = False
                requested_custom_function = False
                if key.startswith('cp_'):
                    requested_custom_property = True
                    key = key[3:]
                if key.startswith('cf_'):
                    requested_custom_function = True
                    key = key[3:]
                if hasattr(
                        material, key
                ) and not requested_custom_property and not requested_custom_function:
                    # check if the type of the value of attribute matches desired
                    if isinstance(getattr(material, key), type(value)):
                        new_value = value
                    # if not, try to enforce some mathutils-specific type
                    else:
                        if isinstance(getattr(material, key),
                                      mathutils.Vector):
                            new_value = mathutils.Vector(value)
                        elif isinstance(getattr(material, key),
                                        mathutils.Euler):
                            new_value = mathutils.Euler(value)
                        elif isinstance(getattr(material, key),
                                        mathutils.Color):
                            new_value = mathutils.Color(value)
                        # raise an exception if it is none of them
                        else:
                            raise Exception(
                                "Types are not matching: %s and %s !" %
                                (type(getattr(material, key)), type(value)))
                    # or check for equality
                    if not ((isinstance(getattr(material, key), str)
                             and re.fullmatch(value, getattr(material,
                                                             key)) is not None)
                            or getattr(material, key) == new_value):
                        select_material = False
                        break
                # check if a custom property with this name exists
                elif key in material and requested_custom_property:
                    # check if the type of the value of such custom property matches desired
                    if isinstance(material[key], type(value)) or (isinstance(
                            material[key], int) and isinstance(value, bool)):
                        # if it is a string and if the whole string matches the given pattern
                        if not ((isinstance(material[key], str)
                                 and re.fullmatch(value, material[key])
                                 is not None) or material[key] == value):
                            select_material = False
                            break
                    else:
                        # raise an exception if not
                        raise Exception(
                            "Types are not matching: {} and {} !".format(
                                type(material[key]), type(value)))
                elif requested_custom_function:
                    if key.startswith("texture_amount_"):
                        if material.use_nodes:
                            value = int(value)
                            nodes = material.node_tree.nodes
                            texture_nodes = Utility.get_nodes_with_type(
                                nodes, "TexImage")
                            amount_of_texture_nodes = len(
                                texture_nodes
                            ) if texture_nodes is not None else 0
                            if "min" in key:
                                if not (amount_of_texture_nodes >= value):
                                    select_material = False
                                    break
                            elif "max" in key:
                                if not (amount_of_texture_nodes <= value):
                                    select_material = False
                                    break
                            elif "eq" in key:
                                if not (amount_of_texture_nodes == value):
                                    select_material = False
                                    break
                            else:
                                raise Exception(
                                    "This type of key is unknown: {}".format(
                                        key))
                        else:
                            select_material = False
                            break
                    elif key.startswith("principled_bsdf_amount_"):
                        if material.use_nodes:
                            value = int(value)
                            nodes = material.node_tree.nodes
                            principled = Utility.get_nodes_with_type(
                                nodes, "BsdfPrincipled")
                            amount_of_principled_bsdf_nodes = len(
                                principled) if principled is not None else 0
                            if "min" in key:
                                if not (amount_of_principled_bsdf_nodes >=
                                        value):
                                    select_material = False
                                    break
                            elif "max" in key:
                                if not (amount_of_principled_bsdf_nodes <=
                                        value):
                                    select_material = False
                                    break
                            elif "eq" in key:
                                if not (amount_of_principled_bsdf_nodes
                                        == value):
                                    select_material = False
                                    break
                            else:
                                raise Exception(
                                    "This type of key is unknown: {}".format(
                                        key))
                        else:
                            select_material = False
                            break
                    elif key.startswith("principled_bsdf_"
                                        ):  # must be after the amount check
                        # This custom function can check the value of a certain Principled BSDF shader input.
                        # For example this can be used to avoid using materials, which have an Alpha Texture by
                        # adding they key: `"cf_principled_bsdf_Alpha_eq": 1.0`
                        if material.use_nodes:
                            value = float(value)
                            # first check if there is only one Principled BSDF node in the material
                            nodes = material.node_tree.nodes
                            principled = Utility.get_nodes_with_type(
                                nodes, "BsdfPrincipled")
                            amount_of_principled_bsdf_nodes = len(
                                principled) if principled is not None else 0
                            if amount_of_principled_bsdf_nodes != 1:
                                select_material = False
                                break
                            principled = principled[0]
                            # then extract the input name from the key, for the Alpha example: `Alpha`
                            extracted_input_name = key[len("principled_bsdf_"
                                                           ):key.rfind("_")]
                            # check if this key exists, else throw an error
                            if extracted_input_name not in principled.inputs:
                                raise Exception(
                                    "Only valid inputs of a principled node are allowed: "
                                    "{} in: {}".format(extracted_input_name,
                                                       key))
                            # extract this input value
                            used_value = principled.inputs[
                                extracted_input_name]
                            # if this input value is not a default value it will be connected via the links
                            if len(used_value.links) > 0:
                                select_material = False
                                break
                            # if no link is found check the default value
                            used_value = used_value.default_value
                            # compare the given value to the default value
                            if key.endswith("min"):
                                if not (used_value >= value):
                                    select_material = False
                                    break
                            elif key.endswith("max"):
                                if not (used_value <= value):
                                    select_material = False
                                    break
                            elif key.endswith("eq"):
                                if not (used_value == value):
                                    select_material = False
                                    break
                            else:
                                raise Exception(
                                    "This type of key is unknown: {}".format(
                                        key))
                        else:
                            select_material = False
                            break
                    elif key == "use_materials_of_objects":
                        objects = Utility.build_provider_based_on_config(
                            value).run()
                        found_material = False
                        # iterate over all selected objects
                        for obj in objects:
                            # check if they have materials
                            if hasattr(obj, "material_slots"):
                                for mat_slot in obj.material_slots:
                                    # if the material is the same as the currently checked one
                                    if mat_slot.material == material:
                                        found_material = True
                                        break
                            if found_material:
                                break
                        if not found_material:
                            select_material = False
                            break
                    else:
                        select_material = False
                        break
                else:
                    select_material = False
                    break
            if select_material:
                new_materials.append(material)
        return new_materials