Skip to content
Snippets Groups Projects
shading.py 82 KiB
Newer Older
# SPDX-License-Identifier: GPL-2.0-or-later
Maurice Raybaud's avatar
Maurice Raybaud committed
"""Translate complex shaders to exported POV textures."""

def write_object_material_interior(material, ob, tab_write):
Maurice Raybaud's avatar
Maurice Raybaud committed
    """Translate some object level material from Blender UI (VS data level)

    to POV interior{} syntax and write it to exported file.
    This is called in object_mesh_topology.export_meshes
Maurice Raybaud's avatar
Maurice Raybaud committed
    """
    # DH - modified some variables to be function local, avoiding RNA write
    # this should be checked to see if it is functionally correct

    # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
    # if material and material.transparency_method == 'RAYTRACE':
    if material:
        # But there can be only one!
        if material.pov_subsurface_scattering.use:  # SSS IOR get highest priority
            tab_write("interior {\n")
            tab_write("ior %.6f\n" % material.pov_subsurface_scattering.ior)
        # Then the raytrace IOR taken from raytrace transparency properties and used for
        # reflections if IOR Mirror option is checked.
        elif material.pov.mirror_use_IOR:
            tab_write("interior {\n")
            tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)
        elif material.pov.transparency_method == 'Z_TRANSPARENCY':
            tab_write("interior {\n")
            tab_write("ior 1.0\n")
        else:
            tab_write("interior {\n")
            tab_write("ior %.6f\n" % material.pov_raytrace_transparency.ior)

        pov_fake_caustics = False
        pov_photons_refraction = False
        pov_photons_reflection = False

        if material.pov.photons_reflection:
            pov_photons_reflection = True
        if not material.pov.refraction_caustics:
            pov_fake_caustics = False
            pov_photons_refraction = False
        elif material.pov.refraction_type == "1":
            pov_fake_caustics = True
            pov_photons_refraction = False
        elif material.pov.refraction_type == "2":
            pov_fake_caustics = False
            pov_photons_refraction = True

        # If only Raytrace transparency is set, its IOR will be used for refraction, but user
        # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
        # Last, if none of the above is specified, user can set up 'un-physical' fresnel
        # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
        if material.pov.caustics_enable:
            if pov_fake_caustics:
                tab_write("caustics %.3g\n" % material.pov.fake_caustics_power)
            if pov_photons_refraction:
                # Default of 1 means no dispersion
                tab_write("dispersion %.6f\n" % material.pov.photons_dispersion)
                tab_write("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
        # TODO
        # Other interior args
        if material.pov.use_transparency and material.pov.transparency_method == 'RAYTRACE':
            # fade_distance
            # In Blender this value has always been reversed compared to what tooltip says.
            # 100.001 rather than 100 so that it does not get to 0
            # which deactivates the feature in POV
            tab_write(
                "fade_distance %.3g\n" % (100.001 - material.pov_raytrace_transparency.depth_max)
            )
            # fade_power
            tab_write("fade_power %.3g\n" % material.pov_raytrace_transparency.falloff)
            # fade_color
            tab_write("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])

        # (variable) dispersion_samples (constant count for now)
        tab_write("}\n")
        if material.pov.photons_reflection or material.pov.refraction_type == "2":
            tab_write("photons{")
            tab_write("target %.3g\n" % ob.pov.spacing_multiplier)
            if not ob.pov.collect_photons:
                tab_write("collect off\n")
            if pov_photons_refraction:
                tab_write("refraction on\n")
            if pov_photons_reflection:
                tab_write("reflection on\n")
            tab_write("}\n")


def write_material(
    using_uberpov,
    DEF_MAT_NAME,
    tab_write,
    safety,
    comments,
    unique_name,
    material_names_dictionary,
    material
Maurice Raybaud's avatar
Maurice Raybaud committed
):
    """Translate Blender material to POV texture{} block and write in exported file."""
    # Assumes only called once on each material
    if material:
        name_orig = material.name
        name = material_names_dictionary[name_orig] = unique_name(
            bpy.path.clean_name(name_orig), material_names_dictionary
        # If saturation(.s) is not zero, then color is not grey, and has a tint
Maurice Raybaud's avatar
Maurice Raybaud committed
        colored_specular_found = (material.pov.specular_color.s > 0.0) and (
            material.pov.diffuse_shader != "MINNAERT"
        )
    else:
        name = name_orig = DEF_MAT_NAME
Maurice Raybaud's avatar
Maurice Raybaud committed
    # Several versions of the finish: ref_level_bound conditions are variations for specular/Mirror
    # texture channel map with alternative finish of 0 specular and no mirror reflection.
Maurice Raybaud's avatar
Maurice Raybaud committed
    # ref_level_bound=1 Means No specular nor Mirror reflection
    # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
    # ref_level_bound=3 Means Maximum Spec and Mirror
Maurice Raybaud's avatar
Maurice Raybaud committed
    def pov_has_no_specular_maps(ref_level_bound):
Maurice Raybaud's avatar
Maurice Raybaud committed
        """Translate Blender specular map influence to POV finish map trick and write to file."""
Maurice Raybaud's avatar
Maurice Raybaud committed
        if ref_level_bound == 1:
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("//--No specular nor Mirror reflection--\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("\n")
            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=1))
Maurice Raybaud's avatar
Maurice Raybaud committed
        elif ref_level_bound == 2:
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write(
                    "//--translation of spec and mir levels for when no map " "influences them--\n"
                )
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("\n")
            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=2))
