Newer
Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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 #####
import bpy
import subprocess
import os
import sys
import time
import math
import platform as pltfrm
if pltfrm.architecture()[0] == '64bit':
bitness = 64
else:
bitness = 32
Constantin Rahn
committed
##############################SF###########################
##############find image texture
def splitExt(path):
dotidx = path.rfind('.')
if dotidx == -1:
return path, ''
else:
return (path[dotidx:]).upper().replace('.','')
Maurice Raybaud
committed
ext_orig = splitExt(imgF)
if ext_orig == 'JPG' or ext_orig == 'JPEG': ext='jpeg'
if ext_orig == 'GIF': ext = 'gif'
if ext_orig == 'TGA': ext = 'tga'
if ext_orig == 'IFF': ext = 'iff'
if ext_orig == 'PPM': ext = 'ppm'
if ext_orig == 'PNG': ext = 'png'
if ext_orig == 'SYS': ext = 'sys'
if ext_orig in ('TIFF', 'TIF'): ext = 'tiff'
if ext_orig == 'EXR': ext = 'exr'#POV3.7 Only!
if ext_orig == 'HDR': ext = 'hdr'#POV3.7 Only! --MR
print(imgF)
if not ext: print(' WARNING: texture image format not supported ') # % (imgF , '')) #(ext_orig)))
return ext
def imgMap(ts):
image_map=''
if ts.mapping=='FLAT':image_map= ' map_type 0 '
if ts.mapping=='SPHERE':image_map= ' map_type 1 '# map_type 7 in megapov
if ts.mapping=='TUBE':image_map= ' map_type 2 '
#if ts.mapping=='?':image_map= ' map_type 3 '# map_type 3 and 4 in development (?) for POV-Ray, currently they just seem to default back to Flat (type 0)
#if ts.mapping=='?':image_map= ' map_type 4 '# map_type 3 and 4 in development (?) for POV-Ray, currently they just seem to default back to Flat (type 0)
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 ')
return image_map
def imgMapBG(wts):
image_mapBG=''
if wts.texture_coords== 'VIEW':image_mapBG= ' map_type 0 ' #texture_coords refers to the mapping of world textures
if wts.texture_coords=='ANGMAP':image_mapBG= ' map_type 1 '
if 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 ')
return image_mapBG
def splitFile(path):
idx = path.rfind('/')
if idx == -1:
idx = path.rfind('\\')
return path[idx:].replace('/', '').replace('\\', '')
def splitPath(path):
idx = path.rfind('/')
if idx == -1:
return path, ''
else:
return path[:idx]
def findInSubDir(filename, subdirectory=''):
pahFile=''
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
def path_image(image):
import os
fn = bpy.path.abspath(image)
fn_strip = os.path.basename(fn)
if not os.path.isfile(fn):
fn=(findInSubDir(splitFile(fn),splitPath(bpy.data.filepath)))
()
return fn
##############end find image texture
Maurice Raybaud
committed
def splitHyphen(name):
hyphidx = name.find('-')
if hyphidx == -1:
return name
else:
return (name[hyphidx:]).replace('-','')
def safety(name, Level):
# 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
committed
if int(name) > 0:
prefix='shader'
except:
prefix = ''
Maurice Raybaud
committed
name = splitHyphen(name)
if Level == 2:
return prefix+name
elif Level == 1:
return prefix+name+'0'#used for 0 of specular map
elif Level == 3:
return prefix+name+'1'#used for 1 of specular map
Maurice Raybaud
committed
##############end safety string name material
##############################EndSF###########################
Constantin Rahn
committed
TabLevel = 0
import mathutils
#file = filename
file = open(filename.name, 'w')
# 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')
Constantin Rahn
committed
def setTab(tabtype, spaces):
TabStr = ''
if tabtype == '0':
TabStr = ''
elif tabtype == '1':
TabStr = '\t'
elif tabtype == '2':
TabStr = spaces * ' '
return TabStr
Tab = setTab(scene.pov_indentation_character, scene.pov_indentation_spaces)
Constantin Rahn
committed
def tabWrite(str_o):
global TabLevel
brackets = 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
def uniqueName(name, nameSeq):
if name not in nameSeq:
return name
name_orig = name
i = 1
while name in nameSeq:
name = '%s_%.3d' % (name_orig, i)
i += 1
Maurice Raybaud
committed
name = splitHyphen(name)
Constantin Rahn
committed
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]))
def writeObjectMaterial(material):
Doug Hammond
committed
# DH - modified some variables to be function local, avoiding RNA write
# this should be checked to see if it is functionally correct
if material: #and material.transparency_method == 'RAYTRACE':#Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
#But there can be only one!
if material.subsurface_scattering.use:#SSS IOR get highest priority
Constantin Rahn
committed
tabWrite('interior {\n')
tabWrite('ior %.6f\n' % material.subsurface_scattering.ior)
elif material.pov_mirror_use_IOR:#Then the raytrace IOR taken from raytrace transparency properties and used for reflections if IOR Mirror option is checked
Constantin Rahn
committed
tabWrite('interior {\n')
tabWrite('ior %.6f\n' % material.raytrace_transparency.ior)
Constantin Rahn
committed
tabWrite('interior {\n')
tabWrite('ior %.6f\n' % material.raytrace_transparency.ior)
Doug Hammond
committed
pov_fake_caustics = False
pov_photons_refraction = False
pov_photons_reflection = False
Doug Hammond
committed
pov_fake_caustics = False
pov_photons_refraction = False
Maurice Raybaud
committed
pov_photons_reflection = True #should respond only to proper checkerbox
Doug Hammond
committed
pov_fake_caustics = True
pov_photons_refraction = False
Doug Hammond
committed
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.
Doug Hammond
committed
if pov_fake_caustics:
Constantin Rahn
committed
tabWrite('caustics %.3g\n' % material.pov_fake_caustics_power)
Maurice Raybaud
committed
if pov_photons_refraction:
Constantin Rahn
committed
tabWrite('dispersion %.3g\n' % material.pov_photons_dispersion) #Default of 1 means no dispersion
Maurice Raybaud
committed
#TODO
Maurice Raybaud
committed
# if material.use_transparency and material.transparency_method == 'RAYTRACE':
# fade_distance 2
# fade_power [Value]
# fade_color
# (variable) dispersion_samples (constant count for now)
Constantin Rahn
committed
tabWrite('}\n')
Doug Hammond
committed
if pov_photons_refraction or pov_photons_reflection:
Constantin Rahn
committed
tabWrite('photons{\n')
tabWrite('target\n')
Doug Hammond
committed
if pov_photons_refraction:
Constantin Rahn
committed
tabWrite('refraction on\n')
Doug Hammond
committed
if pov_photons_reflection:
Constantin Rahn
committed
tabWrite('reflection on\n')
tabWrite('}\n')
materialNames = {}
DEF_MAT_NAME = 'Default'
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)
##################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):
Constantin Rahn
committed
tabWrite('#declare %s = finish {' % safety(name, Level = 1))
if comments: file.write(' //No specular nor Mirror reflection\n')
Constantin Rahn
committed
else: tabWrite('\n')
Constantin Rahn
committed
tabWrite('#declare %s = finish {' % safety(name, Level = 2))
if comments: file.write(' //translation of spec and mir levels for when no map influences them\n')
Constantin Rahn
committed
else: tabWrite('\n')
Constantin Rahn
committed
tabWrite('#declare %s = finish {' % safety(name, Level = 3))
if comments: file.write(' //Maximum Spec and Mirror\n')
Constantin Rahn
committed
else: tabWrite('\n')
#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
if material.pov_conserve_energy:
#Total should not go above one
if (frontDiffuse + backDiffuse) <= 1.0:
pass
elif frontDiffuse==backDiffuse:
frontDiffuse = backDiffuse = 0.5 # Try to respect the user's 'intention' by comparing the two values but bringing the total back to one
elif frontDiffuse>backDiffuse: # Let the highest value stay the highest value
backDiffuse = 1-(1-frontDiffuse)
else:
frontDiffuse = 1-(1-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 / 511.0)
#####################################Diffuse Shader######################################
Maurice Raybaud
committed
# Not used for Full spec (Level=3) of the shader
if material.diffuse_shader == 'OREN_NAYAR' and Level != 3:
tabWrite('brilliance %.3g\n' % (0.9+material.roughness))#blender roughness is what is generally called oren nayar Sigma, and brilliance in POV-Ray
if material.diffuse_shader == 'TOON' and Level != 3:
Constantin Rahn
committed
tabWrite('brilliance %.3g\n' % (0.01+material.diffuse_toon_smooth*0.25))
frontDiffuse*=0.5 #Lower diffuse and increase specular for toon effect seems to look better in POV-Ray
if material.diffuse_shader == 'MINNAERT' and Level != 3:
Constantin Rahn
committed
#tabWrite('aoi %.3g\n' % material.darkness)
pass #let's keep things simple for now
if material.diffuse_shader == 'FRESNEL' and Level != 3:
Constantin Rahn
committed
#tabWrite('aoi %.3g\n' % material.diffuse_fresnel_factor)
pass #let's keep things simple for now
if material.diffuse_shader == 'LAMBERT' and Level != 3:
Constantin Rahn
committed
tabWrite('brilliance 1.8\n') #trying to best match lambert attenuation by that constant brilliance value
if Level == 2:
####################################Specular Shader######################################
if material.specular_shader == 'COOKTORR' or material.specular_shader == 'PHONG':#No difference between phong and cook torrence in blender HaHa!
Constantin Rahn
committed
tabWrite('phong %.3g\n' % (material.specular_intensity))
tabWrite('phong_size %.3g\n'% (material.specular_hardness / 2 + 0.25))
if material.specular_shader == 'BLINN':#POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
Constantin Rahn
committed
tabWrite('specular %.3g\n' % (material.specular_intensity * (material.specular_ior/4))) #Use blender Blinn's IOR just as some factor for spec intensity
tabWrite('roughness %.3g\n' % roughness)
#Could use brilliance 2(or varying around 2 depending on ior or factor) too.
if material.specular_shader == 'TOON':
Constantin Rahn
committed
tabWrite('phong %.3g\n' % (material.specular_intensity * 2))
tabWrite('phong_size %.3g\n' % (0.1+material.specular_toon_smooth / 2)) #use extreme phong_size
if material.specular_shader == 'WARDISO':
Constantin Rahn
committed
tabWrite('specular %.3g\n' % (material.specular_intensity / (material.specular_slope+0.0005))) #find best suited default constant for brilliance Use both phong and specular for some values.
tabWrite('roughness %.4g\n' % (0.0005+material.specular_slope/10)) #find best suited default constant for brilliance Use both phong and specular for some values.
tabWrite('brilliance %.4g\n' % (1.8-material.specular_slope*1.8)) #find best suited default constant for brilliance Use both phong and specular for some values.
Loading
Loading full blame...