Пример #1
0
    def map_vertex_color(self,
                         layer_name: str = 'Col',
                         active_shading: bool = True):
        """ Maps existing vertex color to the base color of the principled bsdf node or a new background color node.

        :param layer_name: Name of the vertex color layer. Type: string.
        :param active_shading: Whether to keep the principled bsdf shader. If True, the material properties influence light
                               reflections such as specularity, roughness, etc. alter the object's appearance. Type: bool.
        """

        if active_shading:
            # create new shader node attribute
            attr_node = self.nodes.new(type='ShaderNodeAttribute')
            attr_node.attribute_name = layer_name
            # connect it to base color of principled bsdf
            principled_bsdf = self.get_the_one_node_with_type("BsdfPrincipled")
            self.links.new(attr_node.outputs['Color'],
                           principled_bsdf.inputs['Base Color'])
        else:
            # create new vertex color shade node
            vcol = self.nodes.new(type="ShaderNodeVertexColor")
            vcol.layer_name = layer_name
            node_connected_to_output, material_output = Utility.get_node_connected_to_the_output_and_unlink_it(
                self.blender_obj)
            # remove principled bsdf
            self.nodes.remove(node_connected_to_output)
            background_color_node = self.nodes.new(type="ShaderNodeBackground")
            if 'Color' in background_color_node.inputs:
                self.links.new(vcol.outputs['Color'],
                               background_color_node.inputs['Color'])
                self.links.new(background_color_node.outputs["Background"],
                               material_output.inputs["Surface"])
            else:
                raise Exception(
                    "Material '{}' has no node connected to the output, "
                    "which has as a 'Base Color' input.".format(
                        self.blender_obj.name))
Пример #2
0
def add_alpha_channel_to_textures(blurry_edges):
    """
    Adds transparency to all textures, which contain an .png image as an image input

    :param blurry_edges: If True, the edges of the alpha channel might be blurry,
                            this causes errors if the alpha channel should only be 0 or 1

    Be careful, when you replace the original texture with something else (Segmentation, ...),
    the necessary texture node gets lost. By copying it into a new material as done in the SegMapRenderer, you
    can keep the transparency even for those nodes.

    """
    obj_with_mats = [
        obj for obj in bpy.context.scene.objects
        if hasattr(obj.data, 'materials')
    ]
    visited_materials = set()
    # walk over all objects, which have materials
    for obj in obj_with_mats:
        for slot in obj.material_slots:
            material = slot.material
            if material is None:
                # this can happen if a material slot was created but no material was assigned
                continue
            if material.name in visited_materials:
                # skip a material if it has been used before
                continue
            visited_materials.add(material.name)
            texture_node = None
            # check each node of the material
            for node in material.node_tree.nodes:
                # if it is a texture image node
                if 'TexImage' in node.bl_idname:
                    if '.png' in node.image.name:  # contains an alpha channel
                        texture_node = node
            # this material contains an alpha png texture
            if texture_node is not None:
                nodes = material.node_tree.nodes
                links = material.node_tree.links
                node_connected_to_the_output, material_output = \
                    Utility.get_node_connected_to_the_output_and_unlink_it(material)

                if node_connected_to_the_output is not None:
                    mix_node = nodes.new(type='ShaderNodeMixShader')

                    # avoid blurry edges on the edges important for Normal, SegMapRenderer and others
                    if blurry_edges:
                        # add the alpha channel of the image to the mix shader node as a factor
                        links.new(texture_node.outputs['Alpha'],
                                  mix_node.inputs['Fac'])
                    else:
                        # Map all alpha values to 0 or 1 by applying the step function: 1 if x > 0.5 else 0
                        step_function_node = nodes.new("ShaderNodeMath")
                        step_function_node.operation = "GREATER_THAN"
                        links.new(texture_node.outputs['Alpha'],
                                  step_function_node.inputs['Value'])
                        links.new(step_function_node.outputs['Value'],
                                  mix_node.inputs['Fac'])

                    links.new(node_connected_to_the_output.outputs[0],
                              mix_node.inputs[2])
                    transparent_node = nodes.new(
                        type='ShaderNodeBsdfTransparent')
                    links.new(transparent_node.outputs['BSDF'],
                              mix_node.inputs[1])
                    # connect to material output
                    links.new(mix_node.outputs['Shader'],
                              material_output.inputs['Surface'])
                else:
                    raise Exception(
                        "Could not find shader node, which is connected to the material output "
                        "for: {}".format(slot.name))