Skip to content
Snippets Groups Projects
render.py 104 KiB
Newer Older
Campbell Barton's avatar
Campbell Barton committed
# ##### BEGIN GPL LICENSE BLOCK #####
Luca Bonavita's avatar
Luca Bonavita committed
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

Luca Bonavita's avatar
Luca Bonavita committed
import bpy
import subprocess
import os
import sys
import time
Maurice Raybaud's avatar
Maurice Raybaud committed
from math import atan, pi, degrees, sqrt
Luca Bonavita's avatar
Luca Bonavita committed

Maurice Raybaud's avatar
Maurice Raybaud committed
##############################SF###########################
##############find image texture
Maurice Raybaud's avatar
Maurice Raybaud committed
def imageFormat(imgF):
    ext = {
        'JPG': "jpeg",
        'JPEG': "jpeg",
        'GIF': "gif",
        'TGA': "tga",
        'IFF': "iff",
        'PPM': "ppm",
        'PNG': "png",
        'SYS': "sys",
        'TIFF': "tiff",
        'TIF': "tiff",
        'EXR': "exr",  # POV3.7 Only!
        'HDR': "hdr",  # POV3.7 Only! --MR
    }.get(os.path.splitext(imgF)[-1].upper(), "")

        print(" WARNING: texture image format not supported ")
Maurice Raybaud's avatar
Maurice Raybaud committed
    return ext

Maurice Raybaud's avatar
Maurice Raybaud committed
def imgMap(ts):
    image_map = ""
    if ts.mapping == 'FLAT':
        image_map = "map_type 0 "
    elif ts.mapping == 'SPHERE':
        image_map = "map_type 1 "  # map_type 7 in megapov
    elif ts.mapping == 'TUBE':
        image_map = "map_type 2 "

    ## map_type 3 and 4 in development (?)
    ## for POV-Ray, currently they just seem to default back to Flat (type 0)
    #    image_map = " map_type 3 "
    #    image_map = " map_type 4 "
    if ts.texture.use_interpolation:
        image_map += " interpolate 2 "
    if ts.texture.extension == 'CLIP':
        image_map += " once "
    #image_map += "}"
    #if ts.mapping=='CUBE':
    #    image_map+= "warp { cubic } rotate <-90,0,180>"
    # no direct cube type mapping. Though this should work in POV 3.7
    # it doesn't give that good results(best suited to environment maps?)
    #if image_map == "":
    #    print(" No texture image  found ")
Maurice Raybaud's avatar
Maurice Raybaud committed
    return image_map

Maurice Raybaud's avatar
Maurice Raybaud committed
def imgMapBG(wts):
    image_mapBG = ""
    # texture_coords refers to the mapping of world textures:
    if wts.texture_coords == 'VIEW':
        image_mapBG = " map_type 0 "
    elif wts.texture_coords == 'ANGMAP':
        image_mapBG = " map_type 1 "
    elif wts.texture_coords == 'TUBE':
        image_mapBG = " map_type 2 "

    if wts.texture.use_interpolation:
        image_mapBG += " interpolate 2 "
    if wts.texture.extension == 'CLIP':
        image_mapBG += " once "
    #image_mapBG += "}"
    #if wts.mapping == 'CUBE':
    #   image_mapBG += "warp { cubic } rotate <-90,0,180>"
    # no direct cube type mapping. Though this should work in POV 3.7
    # it doesn't give that good results(best suited to environment maps?)
    #if image_mapBG == "":
    #    print(" No background texture image  found ")
Maurice Raybaud's avatar
Maurice Raybaud committed
    return image_mapBG


def findInSubDir(filename, subdirectory=""):
    pahFile = ""
Maurice Raybaud's avatar
Maurice Raybaud committed
    if subdirectory:
        path = subdirectory
    else:
        path = os.getcwd()
    try:
        for root, dirs, names in os.walk(path):
            if filename in names:
                pahFile = os.path.join(root, filename)
        return pahFile
Campbell Barton's avatar
Campbell Barton committed
    except OSError:
Maurice Raybaud's avatar
Maurice Raybaud committed

def path_image(image):
    import os
    fn = bpy.path.abspath(image)
    if not os.path.isfile(fn):
        fn = findInSubDir(os.path.basename(fn), os.path.dirname(bpy.data.filepath))
    fn = os.path.realpath(fn)
