Skip to content
Snippets Groups Projects
shading_gui.py 21.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    # <pep8 compliant>
    """"User interface for shaders exported to POV textures."""
    
    import bpy
    from bpy.utils import register_class, unregister_class
    from bpy.types import Operator, Menu, Panel
    from bl_operators.presets import AddPresetBase
    
    # Example of wrapping every class 'as is' except some
    from bl_ui import properties_material
    
    for member in dir(properties_material):
        subclass = getattr(properties_material, member)
    
        if hasattr(subclass, "COMPAT_ENGINES"):
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
    del properties_material
    
    from .shading_properties import check_material
    
    
    def simple_material(mat):
        """Test if a material uses nodes"""
    
        return (mat is not None) and (not mat.use_nodes)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
    class MaterialButtonsPanel:
    
        """Use this class to define buttons from the material tab of properties window."""
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
        bl_space_type = 'PROPERTIES'
        bl_region_type = 'WINDOW'
        bl_context = "material"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            rd = context.scene.render
            return mat and (rd.engine in cls.COMPAT_ENGINES)
    
    
    
    class MATERIAL_PT_POV_shading(MaterialButtonsPanel, Panel):
        bl_label = "Shading"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            engine = context.scene.render.engine
            return check_material(mat) and (mat.pov.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES)
    
        def draw(self, context):
            layout = self.layout
    
            mat = context.material  # FORMERLY : #active_node_mat(context.material)
    
            if mat.pov.type in {'SURFACE', 'WIRE'}:
                split = layout.split()
    
                col = split.column()
                sub = col.column()
                sub.active = not mat.pov.use_shadeless
                sub.prop(mat.pov, "emit")
                sub.prop(mat.pov, "ambient")
                sub = col.column()
                sub.prop(mat.pov, "translucency")
    
                col = split.column()
                col.prop(mat.pov, "use_shadeless")
                sub = col.column()
                sub.active = not mat.pov.use_shadeless
                sub.prop(mat.pov, "use_tangent_shading")
                sub.prop(mat.pov, "use_cubic")
    
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    class MATERIAL_MT_POV_sss_presets(Menu):
        """Use this class to define pov sss preset menu."""
    
        bl_label = "SSS Presets"
        preset_subdir = "pov/material/sss"
        preset_operator = "script.execute_preset"
        draw = bpy.types.Menu.draw_preset
    
    
    class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
        """Add an SSS Preset"""
    
        bl_idname = "material.sss_preset_add"
        bl_label = "Add SSS Preset"
        preset_menu = "MATERIAL_MT_POV_sss_presets"
    
        # variable used for all preset values
        preset_defines = ["material = bpy.context.material"]
    
        # properties to store in the preset
        preset_values = [
            "material.pov_subsurface_scattering.radius",
            "material.pov_subsurface_scattering.color",
        ]
    
        # where to store the preset
        preset_subdir = "pov/material/sss"
    
    
    class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
        """Use this class to define pov sss buttons panel."""
    
        bl_label = "Subsurface Scattering"
        bl_options = {'DEFAULT_CLOSED'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            engine = context.scene.render.engine
            return (
                check_material(mat)
                and (mat.pov.type in {'SURFACE', 'WIRE'})
                and (engine in cls.COMPAT_ENGINES)
            )
    
        def draw_header(self, context):
            mat = context.material  # FORMERLY : #active_node_mat(context.material)
            sss = mat.pov_subsurface_scattering
    
            self.layout.active = not mat.pov.use_shadeless
            self.layout.prop(sss, "use", text="")
    
        def draw(self, context):
            layout = self.layout
    
            mat = context.material  # FORMERLY : #active_node_mat(context.material)
            sss = mat.pov_subsurface_scattering
    
    
            layout.active = sss.use and (not mat.pov.use_shadeless)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
            row = layout.row().split()
            sub = row.row(align=True).split(align=True, factor=0.75)
            sub.menu(MATERIAL_MT_POV_sss_presets.__name__, text=MATERIAL_MT_POV_sss_presets.bl_label)
            sub.operator(MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='ADD')
            sub.operator(
                MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='REMOVE'
            ).remove_active = True
    
            split = layout.split()
    
            col = split.column()
            col.prop(sss, "ior")
            col.prop(sss, "scale")
            col.prop(sss, "color", text="")
            col.prop(sss, "radius", text="RGB Radius", expand=True)
    
            col = split.column()
            sub = col.column(align=True)
            sub.label(text="Blend:")
            sub.prop(sss, "color_factor", text="Color")
            sub.prop(sss, "texture_factor", text="Texture")
            sub.label(text="Scattering Weight:")
            sub.prop(sss, "front")
            sub.prop(sss, "back")
            col.separator()
            col.prop(sss, "error_threshold", text="Error")
    
    
    class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
        """Use this class to define an activate pov nodes button."""
    
        bl_label = "Activate Node Settings"
        bl_context = "material"
        bl_options = {'HIDE_HEADER'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            mat = context.material
            return (
                mat
                and mat.pov.type == "SURFACE"
    
                and engine in cls.COMPAT_ENGINES
                and not mat.pov.material_use_nodes
                and not mat.use_nodes
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            )
    
        def draw(self, context):
            layout = self.layout
            # layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
            # the above replaced with a context hook below:
            layout.operator(
                "WM_OT_context_toggle", text="Use POV-Ray Nodes", icon='NODETREE'
            ).data_path = "material.pov.material_use_nodes"
    
    
    class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
        """Use this class to show pov active node properties buttons."""
    
        bl_label = "Active Node Settings"
        bl_context = "material"
        bl_options = {'HIDE_HEADER'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            mat = context.material
            return (
                mat
                and mat.pov.type == "SURFACE"
                and (engine in cls.COMPAT_ENGINES)
                and mat.pov.material_use_nodes
            )
    
        def draw(self, context):
            mat = context.material
            node_tree = mat.node_tree
    
            if node_tree and mat.use_nodes:
                layout = self.layout
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                node = node_tree.nodes.active
    
                if node:
                    layout.prop(mat.pov, "material_active_node")
                    layout.context_pointer_set("node", node)
                    if hasattr(node, "draw_buttons_ext"):
                        node.draw_buttons_ext(context, layout)
                    elif hasattr(node, "draw_buttons"):
                        node.draw_buttons(context, layout)
                    value_inputs = [
                        socket
                        for socket in node.inputs
                        if socket.enabled and not socket.is_linked
                    ]
                    if value_inputs:
                        layout.separator()
                        layout.label(text="Inputs:")
                        for socket in value_inputs:
                            row = layout.row()
                            socket.draw(context, row, node, socket.name)
                else:
                    layout.label(text="No active nodes!")
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
    class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
        """Use this class to define standard material specularity (highlights) buttons."""
    
        bl_label = "Specular"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            engine = context.scene.render.engine
            return (
                check_material(mat)
                and (mat.pov.type in {'SURFACE', 'WIRE'})
                and (engine in cls.COMPAT_ENGINES)
            )
    
        def draw(self, context):
            layout = self.layout
    
            mat = context.material.pov
    
            layout.active = not mat.use_shadeless
    
            split = layout.split()
    
            col = split.column()
            col.prop(mat, "specular_color", text="")
            col.prop(mat, "specular_intensity", text="Intensity")
    
            col = split.column()
            col.prop(mat, "specular_shader", text="")
            col.prop(mat, "use_specular_ramp", text="Ramp")
    
            col = layout.column()
            if mat.specular_shader in {'COOKTORR', 'PHONG'}:
                col.prop(mat, "specular_hardness", text="Hardness")
            elif mat.specular_shader == 'BLINN':
                row = col.row()
                row.prop(mat, "specular_hardness", text="Hardness")
                row.prop(mat, "specular_ior", text="IOR")
            elif mat.specular_shader == 'WARDISO':
                col.prop(mat, "specular_slope", text="Slope")
            elif mat.specular_shader == 'TOON':
                row = col.row()
                row.prop(mat, "specular_toon_size", text="Size")
                row.prop(mat, "specular_toon_smooth", text="Smooth")
    
            if mat.use_specular_ramp:
                layout.separator()
                layout.template_color_ramp(mat, "specular_ramp", expand=True)
                layout.separator()
    
                row = layout.row()
                row.prop(mat, "specular_ramp_input", text="Input")
                row.prop(mat, "specular_ramp_blend", text="Blend")
    
                layout.prop(mat, "specular_ramp_factor", text="Factor")
    
    
    class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
        """Use this class to define standard material reflectivity (mirror) buttons."""
    
        bl_label = "Mirror"
        bl_options = {'DEFAULT_CLOSED'}
        bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            engine = context.scene.render.engine
            return (
                check_material(mat)
                and (mat.pov.type in {'SURFACE', 'WIRE'})
                and (engine in cls.COMPAT_ENGINES)
            )
    
        def draw_header(self, context):
            mat = context.material
            raym = mat.pov_raytrace_mirror
    
            self.layout.prop(raym, "use", text="")
    
        def draw(self, context):
            layout = self.layout
    
            mat = context.material  # Formerly : #mat = active_node_mat(context.material)
            raym = mat.pov_raytrace_mirror
    
            layout.active = raym.use
    
            split = layout.split()
    
            col = split.column()
            col.prop(raym, "reflect_factor")
            col.prop(raym, "mirror_color", text="")
    
            col = split.column()
            col.prop(raym, "fresnel")
            sub = col.column()
            sub.active = raym.fresnel > 0.0
            sub.prop(raym, "fresnel_factor", text="Blend")
    
            split = layout.split()
    
            col = split.column()
            col.separator()
            col.prop(raym, "depth")
            col.prop(raym, "distance", text="Max Dist")
            col.separator()
            sub = col.split(factor=0.4)
            sub.active = raym.distance > 0.0
            sub.label(text="Fade To:")
            sub.prop(raym, "fade_to", text="")
    
            col = split.column()
            col.label(text="Gloss:")
            col.prop(raym, "gloss_factor", text="Amount")
            sub = col.column()
            sub.active = raym.gloss_factor < 1.0
            sub.prop(raym, "gloss_threshold", text="Threshold")
            sub.prop(raym, "gloss_samples", text="Noise")
            sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
    
    
    class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
        """Use this class to define pov material transparency (alpha) buttons."""
    
        bl_label = "Transparency"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            engine = context.scene.render.engine
            return (
                check_material(mat)
                and (mat.pov.type in {'SURFACE', 'WIRE'})
                and (engine in cls.COMPAT_ENGINES)
            )
    
        def draw_header(self, context):
            mat = context.material
    
            if simple_material(mat):
                self.layout.prop(mat.pov, "use_transparency", text="")
    
        def draw(self, context):
            layout = self.layout
    
            base_mat = context.material
            mat = context.material  # FORMERLY active_node_mat(context.material)
            rayt = mat.pov_raytrace_transparency
    
            if simple_material(base_mat):
                row = layout.row()
                row.active = mat.pov.use_transparency
                row.prop(mat.pov, "transparency_method", expand=True)
    
            split = layout.split()
            split.active = base_mat.pov.use_transparency
    
            col = split.column()
            col.prop(mat.pov, "alpha")
            row = col.row()
            row.active = (base_mat.pov.transparency_method != 'MASK') and (not mat.pov.use_shadeless)
            row.prop(mat.pov, "specular_alpha", text="Specular")
    
            col = split.column()
            col.active = not mat.pov.use_shadeless
            col.prop(rayt, "fresnel")
            sub = col.column()
            sub.active = rayt.fresnel > 0.0
            sub.prop(rayt, "fresnel_factor", text="Blend")
    
            if base_mat.pov.transparency_method == 'RAYTRACE':
                layout.separator()
                split = layout.split()
                split.active = base_mat.pov.use_transparency
    
                col = split.column()
                col.prop(rayt, "ior")
                col.prop(rayt, "filter")
                col.prop(rayt, "falloff")
                col.prop(rayt, "depth_max")
                col.prop(rayt, "depth")
    
                col = split.column()
                col.label(text="Gloss:")
                col.prop(rayt, "gloss_factor", text="Amount")
                sub = col.column()
                sub.active = rayt.gloss_factor < 1.0
                sub.prop(rayt, "gloss_threshold", text="Threshold")
                sub.prop(rayt, "gloss_samples", text="Samples")
    
    
    class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
        """Use this class to define more pov specific reflectivity buttons."""
    
        bl_label = "POV-Ray Reflection"
        bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            mat = context.material
            return (
                mat
                and mat.pov.type == "SURFACE"
    
                and engine in cls.COMPAT_ENGINES
                and not mat.pov.material_use_nodes
                and not mat.use_nodes
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            )
    
        def draw(self, context):
            layout = self.layout
            mat = context.material
            col = layout.column()
            col.prop(mat.pov, "irid_enable")
            if mat.pov.irid_enable:
                col = layout.column()
                col.prop(mat.pov, "irid_amount", slider=True)
                col.prop(mat.pov, "irid_thickness", slider=True)
                col.prop(mat.pov, "irid_turbulence", slider=True)
            col.prop(mat.pov, "conserve_energy")
            col2 = col.split().column()
    
            if not mat.pov_raytrace_mirror.use:
                col2.label(text="Please Check Mirror settings :")
            col2.active = mat.pov_raytrace_mirror.use
            col2.prop(mat.pov, "mirror_use_IOR")
            if mat.pov.mirror_use_IOR:
                col2.alignment = 'CENTER'
                col2.label(text="The current Raytrace ")
                col2.label(text="Transparency IOR is: " + str(mat.pov_raytrace_transparency.ior))
            col2.prop(mat.pov, "mirror_metallic")
    
    
    '''
    #group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
    class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
        bl_label = "POV-Ray Interior"
        bl_idname = "material.pov_interior"
        #bl_parent_id = "material.absorption"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            mat=context.material
    
            return mat and mat.pov.type == "SURFACE"
                        and (engine in cls.COMPAT_ENGINES)
                        and not (mat.pov.material_use_nodes or mat.use_nodes)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
        def draw_header(self, context):
            mat = context.material
    '''
    
    
    class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
        """Use this class to define pov fading (absorption) color buttons."""
    
        bl_label = "POV-Ray Absorption"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
        # bl_parent_id = "material.pov_interior"
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            mat = context.material
            return (
                mat
                and mat.pov.type == "SURFACE"
    
                and engine in cls.COMPAT_ENGINES
                and not mat.pov.material_use_nodes
                and not mat.use_nodes
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            )
    
        def draw_header(self, context):
            mat = context.material
    
            self.layout.prop(mat.pov, "interior_fade_color", text="")
    
        def draw(self, context):
            mat = context.material
            if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
    
                layout = self.layout
                # layout.active = mat.pov.interior_fade_color
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                layout.label(text="Raytrace transparency")
                layout.label(text="depth max Limit needs")
                layout.label(text="to be non zero to fade")
    
    
    class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
        """Use this class to define pov caustics buttons."""
    
        bl_label = "Caustics"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            engine = context.scene.render.engine
            mat = context.material
            return (
                mat
                and mat.pov.type == "SURFACE"
    
                and engine in cls.COMPAT_ENGINES
                and not mat.pov.material_use_nodes
                and not mat.use_nodes
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            )
    
        def draw_header(self, context):
            mat = context.material
            if mat.pov.caustics_enable:
                self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER_SEL")
            else:
                self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER")
    
        def draw(self, context):
    
            layout = self.layout
    
            mat = context.material
            layout.active = mat.pov.caustics_enable
            col = layout.column()
            if mat.pov.caustics_enable:
                col.prop(mat.pov, "refraction_caustics")
                if mat.pov.refraction_caustics:
    
                    col.prop(mat.pov, "refraction_type", text="")
    
                    if mat.pov.refraction_type == "1":
                        col.prop(mat.pov, "fake_caustics_power", slider=True)
                    elif mat.pov.refraction_type == "2":
                        col.prop(mat.pov, "photons_dispersion", slider=True)
                        col.prop(mat.pov, "photons_dispersion_samples", slider=True)
                col.prop(mat.pov, "photons_reflection")
    
                if not mat.pov.refraction_caustics and not mat.pov.photons_reflection:
                    col = layout.column()
                    col.alignment = 'CENTER'
                    col.label(text="Caustics override is on, ")
                    col.label(text="but you didn't chose any !")
    
    
    class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
        """Use this class to define Blender strand antialiasing buttons."""
    
        bl_label = "Strand"
        bl_options = {'DEFAULT_CLOSED'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        @classmethod
        def poll(cls, context):
            mat = context.material
            engine = context.scene.render.engine
            return (
                mat and (mat.pov.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES)
            )
    
        def draw(self, context):
            layout = self.layout
    
            mat = context.material  # don't use node material
            tan = mat.strand
    
            split = layout.split()
    
            col = split.column()
            sub = col.column(align=True)
            sub.label(text="Size:")
            sub.prop(tan, "root_size", text="Root")
            sub.prop(tan, "tip_size", text="Tip")
            sub.prop(tan, "size_min", text="Minimum")
            sub.prop(tan, "use_blender_units")
            sub = col.column()
            sub.active = not mat.pov.use_shadeless
            sub.prop(tan, "use_tangent_shading")
            col.prop(tan, "shape")
    
            col = split.column()
            col.label(text="Shading:")
            col.prop(tan, "width_fade")
            ob = context.object
            if ob and ob.type == 'MESH':
                col.prop_search(tan, "uv_layer", ob.data, "uv_layers", text="")
            else:
                col.prop(tan, "uv_layer", text="")
            col.separator()
            sub = col.column()
            sub.active = not mat.pov.use_shadeless
            sub.label(text="Surface diffuse:")
            sub = col.column()
            sub.prop(tan, "blend_distance", text="Distance")
    
    
    class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
        """Use this class to define pov custom code declared name field."""
    
        bl_label = "Custom POV Code"
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        def draw(self, context):
            layout = self.layout
            mat = context.material
            col = layout.column()
            col.alignment = 'RIGHT'
            col.label(text="Override properties with this")
            col.label(text="text editor {pov code} block")
            layout.prop(mat.pov, "replacement_text", text="#declare name", icon='SYNTAX_ON')
    
    
    classes = (
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        MATERIAL_PT_POV_sss,
        MATERIAL_MT_POV_sss_presets,
        MATERIAL_OT_POV_sss_add_preset,
        MATERIAL_PT_strand,
        MATERIAL_PT_POV_activate_node,
        MATERIAL_PT_POV_active_node,
        MATERIAL_PT_POV_specular,
        MATERIAL_PT_POV_mirror,
        MATERIAL_PT_POV_transp,
        MATERIAL_PT_POV_reflection,
    
        # MATERIAL_PT_POV_interior,
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
        MATERIAL_PT_POV_fade_color,
        MATERIAL_PT_POV_caustics,
        MATERIAL_PT_POV_replacement_text,
    )
    
    
    def register():
        for cls in classes:
            register_class(cls)
    
    
    def unregister():
        for cls in reversed(classes):
            unregister_class(cls)