Newer
Older
Bastien Montagne
committed
# ***** 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 subprocess
import os
import sys
import time
from math import atan, pi, degrees, sqrt, cos, sin
import re
import platform #
import subprocess #
import tempfile # generate temporary files with random names
from bpy.types import Operator
from imghdr import what # imghdr is a python lib to identify image file types
from bpy.utils import register_class
from . import df3 # for smoke rendering
from . import shading # for BI POV shaders emulation
from . import primitives # for import and export of POV specific primitives
from . import nodes # for POV specific nodes
##############################SF###########################
##############find image texture
"""Identify input image filetypes to transmit to POV."""
# First use the below explicit extensions to identify image file prospects
ext = {
'JPG': "jpeg",
'JPEG': "jpeg",
'GIF': "gif",
'TGA': "tga",
'IFF': "iff",
'PPM': "ppm",
'PNG': "png",
'SYS': "sys",
'TIFF': "tiff",
'TIF': "tiff",
'EXR': "exr",
'HDR': "hdr",
}.get(os.path.splitext(imgF)[-1].upper(), "")
# Then, use imghdr to really identify the filetype as it can be different
# maybe add a check for if path exists here?
print(" WARNING: texture image has no extension") # too verbose
ext = what(imgF) # imghdr is a python lib to identify image file types
"""Translate mapping type from Blender UI to POV syntax and return that string."""
image_map = ""
if ts.mapping == 'FLAT':
image_map = "map_type 0 "
elif ts.mapping == 'SPHERE':
elif ts.mapping == 'TUBE':
image_map = "map_type 2 "
## map_type 3 and 4 in development (?) (ENV in pov 3.8)
## for POV-Ray, currently they just seem to default back to Flat (type 0)
# elif ts.mapping=="?":
# elif ts.mapping=="?":
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?)
# print(" No texture image found ")
def imgMapTransforms(ts):
"""Translate mapping transformations from Blender UI to POV syntax and return that string."""
# XXX TODO: unchecked textures give error of variable referenced before assignment XXX
# POV-Ray "scale" is not a number of repetitions factor, but ,its
# inverse, a standard scale factor.
# 0.5 Offset is needed relatively to scale because center of the
# scale is 0.5,0.5 in blender and 0,0 in POV
# Strange that the translation factor for scale is not the same as for
# translate.
# TODO: verify both matches with blender internal.
image_map_transforms = ""
image_map_transforms = (
"scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>"
% (
1.0 / ts.scale.x,
1.0 / ts.scale.y,
1.0 / ts.scale.z,
0.5 - (0.5 / ts.scale.x) - (ts.offset.x),
0.5 - (0.5 / ts.scale.y) - (ts.offset.y),
ts.offset.z,
)
)
# image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
# ( 1.0 / ts.scale.x,
# 1.0 / ts.scale.y,
# 1.0 / ts.scale.z,
# (0.5 / ts.scale.x) + ts.offset.x,
# (0.5 / ts.scale.y) + ts.offset.y,
# ts.offset.z))
# image_map_transforms = ("translate <-0.5,-0.5,0> scale <-1,-1,1> * <%.4g,%.4g,%.4g> translate <0.5,0.5,0> + <%.4g,%.4g,%.4g>" % \
# (1.0 / ts.scale.x,
# 1.0 / ts.scale.y,
# 1.0 / ts.scale.z,
# ts.offset.x,
# ts.offset.y,
# ts.offset.z))
return image_map_transforms
"""Translate world mapping from Blender UI to POV syntax and return that string."""
# texture_coords refers to the mapping of world textures:
if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
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 ")
"""Conform a path string to POV syntax to avoid POV errors."""
return bpy.path.abspath(image.filepath, library=image.library).replace(
"\\", "/"
)
# .replace("\\","/") to get only forward slashes as it's what POV prefers,
Maurice Raybaud
committed
# even on windows
# end find image texture
# -----------------------------------------------------------------------------
"""Remove hyphen characters from a string to avoid POV errors."""
def safety(name, Level):
"""append suffix characters to names of various material declinations.
Material declinations are necessary to POV syntax and used in shading.py
by the povHasnoSpecularMaps function to create the finish map trick and
the suffixes avoid name collisions.
Keyword arguments:
name -- the initial material name as a string
Level -- the enum number of the Level being written:
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
prefix = ""
return prefix + name + "0" # used for 0 of specular map
return prefix + name + "1" # used for 1 of specular map
Maurice Raybaud
committed
##############end safety string name material
##############################EndSF###########################
def is_renderable(scene, ob):
return not ob.hide_render and ob not in csg_list
def renderable_objects(scene):
return [ob for ob in bpy.data.objects if is_renderable(scene, ob)]
def no_renderable_objects(scene):
return [ob for ob in csg_list]
Maurice Raybaud
committed
tabLevel = 0
user_dir = bpy.utils.resource_path('USER')
preview_dir = os.path.join(user_dir, "preview")
## Make sure Preview directory exists and is empty
smokePath = os.path.join(preview_dir, "smoke.df3")
def write_global_setting(scene,file):
file.write("global_settings {\n")
file.write(" assumed_gamma %.6f\n"%scene.pov.assumed_gamma)
if scene.pov.global_settings_advanced:
if scene.pov.radio_enable == False:
file.write(" adc_bailout %.6f\n"%scene.pov.adc_bailout)
file.write(" ambient_light <%.6f,%.6f,%.6f>\n"%scene.pov.ambient_light[:])
file.write(" irid_wavelength <%.6f,%.6f,%.6f>\n"%scene.pov.irid_wavelength[:])
file.write(" charset %s\n"%scene.pov.charset)
file.write(" max_trace_level %s\n"%scene.pov.max_trace_level)
file.write(" max_intersections %s\n"%scene.pov.max_intersections)
file.write(" number_of_waves %s\n"%scene.pov.number_of_waves)
file.write(" noise_generator %s\n"%scene.pov.noise_generator)
# below properties not added to __init__ yet to avoid conflicts with material sss scale
# unless it would override then should be interfaced also in scene units property tab
# if scene.pov.sslt_enable:
# file.write(" mm_per_unit %s\n"%scene.pov.mm_per_unit)
# file.write(" subsurface {\n")
# file.write(" samples %s, %s\n"%(scene.pov.sslt_samples_max,scene.pov.sslt_samples_min))
# if scene.pov.sslt_radiosity:
# file.write(" radiosity on\n")
# file.write("}\n")
if scene.pov.radio_enable:
file.write(" radiosity {\n")
file.write(" pretrace_start %.6f\n"%scene.pov.radio_pretrace_start)
file.write(" pretrace_end %.6f\n"%scene.pov.radio_pretrace_end)
file.write(" count %s\n"%scene.pov.radio_count)
file.write(" nearest_count %s\n"%scene.pov.radio_nearest_count)
file.write(" error_bound %.6f\n"%scene.pov.radio_error_bound)
file.write(" recursion_limit %s\n"%scene.pov.radio_recursion_limit)
file.write(" low_error_factor %.6f\n"%scene.pov.radio_low_error_factor)
file.write(" gray_threshold %.6f\n"%scene.pov.radio_gray_threshold)
file.write(" maximum_reuse %.6f\n"%scene.pov.radio_maximum_reuse)
file.write(" minimum_reuse %.6f\n"%scene.pov.radio_minimum_reuse)
file.write(" brightness %.6f\n"%scene.pov.radio_brightness)
file.write(" adc_bailout %.6f\n"%scene.pov.radio_adc_bailout)
if scene.pov.radio_normal:
if scene.pov.radio_always_sample:
if scene.pov.radio_media:
if scene.pov.radio_subsurface:
file.write(" subsurface on\n")
file.write(" }\n")
if scene.pov.photon_enable:
file.write(" photons {\n")
if scene.pov.photon_enable_count:
file.write(" count %s\n"%scene.pov.photon_count)
else:
file.write(" spacing %.6g\n"%scene.pov.photon_spacing)
if scene.pov.photon_gather:
file.write(" gather %s, %s\n"%(scene.pov.photon_gather_min,scene.pov.photon_gather_max))
if scene.pov.photon_autostop:
file.write(" autostop %.4g\n"%scene.pov.photon_autostop_value)
if scene.pov.photon_jitter_enable:
file.write(" jitter %.4g\n"%scene.pov.photon_jitter)
file.write(" max_trace_level %s\n"%scene.pov.photon_max_trace_level)
if scene.pov.photon_adc:
file.write(" adc_bailout %.6f\n"%scene.pov.photon_adc_bailout)
if scene.pov.photon_media_enable:
file.write(" media %s, %s\n"%(scene.pov.photon_media_steps,scene.pov.photon_media_factor))
if scene.pov.photon_map_file_save_load in {'save'}:
filePhName = 'Photon_map_file.ph'
if scene.pov.photon_map_file != '':
filePhName = scene.pov.photon_map_file+'.ph'
filePhDir = tempfile.gettempdir()
path = bpy.path.abspath(scene.pov.photon_map_dir)
if os.path.exists(path):
filePhDir = path
fullFileName = os.path.join(filePhDir,filePhName)
file.write(' save_file "%s"\n'%fullFileName)
scene.pov.photon_map_file = fullFileName
if scene.pov.photon_map_file_save_load in {'load'}:
fullFileName = bpy.path.abspath(scene.pov.photon_map_file)
if os.path.exists(fullFileName):
file.write(' load_file "%s"\n'%fullFileName)
file.write("}\n")
file.write("}\n")
def write_object_modifiers(scene, ob, File):
"""Translate some object level POV statements from Blender UI
to POV syntax and write to exported file """
# Maybe return that string to be added instead of directly written.
'''XXX WIP
onceCSG = 0
for mod in ob.modifiers:
if onceCSG == 0:
if mod :
if mod.type == 'BOOLEAN':
if ob.pov.boolean_mod == "POV":
File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
(ob.pov.inside_vector[0],
ob.pov.inside_vector[1],
ob.pov.inside_vector[2]))
onceCSG = 1
'''
File.write("\thollow\n")
if ob.pov.double_illuminate:
File.write("\tdouble_illuminate\n")
File.write("\tsturm\n")
File.write("\tno_shadow\n")
File.write("\tno_image\n")
if ob.pov.no_reflection:
File.write("\tno_reflection\n")
if ob.pov.no_radiosity:
File.write("\tno_radiosity\n")
File.write("\tinverse\n")
File.write("\thierarchy\n")
# XXX, Commented definitions
'''
if scene.pov.photon_enable:
File.write("photons {\n")
if ob.pov.target:
File.write("target %.4g\n"%ob.pov.target_value)
if ob.pov.refraction:
File.write("refraction on\n")
if ob.pov.reflection:
File.write("reflection on\n")
if ob.pov.pass_through:
File.write("pass_through\n")
File.write("}\n")
if ob.pov.object_ior > 1:
File.write("interior {\n")
File.write("ior %.4g\n"%ob.pov.object_ior)
if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
File.write("ior %.4g\n"%ob.pov.dispersion_value)
File.write("ior %s\n"%ob.pov.dispersion_samples)
if scene.pov.photon_enable == False:
File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
'''
"""Main export process from Blender UI to POV syntax and write to exported file """
import mathutils
# file = filename
# 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')
comments = scene.pov.comments_enable and not scene.pov.tempfiles_enable
linebreaksinlists = (
scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
)
feature_set = bpy.context.preferences.addons[
__package__
].preferences.branch_feature_set_povray
using_uberpov = feature_set == 'uberpov'
pov_binary = PovrayRender._locate_binary()
if using_uberpov:
print("Unofficial UberPOV feature set chosen in preferences")
else:
print("Official POV-Ray 3.7 feature set chosen in preferences")
print(
"The name of the binary suggests you are probably rendering with Uber POV engine"
)
print(
"The name of the binary suggests you are probably rendering with standard POV engine"
)
Constantin Rahn
committed
def setTab(tabtype, spaces):
TabStr = ""
Campbell Barton
committed
if tabtype == 'NONE':
TabStr = ""
Campbell Barton
committed
elif tabtype == 'TAB':
TabStr = "\t"
Campbell Barton
committed
elif tabtype == 'SPACE':
TabStr = spaces * " "
Constantin Rahn
committed
return TabStr
Bastien Montagne
committed
tab = setTab(scene.pov.indentation_character, scene.pov.indentation_spaces)
if not scene.pov.tempfiles_enable:
"""Indent POV syntax from brackets levels and write to exported file """
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
"""write directly to exported file if user checked autonamed temp files (faster)."""
Constantin Rahn
committed
"""Increment any generated POV name that could get identical to avoid collisions"""
return name
name_orig = name
i = 1
while name in nameSeq:
name = "%s_%.3d" % (name_orig, i)
"""Translate some tranform matrix from Blender UI
to POV syntax and write to exported file """
tabWrite(
"matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n"
% (
matrix[0][0],
matrix[1][0],
matrix[2][0],
matrix[0][1],
matrix[1][1],
matrix[2][1],
matrix[0][2],
matrix[1][2],
matrix[2][2],
matrix[0][3],
matrix[1][3],
matrix[2][3],
)
)
Bastien Montagne
committed
def MatrixAsPovString(matrix):
"""Translate some tranform matrix from Blender UI
to POV syntax and return that string """
sMatrix = (
"matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n"
% (
matrix[0][0],
matrix[1][0],
matrix[2][0],
matrix[0][1],
matrix[1][1],
matrix[2][1],
matrix[0][2],
matrix[1][2],
matrix[2][2],
matrix[0][3],
matrix[1][3],
matrix[2][3],
)
)
Bastien Montagne
committed
return sMatrix
def writeObjectMaterial(material, ob):
"""Translate some object level material from Blender UI (VS data level)
to POV interior{} syntax and write it to exported file """
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
Bastien Montagne
committed
# Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
# if material and material.transparency_method == 'RAYTRACE':
Bastien Montagne
committed
if material:
# But there can be only one!
if (
material.pov_subsurface_scattering.use
): # SSS IOR get highest priority
tabWrite("interior {\n")
tabWrite("ior %.6f\n" % material.pov_subsurface_scattering.ior)
Bastien Montagne
committed
# 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.pov_raytrace_transparency.ior)
elif material.pov.transparency_method == 'Z_TRANSPARENCY':
tabWrite("interior {\n")
tabWrite("ior %.6f\n" % material.pov_raytrace_transparency.ior)
Doug Hammond
committed
pov_fake_caustics = False
pov_photons_refraction = False
pov_photons_reflection = False
Bastien Montagne
committed
if material.pov.photons_reflection:
Maurice Raybaud
committed
if not material.pov.refraction_caustics:
Doug Hammond
committed
pov_fake_caustics = False
pov_photons_refraction = False
Bastien Montagne
committed
elif material.pov.refraction_type == "1":
Doug Hammond
committed
pov_fake_caustics = True
pov_photons_refraction = False
Bastien Montagne
committed
elif material.pov.refraction_type == "2":
Doug Hammond
committed
pov_fake_caustics = False
pov_photons_refraction = True
Bastien Montagne
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:
Doug Hammond
committed
if pov_fake_caustics:
tabWrite(
"caustics %.3g\n" % material.pov.fake_caustics_power
)
Maurice Raybaud
committed
if pov_photons_refraction:
Bastien Montagne
committed
# Default of 1 means no dispersion
tabWrite(
"dispersion %.6f\n" % material.pov.photons_dispersion
)
tabWrite(
"dispersion_samples %.d\n"
% material.pov.photons_dispersion_samples
)
# TODO
if (
material.pov.use_transparency
and material.pov.transparency_method == 'RAYTRACE'
):
Bastien Montagne
committed
# 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.pov_raytrace_transparency.depth_max)
)
tabWrite(
"fade_power %.3g\n"
% material.pov_raytrace_transparency.falloff
)
tabWrite(
"fade_color <%.3g, %.3g, %.3g>\n"
% material.pov.interior_fade_color[:]
)
# (variable) dispersion_samples (constant count for now)
tabWrite("}\n")
if (
material.pov.photons_reflection
or material.pov.refraction_type == "2"
):
tabWrite("photons{")
Maurice Raybaud
committed
tabWrite("target %.3g\n" % ob.pov.spacing_multiplier)
if not ob.pov.collect_photons:
tabWrite("collect off\n")
if pov_photons_refraction:
tabWrite("refraction on\n")
if pov_photons_reflection:
tabWrite("reflection on\n")
tabWrite("}\n")
DEF_MAT_NAME = "" # or "Default"?
"""Translate camera from Blender UI to POV syntax and write to exported file."""
Doug Hammond
committed
# DH disabled for now, this isn't the correct context
active_object = (
None
) # bpy.context.active_object # does not always work MR
matrix = global_matrix @ camera.matrix_world
focal_point = camera.data.dof.focus_distance
Qsize = render.resolution_x / render.resolution_y
tabWrite(
"#declare camLocation = <%.6f, %.6f, %.6f>;\n"
% matrix.translation[:]
)
tabWrite(
"#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
% tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
)
tabWrite("camera {\n")
if (
scene.pov.baking_enable
and active_object
and active_object.type == 'MESH'
):
tabWrite(
"mesh_camera{ 1 3\n"
) # distribution 3 is what we want here
tabWrite("mesh{%s}\n" % active_object.name)
tabWrite("}\n")
tabWrite("location <0,0,.01>")
tabWrite("direction <0,0,-1>")
tabWrite("location <0, 0, 0>\n")
tabWrite("look_at <0, 0, -1>\n")
tabWrite("right <%s, 0, 0>\n" % -Qsize)
tabWrite("up <0, 1, 0>\n")
tabWrite(
"angle %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi)
)
tabWrite(
"rotate <%.6f, %.6f, %.6f>\n"
% tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
)
tabWrite("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
if camera.data.dof.use_dof and (
focal_point != 0 or camera.data.dof.focus_object
):
tabWrite(
"aperture %.3g\n"
% (1 / camera.data.dof.aperture_fstop * 1000)
)
tabWrite(
"blur_samples %d %d\n"
% (
camera.data.pov.dof_samples_min,
camera.data.pov.dof_samples_max,
)
)
Bastien Montagne
committed
tabWrite("variance 1/%d\n" % camera.data.pov.dof_variance)
tabWrite("confidence %.3g\n" % camera.data.pov.dof_confidence)
Maurice Raybaud
committed
if camera.data.dof.focus_object:
focalOb = scene.objects[camera.data.dof.focus_object.name]
matrixBlur = global_matrix @ focalOb.matrix_world
tabWrite(
"focal_point <%.4f,%.4f,%.4f>\n"
% matrixBlur.translation[:]
)
else:
tabWrite("focal_point <0, 0, %f>\n" % focal_point)
if camera.data.pov.normal_enable:
tabWrite(
"normal {%s %.4f turbulence %.4f scale %.4f}\n"
% (
camera.data.pov.normal_patterns,
camera.data.pov.cam_normal,
camera.data.pov.turbulence,
camera.data.pov.scale,
)
)
tabWrite("}\n")
"""Translate lights from Blender UI to POV syntax and write to exported file."""
# Incremented after each lamp export to declare its target
# currently used for Fresnel diffuse shader as their slope vector:
global lampCount
lampCount = 0
# Get all lamps
for ob in lamps:
lamp = ob.data
matrix = global_matrix @ ob.matrix_world
# Color is no longer modified by energy
Maurice Raybaud
committed
color = tuple([c for c in lamp.color])
tabWrite("light_source {\n")
tabWrite("< 0,0,0 >\n")
Maurice Raybaud
committed
tabWrite("color srgb<%.3g, %.3g, %.3g>\n" % color)
tabWrite("spotlight\n")
tabWrite(
"falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0)
) # 1 TO 179 FOR BOTH
tabWrite(
"radius %.6f\n"
% (
(degrees(lamp.spot_size) / 2.0)
* (1.0 - lamp.spot_blend)
)
)
# Blender does not have a tightness equivalent, 0 is most like blender default.
tabWrite("tightness 0\n") # 0:10f
tabWrite("point_at <0, 0, -1>\n")
Maurice Raybaud
committed
tabWrite("looks_like{\n")
tabWrite("sphere{<0,0,0>,%.6f\n" % lamp.distance)
Maurice Raybaud
committed
tabWrite("hollow\n")
tabWrite("material{\n")
tabWrite("texture{\n")
tabWrite(
"pigment{rgbf<1,1,1,%.4f>}\n"
% (lamp.pov.halo_intensity * 5.0)
)
Maurice Raybaud
committed
tabWrite("}\n")
tabWrite("interior{\n")
tabWrite("media{\n")
tabWrite("emission 1\n")
tabWrite("scattering {1, 0.5}\n")
tabWrite("density{\n")
tabWrite("spherical\n")
tabWrite("color_map{\n")
tabWrite("[0.0 rgb <0,0,0>]\n")
tabWrite("[0.5 rgb <1,1,1>]\n")
tabWrite("[1.0 rgb <1,1,1>]\n")
tabWrite("}\n")
tabWrite("}\n")
tabWrite("}\n")
tabWrite("}\n")
tabWrite("}\n")
tabWrite("}\n")
tabWrite("}\n")
tabWrite("parallel\n")
tabWrite("point_at <0, 0, -1>\n") # *must* be after 'parallel'
tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
Bastien Montagne
committed
# Area lights have no falloff type, so always use blenders lamp quad equivalent
# for those?
tabWrite("fade_power %d\n" % 2)
if lamp.shape == 'SQUARE':
size_y = size_x
samples_y = samples_x
else:
size_y = lamp.size_y
tabWrite(
"area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n"
% (size_x, size_y, samples_x, samples_y)
)
tabWrite("area_illumination\n")
if lamp.pov.shadow_ray_sample_method == 'CONSTANT_JITTERED':
if lamp.pov.use_jitter:
tabWrite("jitter\n")
tabWrite("adaptive 1\n")
tabWrite("jitter\n")
# No shadow checked either at global or light level:
if not scene.pov.use_shadows or (
lamp.pov.shadow_method == 'NOSHADOW'
):
tabWrite("shadowless\n")
# Sun shouldn't be attenuated. Area lights have no falloff attribute so they
Bastien Montagne
committed
# are put to type 2 attenuation a little higher above.
if lamp.type not in {'SUN', 'AREA'}:
tabWrite(
"fade_distance %.6f\n" % (sqrt(lamp.distance / 2.0))
)
tabWrite(
"fade_power %d\n" % 2
) # Use blenders lamp quad equivalent
tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
tabWrite("fade_power %d\n" % 1) # Use blenders lamp linear
Bastien Montagne
committed
elif lamp.falloff_type == 'CONSTANT':
tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
# Use blenders lamp constant equivalent no attenuation.
Bastien Montagne
committed
# Using Custom curve for fade power 3 for now.
elif lamp.falloff_type == 'CUSTOM_CURVE':
tabWrite("fade_power %d\n" % 4)
tabWrite("}\n")
lampCount += 1
# v(A,B) rotates vector A about origin by vector B.
file.write(
"#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
% (
lampCount,
-(ob.location.x),
-(ob.location.y),
-(ob.location.z),
ob.rotation_euler.x,
ob.rotation_euler.y,
ob.rotation_euler.z,
)
)
####################################################################################################
def exportRainbows(rainbows):
"""write all POV rainbows primitives to exported file """
povdataname = ob.data.name # enough?
angle = degrees(ob.data.spot_size / 2.5) # radians in blender (2
width = ob.data.spot_blend * 10
# eps=0.0000001
# angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
# width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
# cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
# v(A,B) rotates vector A about origin by vector B.
# and avoid a 0 length vector by adding 1
# file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
# (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
# ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
direction = (
ob.location.x,
ob.location.y,
ob.location.z,
) # not taking matrix into account
rmatrix = global_matrix @ ob.matrix_world
# ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
# XXX Is result of the below offset by 90 degrees?
up = ob.matrix_world.to_3x3()[1].xyz # * global_matrix
# formerly:
# tabWrite("#declare %s = rainbow {\n"%povdataname)
# clumsy for now but remove the rainbow from instancing
# system because not an object. use lamps later instead of meshes
# del data_ref[dataname]
tabWrite("rainbow {\n")
tabWrite("angle %.4f\n" % angle)
tabWrite("width %.4f\n" % width)
tabWrite("distance %.4f\n" % distance)
tabWrite("arc_angle %.4f\n" % ob.pov.arc_angle)
tabWrite("falloff_angle %.4f\n" % ob.pov.falloff_angle)
tabWrite("direction <%.4f,%.4f,%.4f>\n" % rmatrix.translation[:])
tabWrite("up <%.4f,%.4f,%.4f>\n" % (up[0], up[1], up[2]))
tabWrite("color_map {\n")
Maurice Raybaud
committed
tabWrite("[0.000 color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
tabWrite("[0.130 color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
tabWrite("[0.298 color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
tabWrite("[0.412 color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
tabWrite("[0.526 color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
tabWrite("[0.640 color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
tabWrite("[0.754 color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
tabWrite("[0.900 color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
tabWrite("[1.000 color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
povMatName = "Default_texture"
# tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene, ob, file)
# tabWrite("rotate x*90\n")
# matrix = global_matrix @ ob.matrix_world
# writeMatrix(matrix)
# continue #Don't render proxy mesh, skip to next object
################################XXX LOFT, ETC.
def exportCurves(scene, ob):
"""write all curves based POV primitives to exported file """
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.data.name
name = string_strip_hyphen(bpy.path.clean_name(name_orig))
dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
matrix = global_matrix @ ob.matrix_world
bezier_sweep = False
if ob.pov.curveshape == 'sphere_sweep':
# inlined spheresweep macro, which itself calls Shapes.inc:
file.write(' #include "shapes.inc"\n')
file.write(
' #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
)
file.write(' //input adjusting and inspection\n')
file.write(' #if(_resolution <= 1)\n')
file.write(' #local res = 1;\n')
file.write(' #else\n')
file.write(' #local res = int(_resolution);\n')
file.write(' #end\n')
file.write(
' #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n'
)
file.write(' #error ""\n')
file.write(
' #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
)
file.write(' #error ""\n')
file.write(
' #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
)
file.write(' #error ""\n')
file.write(' #else\n')
file.write(
' #local n_of_seg = div(dimension_size(_points_array,1), 4);\n'
)
file.write(' #local ctrl_pts_array = array[n_of_seg]\n')
file.write(' #local ctrl_rs_array = array[n_of_seg]\n')
file.write(' #for(i, 0, n_of_seg-1)\n')
file.write(
' #local ctrl_pts_array[i] = array[4] {_points_array[4*i], _points_array[4*i+1], _points_array[4*i+2], _points_array[4*i+3]}\n'
)
file.write(
' #local ctrl_rs_array[i] = array[4] {abs(_radius_array[4*i]), abs(_radius_array[4*i+1]), abs(_radius_array[4*i+2]), abs(_radius_array[4*i+3])}\n'
)
file.write(' #end\n')
file.write(' #end\n')
file.write(' //drawing\n')
file.write(' #local mockup1 =\n')
file.write(' #if(_merge_shape) merge{ #else union{ #end\n')
file.write(' #for(i, 0, n_of_seg-1)\n')
file.write(' #local has_head = true;\n')
file.write(' #if(i = 0)\n')
file.write(
' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[n_of_seg-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[n_of_seg-1][3] <= 0)\n'
)
file.write(' #local has_head = false;\n')
file.write(' #end\n')
file.write(' #else\n')
file.write(
' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[i-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[i-1][3] <= 0)\n'
)
file.write(' #local has_head = false;\n')
file.write(' #end\n')
file.write(' #end\n')