Maurice Raybaud's avatar
Maurice Raybaud committed
    return fn

##############end find image texture

def safety(name, Level):
    # safety string name material
    #
    # Level=1 is for texture with No specular nor Mirror reflection
    # Level=2 is for texture with translation of spec and mir levels
    # for when no map influences them
    # Level=3 is for texture with Maximum Spec and Mirror
Maurice Raybaud's avatar
Maurice Raybaud committed
    try:
Campbell Barton's avatar
Campbell Barton committed
        if int(name) > 0:
            prefix = "shader"
Campbell Barton's avatar
Campbell Barton committed
    except:
    prefix = "shader_"
        return prefix + name
        return prefix + name + "0"  # used for 0 of specular map
        return prefix + name + "1"  # used for 1 of specular map
Maurice Raybaud's avatar
Maurice Raybaud committed
##############end safety string name material
##############################EndSF###########################
Luca Bonavita's avatar
Luca Bonavita committed

def is_renderable(scene, ob):
    return (ob.is_visible(scene) and not ob.hide_render)

def renderable_objects(scene):
    return [ob for ob in scene.objects if is_renderable(scene, ob)]

Luca Bonavita's avatar
Luca Bonavita committed
def write_pov(filename, scene=None, info_callback=None):
Maurice Raybaud's avatar
Maurice Raybaud committed
    #file = filename
    file = open(filename, "w")
Luca Bonavita's avatar
Luca Bonavita committed

    # Only for testing
    if not scene:
        scene = bpy.data.scenes[0]

    render = scene.render
    world = scene.world
    global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
        elif tabtype == '1':
    tab = setTab(scene.pov.indentation_character, scene.pov.indentation_spaces)
            global tabLevel
            brackets = str_o.count("{") - str_o.count("}") + str_o.count("[") - str_o.count("]")
            if brackets < 0:
                tabLevel = tabLevel + brackets
            if tabLevel < 0:
                print("Indentation Warning: tabLevel = %s" % tabLevel)
                tabLevel = 0
            if tabLevel >= 1:
                file.write("%s" % tab * tabLevel)
            file.write(str_o)
            if brackets > 0:
                tabLevel = tabLevel + brackets
        else:
            file.write(str_o)
Luca Bonavita's avatar
Luca Bonavita committed
    def uniqueName(name, nameSeq):

        if name not in nameSeq:
Luca Bonavita's avatar
Luca Bonavita committed
            return name

        name_orig = name
        i = 1
        while name in nameSeq:
Luca Bonavita's avatar
Luca Bonavita committed
            i += 1
Luca Bonavita's avatar
Luca Bonavita committed
        return name

    def writeMatrix(matrix):
        tabWrite("matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, " \
                 "%.6f>\n" % (matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1],
                              matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2], matrix[3][0],
                              matrix[3][1], matrix[3][2]))
Luca Bonavita's avatar
Luca Bonavita committed