Maurice Raybaud's avatar
Maurice Raybaud committed

Maurice Raybaud's avatar
Maurice Raybaud committed
        elif ref_level_bound == 3:
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("//--Maximum Spec and Mirror--\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("\n")
            tab_write("#declare %s = finish {\n" % safety(name, ref_level_bound=3))
        if material:
            # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
            # (the back diffuse is like blender translucency)
Maurice Raybaud's avatar
Maurice Raybaud committed
            front_diffuse = material.pov.diffuse_intensity
            back_diffuse = material.pov.translucency
Maurice Raybaud's avatar
Maurice Raybaud committed
                # Total should not go above one
                if (front_diffuse + back_diffuse) <= 1.0:
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif front_diffuse == back_diffuse:
                    # Try to respect the user's 'intention' by comparing the two values but
                    # bringing the total back to one.
Maurice Raybaud's avatar
Maurice Raybaud committed
                    front_diffuse = back_diffuse = 0.5
                # Let the highest value stay the highest value.
Maurice Raybaud's avatar
Maurice Raybaud committed
                elif front_diffuse > back_diffuse:
Maurice Raybaud's avatar
Maurice Raybaud committed
                    back_diffuse = min(back_diffuse, (1.0 - front_diffuse))
Maurice Raybaud's avatar
Maurice Raybaud committed
                    front_diffuse = min(front_diffuse, (1.0 - back_diffuse))

            # map hardness between 0.0 and 1.0
Maurice Raybaud's avatar
Maurice Raybaud committed
            roughness = 1.0 - ((material.pov.specular_hardness - 1.0) / 510.0)
            ## scale from 0.0 to 0.1
            roughness *= 0.1
            # add a small value because 0.0 is invalid.
Maurice Raybaud's avatar
Maurice Raybaud committed
            roughness += 1.0 / 511.0
            # ------------------------------ Diffuse Shader ------------------------------ #
Maurice Raybaud's avatar
Maurice Raybaud committed
            # Not used for Full spec (ref_level_bound=3) of the shader.
            if material.pov.diffuse_shader == "OREN_NAYAR" and ref_level_bound != 3:
                # Blender roughness is what is generally called oren nayar Sigma,
                # and brilliance in POV-Ray.
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("brilliance %.3g\n" % (0.9 + material.roughness))
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "TOON" and ref_level_bound != 3:
                tab_write("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
                # Lower diffuse and increase specular for toon effect seems to look better
                # in POV-Ray.
Maurice Raybaud's avatar
Maurice Raybaud committed
                front_diffuse *= 0.5
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "MINNAERT" and ref_level_bound != 3:
                # tab_write("aoi %.3g\n" % material.darkness)
                pass  # let's keep things simple for now
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "FRESNEL" and ref_level_bound != 3:
                # tab_write("aoi %.3g\n" % material.diffuse_fresnel_factor)
                pass  # let's keep things simple for now
Maurice Raybaud's avatar
Maurice Raybaud committed
            if material.pov.diffuse_shader == "LAMBERT" and ref_level_bound != 3:
                # trying to best match lambert attenuation by that constant brilliance value
Maurice Raybaud's avatar
Maurice Raybaud committed
                tab_write("brilliance 1\n")
Loading
Loading full blame...