Campbell Barton's avatar
Campbell Barton committed
        sMatrix = ("matrix <%.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, %.6f,  %.6f, %.6f, " \
                   "%.6f>\n" % (matrix[0][0], matrix[0][1], matrix[0][2], matrix[1][0], matrix[1][1],
                                matrix[1][2], matrix[2][0], matrix[2][1], matrix[2][2], matrix[3][0],
                                matrix[3][1], matrix[3][2]))
    def writeObjectMaterial(material, ob):
        # 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.subsurface_scattering.use:  # SSS IOR get highest priority
                tabWrite("interior {\n")
                tabWrite("ior %.6f\n" % material.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:
                tabWrite("interior {\n")
                tabWrite("ior %.6f\n" % material.raytrace_transparency.ior)
Maurice Raybaud's avatar
Maurice Raybaud committed
            else:
                tabWrite("interior {\n")
                tabWrite("ior %.6f\n" % material.raytrace_transparency.ior)
            pov_fake_caustics = False
            pov_photons_refraction = False
            pov_photons_reflection = False
                pov_photons_reflection = True
                pov_fake_caustics = False
                pov_photons_refraction = False
                pov_fake_caustics = True
                pov_photons_refraction = False
                pov_fake_caustics = False
                pov_photons_refraction = True
Luca Bonavita's avatar
Luca Bonavita committed

            # 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:
                    tabWrite("caustics %.3g\n" % material.pov.fake_caustics_power)
                    # Default of 1 means no dispersion
                    tabWrite("dispersion %.6f\n" % material.pov.photons_dispersion)
                    tabWrite("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
Luca Bonavita's avatar
Luca Bonavita committed
            # Other interior args
            if material.use_transparency and material.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
                tabWrite("fade_distance %.3g\n" % \
                         (100.001 - material.raytrace_transparency.depth_max))
                # fade_power
                tabWrite("fade_power %.3g\n" % material.raytrace_transparency.falloff)
                # fade_color
                tabWrite("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])
Luca Bonavita's avatar
Luca Bonavita committed

Maurice Raybaud's avatar
Maurice Raybaud committed
            # (variable) dispersion_samples (constant count for now)
                tabWrite("collect off\n")
                tabWrite("target %.3g\n" % ob.pov.spacing_multiplier)
            if pov_photons_refraction:
                tabWrite("refraction on\n")
            if pov_photons_reflection:
                tabWrite("reflection on\n")
            tabWrite("}\n")
Luca Bonavita's avatar
Luca Bonavita committed
    materialNames = {}
Luca Bonavita's avatar
Luca Bonavita committed

    def writeMaterial(material):
        # Assumes only called once on each material
        if material:
            name_orig = material.name
        else:
            name_orig = DEF_MAT_NAME

        name = materialNames[name_orig] = uniqueName(bpy.path.clean_name(name_orig), materialNames)
Luca Bonavita's avatar
Luca Bonavita committed

        ##################
        # Several versions of the finish: Level conditions are variations for specular/Mirror
        # texture channel map with alternative finish of 0 specular and no mirror reflection.
        # Level=1 Means No specular nor Mirror reflection
        # Level=2 Means translation of spec and mir levels for when no map influences them
        # Level=3 Means Maximum Spec and Mirror
        def povHasnoSpecularMaps(Level):
Maurice Raybaud's avatar
Maurice Raybaud committed
            if Level == 1:
                tabWrite("#declare %s = finish {" % safety(name, Level=1))
                if not scene.pov.tempfiles_enable and comments:
                    file.write("  //No specular nor Mirror reflection\n")
Maurice Raybaud's avatar
Maurice Raybaud committed
            elif Level == 2:
                tabWrite("#declare %s = finish {" % safety(name, Level=2))
                if not scene.pov.tempfiles_enable and comments:
                    file.write("  //translation of spec and mir levels for when no map " \
                               "influences them\n")
                tabWrite("#declare %s = finish {" % safety(name, Level=3))
                if not scene.pov.tempfiles_enable and comments:
                    file.write("  //Maximum Spec and Mirror\n")
Luca Bonavita's avatar
Luca Bonavita committed

                # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
                # (the back diffuse is like blender translucency)
                frontDiffuse = material.diffuse_intensity
                backDiffuse = material.translucency


                    #Total should not go above one
                    if (frontDiffuse + backDiffuse) <= 1.0:
                        pass
                    elif frontDiffuse == backDiffuse:
                        # Try to respect the user's 'intention' by comparing the two values but
                        # bringing the total back to one.
                        frontDiffuse = backDiffuse = 0.5
                    # Let the highest value stay the highest value.
                    elif frontDiffuse > backDiffuse:
                        # clamps the sum below 1
                        backDiffuse = min(backDiffuse, (1.0 - frontDiffuse))
Maurice Raybaud's avatar
 
Maurice Raybaud committed
                        frontDiffuse = min(frontDiffuse, (1.0 - backDiffuse))

                # map hardness between 0.0 and 1.0
                roughness = ((1.0 - ((material.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.
                roughness += (1.0 / 511.0)
                ################################Diffuse Shader######################################
                # Not used for Full spec (Level=3) of the shader.
                if material.diffuse_shader == 'OREN_NAYAR' and Level != 3:
                    # Blender roughness is what is generally called oren nayar Sigma,
                    # and brilliance in POV-Ray.
                    tabWrite("brilliance %.3g\n" % (0.9 + material.roughness))
                if material.diffuse_shader == 'TOON' and Level != 3:
                    tabWrite("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth *
Loading
Loading full blame...