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 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
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),
# 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.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."""
Maurice Raybaud
committed
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
##############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
unpacked_images=[]
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)
'''
Campbell Barton
committed
"""Main export process from Blender UI to POV syntax and write to exported file """
import mathutils
# 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:
def tabWrite(str_o):
"""Indent POV syntax from brackets levels and write to exported file """
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
"""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':
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 1.0\n")
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:
Bastien Montagne
committed
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)
Maurice Raybaud
committed
tabWrite("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
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
Bastien Montagne
committed
tabWrite("fade_distance %.3g\n" % \
(100.001 - material.pov_raytrace_transparency.depth_max))
tabWrite("fade_power %.3g\n" % material.pov_raytrace_transparency.falloff)
Bastien Montagne
committed
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" %
Bastien Montagne
committed
tuple([degrees(e) for e in matrix.to_3x3().to_euler()]))
tabWrite("camera {\n")
Bastien Montagne
committed
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))
Bastien Montagne
committed
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):
Maurice Raybaud
committed
tabWrite("aperture %.3g\n" % (1/camera.data.dof.aperture_fstop*1000))
Bastien Montagne
committed
tabWrite("blur_samples %d %d\n" % \
(camera.data.pov.dof_samples_min, camera.data.pov.dof_samples_max))
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
Bastien Montagne
committed
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)
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
Maurice Raybaud
committed
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.
Bastien Montagne
committed
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))
Bastien Montagne
committed
####################################################################################################
def exportRainbows(rainbows):
"""write all POV rainbows primitives to exported file """
for ob in rainbows:
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
# formerly:
#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
#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)
tabWrite("}\n")
#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':
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
#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')
file.write(' #if(has_head = true)\n')
file.write(' sphere{\n')
file.write(' ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n')
file.write(' }\n')
file.write(' #end\n')
file.write(' #local para_t = (1/2)/res;\n')
file.write(' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n')
file.write(' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n')
file.write(' #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n')
file.write(' object{\n')
file.write(' Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n')
file.write(' }\n')
file.write(' #end\n')
file.write(' sphere{\n')
file.write(' this_point, this_radius\n')
file.write(' }\n')
file.write(' #for(j, 1, res-1)\n')
file.write(' #local last_point = this_point;\n')
file.write(' #local last_radius = this_radius;\n')
file.write(' #local para_t = (1/2+j)/res;\n')
file.write(' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n')
file.write(' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n')
file.write(' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n')
file.write(' object{\n')
file.write(' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n')
file.write(' }\n')
file.write(' #end\n')
file.write(' sphere{\n')
file.write(' this_point, this_radius\n')
file.write(' }\n')
file.write(' #end\n')
file.write(' #local last_point = this_point;\n')
file.write(' #local last_radius = this_radius;\n')
file.write(' #local this_point = ctrl_pts_array[i][3];\n')
file.write(' #local this_radius = ctrl_rs_array[i][3];\n')
file.write(' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n')
file.write(' object{\n')
file.write(' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n')
file.write(' }\n')
file.write(' #end\n')
file.write(' sphere{\n')
file.write(' this_point, this_radius\n')
file.write(' }\n')
file.write(' #end\n')
file.write(' }\n')
file.write(' mockup1\n')
file.write(' #end\n')
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
for spl in ob.data.splines:
if spl.type == "BEZIER":
bezier_sweep = True
if ob.pov.curveshape in {'loft','birail'}:
n=0
for spline in ob.data.splines:
n+=1
tabWrite('#declare %s%s=spline {\n'%(dataname,n))
tabWrite('cubic_spline\n')
lp = len(spline.points)
delta = 1/(lp)
d=-delta
point = spline.points[lp-1]
x,y,z,w = point.co[:]
tabWrite('%.6f, <%.6f,%.6f,%.6f>\n'%(d,x,y,z))
d+=delta
for point in spline.points:
x,y,z,w = point.co[:]
tabWrite('%.6f, <%.6f,%.6f,%.6f>\n'%(d,x,y,z))
d+=delta
for i in range(2):
point = spline.points[i]
x,y,z,w = point.co[:]
tabWrite('%.6f, <%.6f,%.6f,%.6f>\n'%(d,x,y,z))
d+=delta
tabWrite('}\n')
if ob.pov.curveshape in {'loft'}:
n = len(ob.data.splines)
tabWrite('#declare %s = array[%s]{\n'%(dataname,(n+3)))
tabWrite('spline{%s%s},\n'%(dataname,n))
for i in range(n):
tabWrite('spline{%s%s},\n'%(dataname,(i+1)))
tabWrite('spline{%s1},\n'%(dataname))
tabWrite('spline{%s2}\n'%(dataname))
tabWrite('}\n')
# Use some of the Meshmaker.inc macro, here inlined
file.write('#macro CheckFileName(FileName)\n')
file.write(' #local Len=strlen(FileName);\n')
file.write(' #if(Len>0)\n')
file.write(' #if(file_exists(FileName))\n')
file.write(' #if(Len>=4)\n')
file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
file.write(' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n')
file.write(' #local Return=99;\n')
file.write(' #else\n')
file.write(' #local Return=0;\n')
file.write(' #end\n')
file.write(' #else\n')
file.write(' #local Return=0;\n')
file.write(' #end\n')
file.write(' #else\n')
file.write(' #if(Len>=4)\n')
file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
file.write(' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n')
file.write(' #if (strcmp(Ext,".obj")=0)\n')
file.write(' #local Return=2;\n')
file.write(' #end\n')
file.write(' #if (strcmp(Ext,".pcm")=0)\n')
file.write(' #local Return=3;\n')
file.write(' #end\n')
file.write(' #if (strcmp(Ext,".arr")=0)\n')
file.write(' #local Return=4;\n')
file.write(' #end\n')
file.write(' #else\n')
file.write(' #local Return=1;\n')
file.write(' #end\n')
file.write(' #else\n')
file.write(' #local Return=1;\n')
file.write(' #end\n')
file.write(' #end\n')
file.write(' #else\n')
file.write(' #local Return=1;\n')
file.write(' #end\n')
file.write(' (Return)\n')
file.write('#end\n')
file.write('#macro BuildSpline(Arr, SplType)\n')
file.write(' #local Ds=dimension_size(Arr,1);\n')
file.write(' #local Asc=asc(strupr(SplType));\n')
file.write(' #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
file.write(' #local Asc=76;\n')
file.write(' #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n')
file.write(' #end\n')
file.write(' spline {\n')
file.write(' #switch (Asc)\n')
file.write(' #case (67) //C cubic_spline\n')
file.write(' cubic_spline\n')
file.write(' #break\n')
file.write(' #case (76) //L linear_spline\n')
file.write(' linear_spline\n')
file.write(' #break\n')
file.write(' #case (78) //N linear_spline\n')
file.write(' natural_spline\n')
file.write(' #break\n')
file.write(' #case (81) //Q Quadratic_spline\n')
file.write(' quadratic_spline\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' #local Add=1/((Ds-2)-1);\n')
file.write(' #local J=0-Add;\n')
file.write(' #local I=0;\n')
file.write(' #while (I<Ds)\n')
file.write(' J\n')
file.write(' Arr[I]\n')
file.write(' #local I=I+1;\n')
file.write(' #local J=J+Add;\n')
file.write(' #end\n')
file.write(' }\n')
file.write('#end\n')
file.write('#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n')
#suppressed some file checking from original macro because no more separate files
file.write(' #local Write=0;\n')
file.write(' #debug concat("\\n\\n Building mesh2: \\n - vertex_vectors\\n")\n')
file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
file.write(' #switch (Write)\n')
file.write(' #case(1)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' " vertex_vectors {\\n",\n')
file.write(' " ", str(NumVertices,0,0),"\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' str(2*NumVertices,0,0),",\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' mesh2 {\n')
file.write(' vertex_vectors {\n')
file.write(' NumVertices\n')
file.write(' #local I=0;\n')
file.write(' #while (I<NumVertices)\n')
file.write(' VecArr[I]\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile, VecArr[I])\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(MeshFile, VecArr[I])\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' #local I=I+1;\n')
file.write(' #if(Write=1 | Write=4)\n')
file.write(' #if(mod(I,3)=0)\n')
file.write(' #write(MeshFile,"\\n ")\n')
file.write(' #end\n')
file.write(' #end \n')
file.write(' #end\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile,"\\n }\\n")\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(MeshFile,"\\n")\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' // do nothing\n')
file.write(' #break\n')
file.write(' #case(4) \n')
file.write(' #write(MeshFile,"\\n}\\n")\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' }\n')
file.write(' #debug concat(" - normal_vectors\\n") \n')
file.write(' #local NumVertices=dimension_size(NormArr,1);\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' " normal_vectors {\\n",\n')
file.write(' " ", str(NumVertices,0,0),"\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "# Normals: ",str(NumVertices,0,0),"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' // do nothing\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' normal_vectors {\n')
file.write(' NumVertices\n')
file.write(' #local I=0;\n')
file.write(' #while (I<NumVertices)\n')
file.write(' NormArr[I]\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile NormArr[I])\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(MeshFile NormArr[I])\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' #local I=I+1;\n')
file.write(' #if(Write=1 | Write=4) \n')
file.write(' #if(mod(I,3)=0)\n')
file.write(' #write(MeshFile,"\\n ")\n')
file.write(' #end\n')
file.write(' #end\n')
file.write(' #end\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile,"\\n }\\n")\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(MeshFile,"\\n")\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' //do nothing\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(MeshFile,"\\n}\\n")\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' }\n')
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
file.write(' #debug concat(" - uv_vectors\\n") \n')
file.write(' #local NumVertices=dimension_size(UVArr,1);\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(\n')
file.write(' MeshFile, \n')
file.write(' " uv_vectors {\\n",\n')
file.write(' " ", str(NumVertices,0,0),"\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' // do nothing, *.pcm does not support uv-vectors\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' uv_vectors {\n')
file.write(' NumVertices\n')
file.write(' #local I=0;\n')
file.write(' #while (I<NumVertices)\n')
file.write(' UVArr[I]\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile UVArr[I])\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' //do nothing\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(MeshFile UVArr[I])\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' #local I=I+1; \n')
file.write(' #if(Write=1 | Write=4)\n')
file.write(' #if(mod(I,3)=0)\n')
file.write(' #write(MeshFile,"\\n ")\n')
file.write(' #end \n')
file.write(' #end\n')
file.write(' #end \n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile,"\\n }\\n")\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(MeshFile,"\\n")\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' //do nothing\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(MeshFile,"\\n}\\n")\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' }\n')
file.write('\n')
file.write(' #debug concat(" - face_indices\\n") \n')
file.write(' #declare NumFaces=U*V*2;\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' " face_indices {\\n"\n')
file.write(' " ", str(NumFaces,0,0),"\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write (\n')
file.write(' MeshFile,\n')
file.write(' "# faces: ",str(NumFaces,0,0),"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' #write (\n')
file.write(' MeshFile,\n')
file.write(' "0,",str(NumFaces,0,0),",\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n "\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' face_indices {\n')
file.write(' NumFaces\n')
file.write(' #local I=0;\n')
file.write(' #local H=0;\n')
file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
file.write(' #while (I<V)\n')
file.write(' #local J=0;\n')
file.write(' #while (J<U)\n')
file.write(' #local Ind=(I*U)+I+J;\n')
file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n')
file.write(' "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n')
file.write(' Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(\n')
file.write(' MeshFile,\n')
file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
file.write(' )\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' #local J=J+1;\n')
file.write(' #local H=H+1;\n')
file.write(' #if(Write=1 | Write=4)\n')
file.write(' #if(mod(H,3)=0)\n')
file.write(' #write(MeshFile,"\\n ")\n')
file.write(' #end \n')
file.write(' #end\n')
file.write(' #end\n')
file.write(' #local I=I+1;\n')
file.write(' #end\n')
file.write(' }\n')
file.write(' #switch(Write)\n')
file.write(' #case(1)\n')
file.write(' #write(MeshFile, "\\n }\\n}")\n')
file.write(' #fclose MeshFile\n')
file.write(' #debug concat(" Done writing\\n")\n')
file.write(' #break\n')
file.write(' #case(2)\n')
file.write(' #fclose MeshFile\n')
file.write(' #debug concat(" Done writing\\n")\n')
file.write(' #break\n')
file.write(' #case(3)\n')
file.write(' #fclose MeshFile\n')
file.write(' #debug concat(" Done writing\\n")\n')
file.write(' #break\n')
file.write(' #case(4)\n')
file.write(' #write(MeshFile, "\\n}\\n}")\n')
file.write(' #fclose MeshFile\n')
file.write(' #debug concat(" Done writing\\n")\n')
file.write(' #break\n')
file.write(' #end\n')
file.write(' }\n')
file.write('#end\n')
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
file.write('#macro MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)\n')
file.write(' #declare Build=CheckFileName(FileName);\n')
file.write(' #if(Build=0)\n')
file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
file.write(' #include FileName\n')
file.write(' object{Surface}\n')
file.write(' #else\n')
file.write(' #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
file.write(' #local NumFaces=SplRes*InterpRes*2;\n')
file.write(' #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n')
file.write(' #local VecArr=array[NumVertices]\n')
file.write(' #local NormArr=array[NumVertices]\n')
file.write(' #local UVArr=array[NumVertices]\n')
file.write(' #local N=dimension_size(SplineArray,1);\n')
file.write(' #local TempSplArr0=array[N];\n')
file.write(' #local TempSplArr1=array[N];\n')
file.write(' #local TempSplArr2=array[N];\n')
file.write(' #local PosStep=1/SplRes;\n')
file.write(' #local InterpStep=1/InterpRes;\n')
file.write(' #local Count=0;\n')
file.write(' #local Pos=0;\n')
file.write(' #while(Pos<=1)\n')
file.write(' #local I=0;\n')
file.write(' #if (Pos=0)\n')
file.write(' #while (I<N)\n')
file.write(' #local Spl=spline{SplineArray[I]}\n')
file.write(' #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n')
file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
file.write(' #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n')
file.write(' #local I=I+1;\n')
file.write(' #end\n')
file.write(' #local S0=BuildSpline(TempSplArr0, Interp_type)\n')
file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
file.write(' #local S2=BuildSpline(TempSplArr2, Interp_type)\n')
file.write(' #else\n')
file.write(' #while (I<N)\n')
file.write(' #local Spl=spline{SplineArray[I]}\n')
file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
file.write(' #local I=I+1;\n')
file.write(' #end\n')
file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
file.write(' #end\n')
file.write(' #local J=0;\n')
file.write(' #while (J<=1)\n')
file.write(' #local P0=<0,0,0>+S0(J);\n')
file.write(' #local P1=<0,0,0>+S1(J);\n')
file.write(' #local P2=<0,0,0>+S2(J);\n')
file.write(' #local P3=<0,0,0>+S0(J+InterpStep);\n')
file.write(' #local P4=<0,0,0>+S0(J-InterpStep);\n')
file.write(' #local B1=P4-P0;\n')
file.write(' #local B2=P2-P0;\n')
file.write(' #local B3=P3-P0;\n')
file.write(' #local B4=P1-P0;\n')
file.write(' #local N1=vcross(B1,B2);\n')
file.write(' #local N2=vcross(B2,B3);\n')
file.write(' #local N3=vcross(B3,B4);\n')
file.write(' #local N4=vcross(B4,B1);\n')
file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
file.write(' #local VecArr[Count]=P0;\n')
file.write(' #local NormArr[Count]=Norm;\n')
file.write(' #local UVArr[Count]=<J,Pos>;\n')
file.write(' #local J=J+InterpStep;\n')
file.write(' #local Count=Count+1;\n')
file.write(' #end\n')
file.write(' #local S2=spline{S0}\n')
file.write(' #local S0=spline{S1}\n')
file.write(' #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n')
file.write(' #local Pos=Pos+PosStep;\n')
file.write(' #end\n')
file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n')
file.write(' #end\n')
file.write('#end\n\n')
file.write('#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n')
file.write(' #declare Build=CheckFileName(FileName);\n')
file.write(' #if(Build=0)\n')
file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
file.write(' #include FileName\n')
file.write(' object{Surface}\n')
file.write(' #else\n')
file.write(' #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
file.write(' #local NumFaces=Iter_U*Iter_V*2;\n')
file.write(' #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n')
file.write(' #declare VecArr=array[NumVertices] \n')
file.write(' #declare NormArr=array[NumVertices] \n')
file.write(' #local UVArr=array[NumVertices] \n')
file.write(' #local Spl1_0=Spl1(0);\n')
file.write(' #local Spl2_0=Spl2(0);\n')
file.write(' #local Spl3_0=Spl3(0);\n')
file.write(' #local Spl4_0=Spl4(0);\n')
file.write(' #local UStep=1/Iter_U;\n')
file.write(' #local VStep=1/Iter_V;\n')
file.write(' #local Count=0;\n')
file.write(' #local I=0;\n')
file.write(' #while (I<=1)\n')
file.write(' #local Im=1-I;\n')
file.write(' #local J=0;\n')
file.write(' #while (J<=1)\n')
file.write(' #local Jm=1-J;\n')
file.write(' #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n')
file.write(' #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n')
file.write(' LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n')
file.write(' #declare VecArr[Count]=P0;\n')
file.write(' #local UVArr[Count]=<J,I>;\n')
file.write(' #local J=J+UStep;\n')
file.write(' #local Count=Count+1;\n')
file.write(' #end\n')
file.write(' #debug concat(\n')
file.write(' "\r Done ", str(Count,0,0)," vertices : ",\n')
file.write(' str(100*Count/NumVertices,0,2)," %"\n')
file.write(' )\n')
file.write(' #local I=I+VStep;\n')
file.write(' #end\n')
file.write(' #debug "\r Normals "\n')
file.write(' #local Count=0;\n')
file.write(' #local I=0;\n')
file.write(' #while (I<=Iter_V)\n')
file.write(' #local J=0;\n')
file.write(' #while (J<=Iter_U)\n')
file.write(' #local Ind=(I*Iter_U)+I+J;\n')
file.write(' #local P0=VecArr[Ind];\n')
file.write(' #if(J=0)\n')
file.write(' #local P1=P0+(P0-VecArr[Ind+1]);\n')
file.write(' #else\n')
file.write(' #local P1=VecArr[Ind-1];\n')
file.write(' #end\n')
file.write(' #if (J=Iter_U)\n')
file.write(' #local P2=P0+(P0-VecArr[Ind-1]);\n')
file.write(' #else\n')
file.write(' #local P2=VecArr[Ind+1];\n')
file.write(' #end\n')
file.write(' #if (I=0)\n')
file.write(' #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n')
file.write(' #else\n')
file.write(' #local P3=VecArr[Ind-Iter_U-1];\n')
file.write(' #end\n')
file.write(' #if (I=Iter_V)\n')
file.write(' #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n')
file.write(' #else\n')
file.write(' #local P4=VecArr[Ind+Iter_U+1];\n')
file.write(' #end\n')
file.write(' #local B1=P4-P0;\n')
file.write(' #local B2=P2-P0;\n')
file.write(' #local B3=P3-P0;\n')
file.write(' #local B4=P1-P0;\n')
file.write(' #local N1=vcross(B1,B2);\n')
file.write(' #local N2=vcross(B2,B3);\n')
file.write(' #local N3=vcross(B3,B4);\n')
file.write(' #local N4=vcross(B4,B1);\n')
file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
file.write(' #declare NormArr[Count]=Norm;\n')
file.write(' #local J=J+1;\n')
file.write(' #local Count=Count+1;\n')
file.write(' #end\n')
file.write(' #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n')
file.write(' #local I=I+1;\n')
file.write(' #end\n')
file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n')
file.write(' #end\n')
file.write('#end\n\n')
Maurice Raybaud
committed
# Empty curves
Maurice Raybaud
committed
if len(ob.data.splines)==0:
tabWrite("\n//dummy sphere to represent empty curve location\n")
tabWrite("#declare %s =\n"%dataname)
tabWrite("sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n" % (ob.location.x, ob.location.y, ob.location.z)) # ob.name > povdataname)
# And non empty curves
Maurice Raybaud
committed
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
else:
if bezier_sweep == False:
tabWrite("#declare %s =\n"%dataname)
if ob.pov.curveshape == 'sphere_sweep' and bezier_sweep == False:
tabWrite("union {\n")
for spl in ob.data.splines:
if spl.type != "BEZIER":
spl_type = "linear"
if spl.type == "NURBS":
spl_type = "cubic"
points=spl.points
numPoints=len(points)
if spl.use_cyclic_u:
numPoints+=3
tabWrite("sphere_sweep { %s_spline %s,\n"%(spl_type,numPoints))
if spl.use_cyclic_u:
pt1 = points[len(points)-1]
wpt1 = pt1.co
tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt1[0], wpt1[1], wpt1[2], pt1.radius*ob.data.bevel_depth))
for pt in points:
wpt = pt.co
tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt[0], wpt[1], wpt[2], pt.radius*ob.data.bevel_depth))
if spl.use_cyclic_u:
for i in range (0,2):
endPt=points[i]
wpt = endPt.co
tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt[0], wpt[1], wpt[2], endPt.radius*ob.data.bevel_depth))
Maurice Raybaud
committed
tabWrite("}\n")
# below not used yet?
Maurice Raybaud
committed
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
if ob.pov.curveshape == 'sor':
for spl in ob.data.splines:
if spl.type in {'POLY','NURBS'}:
points=spl.points
numPoints=len(points)
tabWrite("sor { %s,\n"%numPoints)
for pt in points:
wpt = pt.co
tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
else:
tabWrite("box { 0,0\n")
if ob.pov.curveshape in {'lathe','prism'}:
spl = ob.data.splines[0]
if spl.type == "BEZIER":
points=spl.bezier_points
lenCur=len(points)-1
lenPts=lenCur*4
ifprism = ''
if ob.pov.curveshape in {'prism'}:
height = ob.data.extrude
ifprism = '-%s, %s,'%(height, height)
lenCur+=1
lenPts+=4
tabWrite("%s { bezier_spline %s %s,\n"%(ob.pov.curveshape,ifprism,lenPts))
for i in range(0,lenCur):
p1=points[i].co
pR=points[i].handle_right
end = i+1
if i == lenCur-1 and ob.pov.curveshape in {'prism'}:
end = 0
pL=points[end].handle_left
p2=points[end].co
line="<%.4g,%.4g>"%(p1[0],p1[1])
line+="<%.4g,%.4g>"%(pR[0],pR[1])
line+="<%.4g,%.4g>"%(pL[0],pL[1])
line+="<%.4g,%.4g>"%(p2[0],p2[1])
tabWrite("%s\n" %line)
else:
Maurice Raybaud
committed
lenCur=len(points)
lenPts=lenCur
ifprism = ''
if ob.pov.curveshape in {'prism'}:
height = ob.data.extrude
ifprism = '-%s, %s,'%(height, height)
lenPts+=3
spl_type = 'quadratic'
if spl.type == 'POLY':
spl_type = 'linear'
tabWrite("%s { %s_spline %s %s,\n"%(ob.pov.curveshape,spl_type,ifprism,lenPts))
if ob.pov.curveshape in {'prism'}:
pt = points[len(points)-1]
wpt = pt.co
tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
Maurice Raybaud
committed
for pt in points:
wpt = pt.co
tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
Maurice Raybaud
committed
if ob.pov.curveshape in {'prism'}:
for i in range(2):
pt = points[i]
wpt = pt.co
tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
if bezier_sweep:
for p in range(len(ob.data.splines)):
Maurice Raybaud
committed
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
br = []
depth = ob.data.bevel_depth
spl = ob.data.splines[p]
points=spl.bezier_points
lenCur = len(points)-1
numPoints = lenCur*4
if spl.use_cyclic_u:
lenCur += 1
numPoints += 4
tabWrite("#declare %s_points_%s = array[%s]{\n"%(dataname,p,numPoints))
for i in range(lenCur):
p1=points[i].co
pR=points[i].handle_right
end = i+1
if spl.use_cyclic_u and i == (lenCur - 1):
end = 0
pL=points[end].handle_left
p2=points[end].co
r3 = points[end].radius * depth
r0 = points[i].radius * depth
r1 = 2/3*r0 + 1/3*r3
r2 = 1/3*r0 + 2/3*r3
br.append((r0,r1,r2,r3))
line="<%.4g,%.4g,%.4f>"%(p1[0],p1[1],p1[2])
line+="<%.4g,%.4g,%.4f>"%(pR[0],pR[1],pR[2])
line+="<%.4g,%.4g,%.4f>"%(pL[0],pL[1],pL[2])
line+="<%.4g,%.4g,%.4f>"%(p2[0],p2[1],p2[2])
tabWrite("%s\n" %line)
tabWrite("}\n")
tabWrite("#declare %s_radii_%s = array[%s]{\n"%(dataname,p,len(br)*4))
for Tuple in br:
tabWrite('%.4f,%.4f,%.4f,%.4f\n'%(Tuple[0],Tuple[1],Tuple[2],Tuple[3]))
tabWrite("}\n")
if len(ob.data.splines)== 1:
tabWrite('#declare %s = object{\n'%dataname)
tabWrite(' Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'%(ob.data.resolution_u,dataname,p,dataname,p))
else:
tabWrite('#declare %s = union{\n'%dataname)
for p in range(len(ob.data.splines)):
tabWrite(' object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'%(ob.data.resolution_u,dataname,p,dataname,p))
#tabWrite('#include "bezier_spheresweep.inc"\n') #now inlined
# tabWrite('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
if ob.pov.curveshape in {'loft'}:
tabWrite('object {MSM(%s,%s,"c",%s,"")\n'%(dataname,ob.pov.res_u,ob.pov.res_v))
if ob.pov.curveshape in {'birail'}:
splines = '%s1,%s2,%s3,%s4'%(dataname,dataname,dataname,dataname)
tabWrite('object {Coons(%s, %s, %s, "")\n'%(splines,ob.pov.res_u,ob.pov.res_v))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
if ob.pov.curveshape in {'prism'}:
tabWrite("rotate <90,0,0>\n")
tabWrite("scale y*-1\n" )
tabWrite("}\n")
#################################################################
"""write all POV blob primitives and Blender Metas to exported file """
if comments and len(metas) >= 1:
file.write("//--Blob objects--\n\n")
# Get groups of metaballs by blender name prefix.
meta_group = {}
meta_elems = {}
Maurice Raybaud
committed
prefix = ob.name.split(".")[0]
if not prefix in meta_group:
meta_group[prefix] = ob # .data.threshold
Maurice Raybaud
committed
elems = [(elem, ob) for elem in ob.data.elements if elem.type in {'BALL', 'ELLIPSOID','CAPSULE','CUBE','PLANE'}]
if prefix in meta_elems:
meta_elems[prefix].extend(elems)
Maurice Raybaud
committed
else:
Maurice Raybaud
committed
# empty metaball
if len(elems)==0:
tabWrite("\n//dummy sphere to represent empty meta location\n")
tabWrite("sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n" % (ob.location.x, ob.location.y, ob.location.z)) # ob.name > povdataname)
# other metaballs
else:
Maurice Raybaud
committed
for mg, ob in meta_group.items():
Maurice Raybaud
committed
tabWrite("blob{threshold %.4g // %s \n" % (ob.data.threshold, mg))
for elems in meta_elems[mg]:
elem = elems[0]
loc = elem.co
stiffness = elem.stiffness
if elem.use_negative:
stiffness = - stiffness
if elem.type == 'BALL':
tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g " %
(loc.x, loc.y, loc.z, elem.radius, stiffness))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
elif elem.type == 'ELLIPSOID':
tabWrite("sphere{ <%.6g, %.6g, %.6g>,%.4g,%.4g " %
(loc.x / elem.size_x, loc.y / elem.size_y, loc.z / elem.size_z,
elem.radius, stiffness))
tabWrite("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
elif elem.type == 'CAPSULE':
tabWrite("cylinder{ <%.6g, %.6g, %.6g>,<%.6g, %.6g, %.6g>,%.4g,%.4g " %
((loc.x - elem.size_x), (loc.y), (loc.z),
(loc.x + elem.size_x), (loc.y), (loc.z),
elem.radius, stiffness))
#tabWrite("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
tabWrite("}\n")
elif elem.type == 'CUBE':
tabWrite("cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n" % (elem.radius*2.0, stiffness/4.0, loc.x, loc.y, loc.z, elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
tabWrite("}\n")
tabWrite("cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n" % (elem.radius*2.0, stiffness/4.0, loc.x, loc.y, loc.z, elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
tabWrite("cylinder { -z*8, +z*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1,1/4> scale <%.6g, %.6g, %.6g>\n" % (elem.radius*2.0, stiffness/4.0, loc.x, loc.y, loc.z, elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
tabWrite("}\n")
Maurice Raybaud
committed
elif elem.type == 'PLANE':
tabWrite("cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n" % (elem.radius*2.0, stiffness/4.0, loc.x, loc.y, loc.z, elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
tabWrite("}\n")
tabWrite("cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n" % (elem.radius*2.0, stiffness/4.0, loc.x, loc.y, loc.z, elem.size_x, elem.size_y, elem.size_z))
writeMatrix(global_matrix @ elems[1].matrix_world)
Maurice Raybaud
committed
Maurice Raybaud
committed
try:
material = elems[1].data.materials[0] # lame! - blender cant do enything else.
except:
material = None
if material:
diffuse_color = material.diffuse_color
trans = 1.0 - material.pov.alpha
Maurice Raybaud
committed
if material.use_transparency and material.transparency_method == 'RAYTRACE':
povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
trans = (1.0 - material.pov.alpha) - povFilter
Maurice Raybaud
committed
else:
povFilter = 0.0
material_finish = materialNames[material.name]
tabWrite("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
(diffuse_color[0], diffuse_color[1], diffuse_color[2],
povFilter, trans))
tabWrite("finish{%s} " % safety(material_finish, Level=2))
else:
tabWrite("pigment{srgb 1} finish{%s} " % (safety(DEF_MAT_NAME, Level=2)))
Maurice Raybaud
committed
writeObjectMaterial(material, ob)
#writeObjectMaterial(material, elems[1])
tabWrite("radiosity{importance %3g}\n" % ob.pov.importance_value)
Maurice Raybaud
committed
Maurice Raybaud
committed
'''
# important because no elements will break parsing.
elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
tabWrite("blob {\n")
tabWrite("threshold %.4g\n" % meta.threshold)
Bastien Montagne
committed
importance = ob.pov.importance_value
material = meta.materials[0] # lame! - blender cant do enything else.
except:
material = None
for elem in elements:
loc = elem.co
stiffness = elem.stiffness
if elem.use_negative:
stiffness = - stiffness
if elem.type == 'BALL':
tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
Bastien Montagne
committed
(loc.x, loc.y, loc.z, elem.radius, stiffness))
# After this wecould do something simple like...
# "pigment {Blue} }"
# except we'll write the color
elif elem.type == 'ELLIPSOID':
# location is modified by scale
tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
(loc.x / elem.size_x,
loc.y / elem.size_y,
loc.z / elem.size_z,
Bastien Montagne
committed
elem.radius, stiffness))
tabWrite("scale <%.6g, %.6g, %.6g> \n" %
Bastien Montagne
committed
(elem.size_x, elem.size_y, elem.size_z))
if material:
diffuse_color = material.diffuse_color
trans = 1.0 - material.pov.alpha
if material.use_transparency and material.transparency_method == 'RAYTRACE':
povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
trans = (1.0 - material.pov.alpha) - povFilter
material_finish = materialNames[material.name]
Maurice Raybaud
committed
tabWrite("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
Bastien Montagne
committed
(diffuse_color[0], diffuse_color[1], diffuse_color[2],
povFilter, trans))
tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
Maurice Raybaud
committed
tabWrite("pigment {srgb 1} \n")
Bastien Montagne
committed
# Write the finish last.
tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
Maurice Raybaud
committed
writeObjectMaterial(material, elems[1])
writeMatrix(global_matrix @ ob.matrix_world)
Maurice Raybaud
committed
# Importance for radiosity sampling added here
tabWrite("radiosity { \n")
# importance > ob.pov.importance_value
tabWrite("importance %3g \n" % importance)
tabWrite("}\n")
tabWrite("}\n") # End of Metaball block
if comments and len(metas) >= 1:
file.write("\n")
Maurice Raybaud
committed
'''
Bastien Montagne
committed
# objectNames = {}
DEF_OBJ_NAME = "Default"
def exportMeshes(scene, sel, csg):
"""write all meshes as POV mesh2{} syntax to exported file """
Bastien Montagne
committed
# obmatslist = []
# def hasUniqueMaterial():
# # Grab materials attached to object instances ...
# if hasattr(ob, 'material_slots'):
# for ms in ob.material_slots:
# if ms.material is not None and ms.link == 'OBJECT':
Bastien Montagne
committed
# if ms.material in obmatslist:
# return False
# else:
# obmatslist.append(ms.material)
# return True
# def hasObjectMaterial(ob):
# # Grab materials attached to object instances ...
# if hasattr(ob, 'material_slots'):
# for ms in ob.material_slots:
# if ms.material is not None and ms.link == 'OBJECT':
Bastien Montagne
committed
# # If there is at least one material slot linked to the object
Bastien Montagne
committed
# # and not the data (mesh), always create a new, "private" data instance.
Bastien Montagne
committed
# return True
# return False
# For objects using local material(s) only!
# This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
Bastien Montagne
committed
# As only objects using:
# * The same data.
# * EXACTLY the same materials, in EXACTLY the same sockets.
# ... can share a same instance in POV export.
Bastien Montagne
committed
obmats2data = {}
Bastien Montagne
committed
def checkObjectMaterials(ob, name, dataname):
if hasattr(ob, 'material_slots'):
has_local_mats = False
key = [dataname]
for ms in ob.material_slots:
Bastien Montagne
committed
key.append(ms.material.name)
if ms.link == 'OBJECT' and not has_local_mats:
has_local_mats = True
else:
# Even if the slot is empty, it is important to grab it...
Bastien Montagne
committed
key.append("")
if has_local_mats:
# If this object uses local material(s), lets find if another object
# using the same data and exactly the same list of materials
# (in the same slots) has already been processed...
Bastien Montagne
committed
# Note that here also, we use object name as new, unique dataname for Pov.
key = tuple(key) # Lists are not hashable...
Bastien Montagne
committed
if key not in obmats2data:
obmats2data[key] = name
return obmats2data[key]
return None
data_ref = {}
Bastien Montagne
committed
def store(scene, ob, name, dataname, matrix):
# The Object needs to be written at least once but if its data is
# already in data_ref this has already been done.
Bastien Montagne
committed
# This func returns the "povray" name of the data, or None
Bastien Montagne
committed
# if no writing is needed.
if ob.is_modified(scene, 'RENDER'):
# Data modified.
# Create unique entry in data_ref by using object name
# (always unique in Blender) as data name.
data_ref[name] = [(name, MatrixAsPovString(matrix))]
return name
# Here, we replace dataname by the value returned by checkObjectMaterials, only if
# it is not evaluated to False (i.e. only if the object uses some local material(s)).
dataname = checkObjectMaterials(ob, name, dataname) or dataname
if dataname in data_ref:
# Data already known, just add the object instance.
data_ref[dataname].append((name, MatrixAsPovString(matrix)))
# No need to write data
return None
else:
# Data not yet processed, create a new entry in data_ref.
data_ref[dataname] = [(name, MatrixAsPovString(matrix))]
return dataname
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
def exportSmoke(smoke_obj_name):
#if LuxManager.CurrentScene.name == 'preview':
#return 1, 1, 1, 1.0
#else:
flowtype = -1
smoke_obj = bpy.data.objects[smoke_obj_name]
domain = None
# Search smoke domain target for smoke modifiers
for mod in smoke_obj.modifiers:
if mod.name == 'Smoke':
if mod.smoke_type == 'FLOW':
if mod.flow_settings.smoke_flow_type == 'BOTH':
flowtype = 2
else:
if mod.flow_settings.smoke_flow_type == 'SMOKE':
flowtype = 0
else:
if mod.flow_settings.smoke_flow_type == 'FIRE':
flowtype = 1
if mod.smoke_type == 'DOMAIN':
domain = smoke_obj
smoke_modifier = mod
eps = 0.000001
if domain is not None:
#if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
# Blender version 2.71 supports direct access to smoke data structure
set = mod.domain_settings
channeldata = []
for v in set.density_grid:
channeldata.append(v.real)
print(v.real)
## Usage en voxel texture:
# channeldata = []
# if channel == 'density':
# for v in set.density_grid:
# channeldata.append(v.real)
# if channel == 'fire':
# for v in set.flame_grid:
# channeldata.append(v.real)
resolution = set.resolution_max
big_res = []
big_res.append(set.domain_resolution[0])
big_res.append(set.domain_resolution[1])
big_res.append(set.domain_resolution[2])
if set.use_high_resolution:
big_res[0] = big_res[0] * (set.amplify + 1)
big_res[1] = big_res[1] * (set.amplify + 1)
big_res[2] = big_res[2] * (set.amplify + 1)
# else:
# p = []
##gather smoke domain settings
# BBox = domain.bound_box
# p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
# p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
# set = mod.domain_settings
# resolution = set.resolution_max
# smokecache = set.point_cache
# ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
# res_x = ret[0]
# res_y = ret[1]
# res_z = ret[2]
# density = ret[3]
# fire = ret[4]
# if res_x * res_y * res_z > 0:
##new cache format
# big_res = []
# big_res.append(res_x)
# big_res.append(res_y)
# big_res.append(res_z)
# else:
# max = domain.dimensions[0]
# if (max - domain.dimensions[1]) < -eps:
# max = domain.dimensions[1]
# if (max - domain.dimensions[2]) < -eps:
# max = domain.dimensions[2]
# big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
# int(round(resolution * domain.dimensions[1] / max, 0)),
# int(round(resolution * domain.dimensions[2] / max, 0))]
# if set.use_high_resolution:
# big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
# big_res[2] * (set.amplify + 1)]
# if channel == 'density':
# channeldata = density
# if channel == 'fire':
# channeldata = fire
# sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
# if not os.path.exists( sc_fr ):
# os.makedirs(sc_fr)
# smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
# smoke_path = '/'.join([sc_fr, smoke_filename])
# with open(smoke_path, 'wb') as smoke_file:
# # Binary densitygrid file format
# #
# # File header
# smoke_file.write(b'SMOKE') #magic number
# smoke_file.write(struct.pack('<I', big_res[0]))
# smoke_file.write(struct.pack('<I', big_res[1]))
# smoke_file.write(struct.pack('<I', big_res[2]))
# smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
# LuxLog('Binary SMOKE file written: %s' % (smoke_path))
#return big_res[0], big_res[1], big_res[2], channeldata
mydf3 = df3.df3(big_res[0],big_res[1],big_res[2])
sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
for x in range(sim_sizeX):
for y in range(sim_sizeY):
for z in range(sim_sizeZ):
mydf3.set(x, y, z, channeldata[((z * sim_sizeY + y) * sim_sizeX + x)])
mydf3.exportDF3(smokePath)
print('Binary smoke.df3 file written in preview directory')
if comments:
file.write("\n//--Smoke--\n\n")
# Note: We start with a default unit cube.
# This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
# coordinates from the start, and avoid scale/translate operations at the end...
file.write("box{<0,0,0>, <1,1,1>\n")
file.write(" pigment{ rgbt 1 }\n")
file.write(" hollow\n")
file.write(" interior{ //---------------------\n")
file.write(" media{ method 3\n")
file.write(" emission <1,1,1>*1\n")# 0>1 for dark smoke to white vapour
file.write(" scattering{ 1, // Type\n")
file.write(" <1,1,1>*0.1\n")
file.write(" density{density_file df3 \"%s\"\n" % (smokePath))
file.write(" color_map {\n")
file.write(" [0.00 rgb 0]\n")
file.write(" [0.05 rgb 0]\n")
file.write(" [0.20 rgb 0.2]\n")
file.write(" [0.30 rgb 0.6]\n")
file.write(" [0.40 rgb 1]\n")
file.write(" [1.00 rgb 1]\n")
file.write(" } // end color_map\n")
file.write(" } // end of density\n")
file.write(" samples %i // higher = more precise\n" % resolution)
file.write(" } // end of media --------------------------\n")
file.write(" } // end of interior\n")
# START OF TRANSFORMATIONS
# Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
# loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
bbox = smoke_obj.bound_box
dim = [abs(bbox[6][0] - bbox[0][0]), abs(bbox[6][1] - bbox[0][1]), abs(bbox[6][2] - bbox[0][2])]
# We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
# We offset our cube such that (0,0,0) coordinate matches Blender's object center.
file.write("translate<%.6g,%.6g,%.6g>\n" % (bbox[0][0], bbox[0][1], bbox[0][2]))
# We apply object's transformations to get final loc/rot/size in world space!
# Note: we could combine the two previous transformations with this matrix directly...
writeMatrix(global_matrix @ smoke_obj.matrix_world)
# END OF TRANSFORMATIONS
#file.write(" interpolate 1\n")
#file.write(" frequency 0\n")
#file.write(" }\n")
Bastien Montagne
committed
ob_num = 0
#subtract original from the count of their instances as were not counted before 2.8
if not (ob.is_instancer and ob.original != ob):
ob_num += 1
# XXX I moved all those checks here, as there is no need to compute names
# for object we won't export here!
if (ob.type in {'LIGHT', 'CAMERA', #'EMPTY', #empties can bear dupligroups
'META', 'ARMATURE', 'LATTICE'}):
continue
smokeFlag=False
for mod in ob.modifiers:
if mod and hasattr(mod, 'smoke_type'):
smokeFlag=True
if (mod.smoke_type == 'DOMAIN'):
exportSmoke(ob.name)
break # don't render domain mesh or flow emitter mesh, skip to next object.
if not smokeFlag:
# Export Hair
renderEmitter = True
if hasattr(ob, 'particle_systems'):
renderEmitter = False
if ob.show_instancer_for_render:
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
for pSys in ob.particle_systems:
for mod in [m for m in ob.modifiers if (m is not None) and (m.type == 'PARTICLE_SYSTEM')]:
if (pSys.settings.render_type == 'PATH') and mod.show_render and (pSys.name == mod.particle_system.name):
tstart = time.time()
texturedHair=0
if ob.material_slots[pSys.settings.material - 1].material and ob.active_material is not None:
pmaterial = ob.material_slots[pSys.settings.material - 1].material
for th in pmaterial.texture_slots:
if th and th.use:
if (th.texture.type == 'IMAGE' and th.texture.image) or th.texture.type != 'IMAGE':
if th.use_map_color_diffuse:
texturedHair=1
if pmaterial.strand.use_blender_units:
strandStart = pmaterial.strand.root_size
strandEnd = pmaterial.strand.tip_size
strandShape = pmaterial.strand.shape
else: # Blender unit conversion
strandStart = pmaterial.strand.root_size / 200.0
strandEnd = pmaterial.strand.tip_size / 200.0
strandShape = pmaterial.strand.shape
else:
pmaterial = "default" # No material assigned in blender, use default one
strandStart = 0.01
strandEnd = 0.01
strandShape = 0.0
# Set the number of particles to render count rather than 3d view display
#pSys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
# When you render, the entire dependency graph will be
# evaluated at render resolution, including the particles.
# In the viewport it will be at viewport resolution.
# So there is no need fo render engines to use this function anymore,
steps = pSys.settings.display_step
steps = 3 ** steps # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
totalNumberOfHairs = ( pSys.settings.count + pSys.settings.rendered_child_count )
#hairCounter = 0
file.write('#declare HairArray = array[%i] {\n' % totalNumberOfHairs)
for pindex in range(0, totalNumberOfHairs):
#if particle.is_exist and particle.is_visible:
#hairCounter += 1
#controlPointCounter = 0
# Each hair is represented as a separate sphere_sweep in POV-Ray.
file.write('sphere_sweep{')
if pSys.settings.use_hair_bspline:
file.write('b_spline ')
file.write('%i,\n' % (steps + 2)) # +2 because the first point needs tripling to be more than a handle in POV
file.write('linear_spline ')
file.write('%i,\n' % (steps))
#changing world coordinates to object local coordinates by multiplying with inverted matrix
initCo = ob.matrix_world.inverted() @ (pSys.co_hair(ob, particle_no = pindex, step = 0))
if ob.material_slots[pSys.settings.material - 1].material and ob.active_material is not None:
pmaterial = ob.material_slots[pSys.settings.material-1].material
for th in pmaterial.texture_slots:
if th and th.use and th.use_map_color_diffuse:
#treat POV textures as bitmaps
if (th.texture.type == 'IMAGE' and th.texture.image and th.texture_coords == 'UV' and ob.data.uv_textures is not None): # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures is not None):
image=th.texture.image
image_width = image.size[0]
image_height = image.size[1]
image_pixels = image.pixels[:]
uv_co = pSys.uv_on_emitter(mod, pSys.particles[pindex], pindex, 0)
x_co = round(uv_co[0] * (image_width - 1))
y_co = round(uv_co[1] * (image_height - 1))
pixelnumber = (image_width * y_co) + x_co
r = image_pixels[pixelnumber*4]
g = image_pixels[pixelnumber*4+1]
b = image_pixels[pixelnumber*4+2]
a = image_pixels[pixelnumber*4+3]
initColor=(r,g,b,a)
else:
#only overwrite variable for each competing texture for now
initColor=th.texture.evaluate((initCo[0],initCo[1],initCo[2]))
for step in range(0, steps):
co = ob.matrix_world.inverted() @ (pSys.co_hair(ob, particle_no = pindex, step = step))
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
#for controlPoint in particle.hair_keys:
if pSys.settings.clump_factor != 0:
hDiameter = pSys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
elif step == 0:
hDiameter = strandStart
else:
hDiameter += (strandEnd-strandStart)/(pSys.settings.display_step+1) #XXX +1 or not?
if step == 0 and pSys.settings.use_hair_bspline:
# Write three times the first point to compensate pov Bezier handling
file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (co[0], co[1], co[2], abs(hDiameter)))
file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (co[0], co[1], co[2], abs(hDiameter)))
#file.write('<%.6g,%.6g,%.6g>,%.7g' % (particle.location[0], particle.location[1], particle.location[2], abs(hDiameter))) # Useless because particle location is the tip, not the root.
#file.write(',\n')
#controlPointCounter += 1
#totalNumberOfHairs += len(pSys.particles)# len(particle.hair_keys)
# Each control point is written out, along with the radius of the
# hair at that point.
file.write('<%.6g,%.6g,%.6g>,%.7g' % (co[0], co[1], co[2], abs(hDiameter)))
# All coordinates except the last need a following comma.
if step != steps - 1:
file.write(',\n')
else:
if texturedHair:
# Write pigment and alpha (between Pov and Blender alpha 0 and 1 are reversed)
file.write('\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n' %(initColor[0], initColor[1], initColor[2], 1.0-initColor[3]))
# End the sphere_sweep declaration for this hair
file.write('}\n')
# All but the final sphere_sweep (each array element) needs a terminating comma.
if pindex != totalNumberOfHairs:
file.write(',\n')
else:
# End the array declaration.
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
if not texturedHair:
# Pick up the hair material diffuse color and create a default POV-Ray hair texture.
file.write('#ifndef (HairTexture)\n')
file.write(' #declare HairTexture = texture {\n')
file.write(' pigment {srgbt <%s,%s,%s,%s>}\n' % (pmaterial.diffuse_color[0], pmaterial.diffuse_color[1], pmaterial.diffuse_color[2], (pmaterial.strand.width_fade + 0.05)))
file.write(' }\n')
file.write('#end\n')
file.write('\n')
# Dynamically create a union of the hairstrands (or a subset of them).
# By default use every hairstrand, commented line is for hand tweaking test renders.
file.write('//Increasing HairStep divides the amount of hair for test renders.\n')
file.write('#ifndef(HairStep) #declare HairStep = 1; #end\n')
file.write('union{\n')
file.write(' #local I = 0;\n')
file.write(' #while (I < %i)\n' % totalNumberOfHairs)
file.write(' object {HairArray[I]')
if not texturedHair:
file.write(' texture{HairTexture}\n')
else:
file.write('\n')
# Translucency of the hair:
file.write(' hollow\n')
file.write(' double_illuminate\n')
file.write(' interior {\n')
file.write(' ior 1.45\n')
file.write(' media {\n')
file.write(' scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n')
file.write(' absorption 10/<0.83, 0.75, 0.15>\n')
file.write(' samples 1\n')
file.write(' method 2\n')
file.write(' density {cylindrical\n')
file.write(' color_map {\n')
file.write(' [0.0 rgb <0.83, 0.45, 0.35>]\n')
file.write(' [0.5 rgb <0.8, 0.8, 0.4>]\n')
file.write(' [1.0 rgb <1,1,1>]\n')
file.write(' }\n')
file.write(' }\n')
file.write(' }\n')
file.write(' }\n')
file.write(' }\n')
file.write(' #local I = I + HairStep;\n')
file.write(' #end\n')
writeMatrix(global_matrix @ ob.matrix_world)
file.write('}')
print('Totals hairstrands written: %i' % totalNumberOfHairs)
print('Number of tufts (particle systems)', len(ob.particle_systems))
# Set back the displayed number of particles to preview count
# pSys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
# When you render, the entire dependency graph will be
# evaluated at render resolution, including the particles.
# In the viewport it will be at viewport resolution.
# So there is no need fo render engines to use this function anymore,
if renderEmitter == False:
continue #don't render mesh, skip to next object.
#############################################
# Generating a name for object just like materials to be able to use it
# (baking for now or anything else).
# XXX I don't understand that if we are here, sel if a non-empty iterable,
# so this condition is always True, IMO -- mont29
if ob.data:
Maurice Raybaud
committed
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.data.name
elif ob.is_instancer:
if ob.instance_type == 'COLLECTION':
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.instance_collection.name
else:
#hoping only dupligroups have several source datablocks
#ob_dupli_list_create(scene) #deprecated in 2.8
depsgraph = bpy.context.evaluated_depsgraph_get()
for eachduplicate in depsgraph.object_instances:
if eachduplicate.is_instance: # Real dupli instance filtered because original included in list since 2.8
dataname_orig = "DATA" + eachduplicate.object.name
#ob.dupli_list_clear() #just don't store any reference to instance since 2.8
elif ob.type == 'EMPTY':
name_orig = "OB" + ob.name
dataname_orig = "DATA" + ob.name
Maurice Raybaud
committed
else:
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
name_orig = DEF_OBJ_NAME
dataname_orig = DEF_OBJ_NAME
name = string_strip_hyphen(bpy.path.clean_name(name_orig))
dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
## for slot in ob.material_slots:
## if slot.material is not None and slot.link == 'OBJECT':
## obmaterial = slot.material
#############################################
if info_callback:
info_callback("Object %2.d of %2.d (%s)" % (ob_num, len(sel), ob.name))
#if ob.type != 'MESH':
# continue
# me = ob.data
matrix = global_matrix @ ob.matrix_world
povdataname = store(scene, ob, name, dataname, matrix)
if povdataname is None:
print("This is an instance of " + name)
continue
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
print("Writing Down First Occurrence of " + name)
############################################Povray Primitives
# special exportCurves() function takes care of writing
# lathe, sphere_sweep, birail, and loft except with modifiers
# converted to mesh
if not ob.is_modified(scene, 'RENDER'):
if ob.type == 'CURVE' and (ob.pov.curveshape in
{'lathe', 'sphere_sweep', 'loft'}):
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'ISOSURFACE':
tabWrite("#declare %s = isosurface{ \n"% povdataname)
tabWrite("function{ \n")
textName = ob.pov.iso_function_text
if textName:
node_tree = bpy.context.scene.node_tree
for node in node_tree.nodes:
if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
for inp in node.inputs:
if inp:
tabWrite("#declare %s = %.6g;\n"%(inp.name,inp.default_value))
text = bpy.data.texts[textName]
for line in text.lines:
split = line.body.split()
if split[0] != "#declare":
tabWrite("%s\n"%line.body)
else:
tabWrite("abs(x) - 2 + y")
tabWrite("}\n")
tabWrite("threshold %.6g\n"%ob.pov.threshold)
tabWrite("max_gradient %.6g\n"%ob.pov.max_gradient)
tabWrite("accuracy %.6g\n"%ob.pov.accuracy)
tabWrite("contained_by { ")
if ob.pov.contained_by == "sphere":
tabWrite("sphere {0,%.6g}}\n"%ob.pov.container_scale)
else:
tabWrite("box {-%.6g,%.6g}}\n"%(ob.pov.container_scale,ob.pov.container_scale))
if ob.pov.all_intersections:
tabWrite("all_intersections\n")
else:
if ob.pov.max_trace > 1:
tabWrite("max_trace %.6g\n"%ob.pov.max_trace)
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
tabWrite("scale %.6g\n"%(1/ob.pov.container_scale))
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'SUPERELLIPSOID':
tabWrite("#declare %s = superellipsoid{ <%.4f,%.4f>\n"%(povdataname,ob.pov.se_n2,ob.pov.se_n1))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
if ob.pov.object_as == 'SUPERTORUS':
rMajor = ob.pov.st_major_radius
rMinor = ob.pov.st_minor_radius
ring = ob.pov.st_ring
cross = ob.pov.st_cross
accuracy=ob.pov.st_accuracy
gradient=ob.pov.st_max_gradient
############Inline Supertorus macro
file.write("#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n")
file.write(" #local CP = 2/MinorControl;\n")
file.write(" #local RP = 2/MajorControl;\n")
file.write(" isosurface {\n")
file.write(" function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n")
file.write(" threshold 0\n")
file.write(" contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n")
file.write(" #if(MaxGradient >= 1)\n")
file.write(" max_gradient MaxGradient\n")
file.write(" #else\n")
file.write(" evaluate 1, 10, 0.1\n")
file.write(" #end\n")
file.write(" accuracy Accuracy\n")
file.write(" }\n")
file.write("#end\n")
############
tabWrite("#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"%(povdataname,rMajor,rMinor,ring,cross,accuracy,gradient))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'PLANE':
tabWrite("#declare %s = plane{ <0,0,1>,1\n"%povdataname)
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'BOX':
tabWrite("#declare %s = box { -1,1\n"%povdataname)
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'CONE':
br = ob.pov.cone_base_radius
cr = ob.pov.cone_cap_radius
bz = ob.pov.cone_base_z
cz = ob.pov.cone_cap_z
tabWrite("#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"%(povdataname,bz,br,cz,cr))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
if ob.pov.object_as == 'CYLINDER':
r = ob.pov.cylinder_radius
x2 = ob.pov.cylinder_location_cap[0]
y2 = ob.pov.cylinder_location_cap[1]
z2 = ob.pov.cylinder_location_cap[2]
tabWrite("#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n"%(
povdataname,
x2,
y2,
z2,
r))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
#cylinders written at origin, translated below
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
if ob.pov.object_as == 'HEIGHT_FIELD':
data = ""
filename = ob.pov.hf_filename
data += '"%s"'%filename
gamma = ' gamma %.4f'%ob.pov.hf_gamma
data += gamma
if ob.pov.hf_premultiplied:
data += ' premultiplied on'
if ob.pov.hf_smooth:
data += ' smooth'
if ob.pov.hf_water > 0:
data += ' water_level %.4f'%ob.pov.hf_water
#hierarchy = ob.pov.hf_hierarchy
tabWrite('#declare %s = height_field { %s\n'%(povdataname,data))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("rotate x*90\n")
tabWrite("translate <-0.5,0.5,0>\n")
tabWrite("scale <0,-1,0>\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'SPHERE':
tabWrite("#declare %s = sphere { 0,%6f\n"%(povdataname,ob.pov.sphere_radius))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
#tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'TORUS':
tabWrite("#declare %s = torus { %.4f,%.4f\n"%(povdataname,ob.pov.torus_major_radius,ob.pov.torus_minor_radius))
povMatName = "Default_texture"
if ob.active_material:
#povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
try:
material = ob.active_material
writeObjectMaterial(material, ob)
except IndexError:
print(me)
#tabWrite("texture {%s}\n"%povMatName)
write_object_modifiers(scene,ob,file)
tabWrite("rotate x*90\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
if ob.pov.object_as == 'PARAMETRIC':
tabWrite("#declare %s = parametric {\n"%povdataname)
tabWrite("function { %s }\n"%ob.pov.x_eq)
tabWrite("function { %s }\n"%ob.pov.y_eq)
tabWrite("function { %s }\n"%ob.pov.z_eq)
tabWrite("<%.4f,%.4f>, <%.4f,%.4f>\n"%(ob.pov.u_min,ob.pov.v_min,ob.pov.u_max,ob.pov.v_max))
if ob.pov.contained_by == "sphere":
tabWrite("contained_by { sphere{0, 2} }\n")
else:
tabWrite("contained_by { box{-2, 2} }\n")
tabWrite("max_gradient %.6f\n"%ob.pov.max_gradient)
tabWrite("accuracy %.6f\n"%ob.pov.accuracy)
tabWrite("precompute 10 x,y,z\n")
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
if ob.pov.object_as == 'POLYCIRCLE':
#TODO write below macro Once:
#if write_polytocircle_macro_once == 0:
file.write("/****************************\n")
file.write("This macro was written by 'And'.\n")
file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n")
file.write("****************************/\n")
file.write("//from math.inc:\n")
file.write("#macro VPerp_Adjust(V, Axis)\n")
file.write(" vnormalize(vcross(vcross(Axis, V), Axis))\n")
file.write("#end\n")
file.write("//Then for the actual macro\n")
file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n")
file.write("#local p1 = point1 + <0,0,0>;\n")
file.write("#local p2 = point2 + <0,0,0>;\n")
file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n")
file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
file.write(' #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n')
file.write("#end\n\n")
file.write("#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n")
file.write("#local d = vdot(norm, p1);\n")
file.write("plane{\n")
file.write("norm, d\n")
file.write("}\n")
file.write("#end\n\n")
file.write("//polygon to circle\n")
file.write("#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n")
file.write("#local n = int(_polygon_n);\n")
file.write("#if(n < 3)\n")
file.write(" #error ""\n")
file.write("#end\n\n")
file.write("#local front_v = VPerp_Adjust(_side_face, z);\n")
file.write("#if(vdot(front_v, x) >= 0)\n")
file.write(" #local face_ang = acos(vdot(-y, front_v));\n")
file.write("#else\n")
file.write(" #local face_ang = -acos(vdot(-y, front_v));\n")
file.write("#end\n")
file.write("#local polyg_ext_ang = 2*pi/n;\n")
file.write("#local polyg_outer_r = _polygon_circumscribed_radius;\n")
file.write("#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n")
file.write("#local cycle_r = _circle_radius;\n")
file.write("#local h = _height;\n")
file.write("#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n")
file.write(' #error "error: each side length must be positive"\n')
file.write("#end\n\n")
file.write("#local multi = 1000;\n")
file.write("#local poly_obj =\n")
file.write("polynomial{\n")
file.write("4,\n")
file.write("xyz(0,2,2): multi*1,\n")
file.write("xyz(2,0,1): multi*2*h,\n")
file.write("xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n")
file.write("xyz(2,0,0): multi*(-h*h),\n")
file.write("xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n")
file.write("xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n")
file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n")
file.write("xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n")
file.write("xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n")
file.write("sturm\n")
file.write("}\n\n")
file.write("#local mockup1 =\n")
file.write("difference{\n")
file.write(" cylinder{\n")
file.write(" <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n")
file.write(" }\n\n")
file.write(" #for(i, 0, n-1)\n")
file.write(" object{\n")
file.write(" poly_obj\n")
file.write(" inverse\n")
file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
file.write(" }\n")
file.write(" object{\n")
file.write(" Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n")
file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
file.write(" }\n")
file.write(" #end\n")
file.write("}\n\n")
file.write("object{\n")
file.write("mockup1\n")
file.write("rotate <0, 0, degrees(face_ang)>\n")
file.write("}\n")
file.write("#end\n")
#Use the macro
ngon = ob.pov.polytocircle_ngon
ngonR = ob.pov.polytocircle_ngonR
circleR = ob.pov.polytocircle_circleR
tabWrite("#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"%(povdataname,ngon,ngonR,circleR))
tabWrite("}\n")
continue #Don't render proxy mesh, skip to next object
############################################else try to export mesh
elif ob.is_instancer == False: #except duplis which should be instances groups for now but all duplis later
if ob.type == 'EMPTY':
tabWrite("\n//dummy sphere to represent Empty location\n")
tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
# TODO(sergey): PovRay is a render engine, so should be using dependency graph
# which was given to it via render engine API.
depsgraph = bpy.context.evaluated_depsgraph_get()
ob_eval = ob.evaluated_get(depsgraph)
try:
me = ob_eval.to_mesh()
#XXX Here? identify the specific exception for mesh object with no data
#XXX So that we can write something for the dataname !
except:
# also happens when curves cant be made into meshes because of no-data
continue
importance = ob.pov.importance_value
if me:
me.calc_loop_triangles()
me_materials = me.materials
me_faces = me.loop_triangles[:]
#if len(me_faces)==0:
#tabWrite("\n//dummy sphere to represent empty mesh location\n")
#tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
if not me or not me_faces:
tabWrite("\n//dummy sphere to represent empty mesh location\n")
tabWrite("#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
continue
uv_layers = me.uv_layers
if len(uv_layers) > 0:
if me.uv_layers.active and uv_layers.active.data:
uv_layer = uv_layers.active.data
try:
#vcol_layer = me.vertex_colors.active.data
vcol_layer = me.vertex_colors.active.data
except AttributeError:
vcol_layer = None
faces_verts = [f.vertices[:] for f in me_faces]
faces_normals = [f.normal[:] for f in me_faces]
verts_normals = [v.normal[:] for v in me.vertices]
# Use named declaration to allow reference e.g. for baking. MR
file.write("\n")
tabWrite("#declare %s =\n" % povdataname)
tabWrite("mesh2 {\n")
tabWrite("vertex_vectors {\n")
tabWrite("%d" % len(me.vertices)) # vert count
tabStr = tab * tabLevel
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
#tabWrite("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
file.write("\n")
tabWrite("}\n")
# Build unique Normal list
uniqueNormals = {}
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
# [-1] is a dummy index, use a list so we can modify in place
if f.use_smooth: # Use vertex normals
for v in fv:
key = verts_normals[v]
uniqueNormals[key] = [-1]
else: # Use face normal
key = faces_normals[fi]
uniqueNormals[key] = [-1]
tabWrite("normal_vectors {\n")
tabWrite("%d" % len(uniqueNormals)) # vert count
idx = 0
tabStr = tab * tabLevel
for no, index in uniqueNormals.items():
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%.6f, %.6f, %.6f>" % no) # vert count
file.write(", ")
file.write("<%.6f, %.6f, %.6f>" % no) # vert count
index[0] = idx
idx += 1
file.write("\n")
tabWrite("}\n")
# Vertex colors
vertCols = {} # Use for material colors also.
if uv_layer:
# Generate unique UV's
uniqueUVs = {}
#n = 0
for f in me_faces: # me.faces in 2.7
uvs = [uv_layer[l].uv[:] for l in f.loops]
for uv in uvs:
uniqueUVs[uv[:]] = [-1]
tabWrite("uv_vectors {\n")
#print unique_uvs
tabWrite("%d" % len(uniqueUVs)) # vert count
idx = 0
tabStr = tab * tabLevel
for uv, index in uniqueUVs.items():
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%.6f, %.6f>" % uv)
file.write("<%.6f, %.6f>" % uv)
index[0] = idx
idx += 1
'''
# Just add 1 dummy vector, no real UV's
tabWrite('1') # vert count
file.write(',\n\t\t<0.0, 0.0>')
'''
file.write("\n")
tabWrite("}\n")
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
if me.vertex_colors:
#Write down vertex colors as a texture for each vertex
tabWrite("texture_list {\n")
tabWrite("%d\n" % (len(me_faces) * 3)) # assumes we have only triangles
VcolIdx=0
if comments:
file.write("\n //Vertex colors: one simple pigment texture per vertex\n")
for fi, f in enumerate(me_faces):
# annoying, index may be invalid
material_index = f.material_index
try:
material = me_materials[material_index]
except:
material = None
if material: #and material.use_vertex_color_paint: #Always use vertex color when there is some for now
cols = [vcol_layer[l].color[:] for l in f.loops]
for col in cols:
key = col[0], col[1], col[2], material_index # Material index!
VcolIdx+=1
vertCols[key] = [VcolIdx]
if linebreaksinlists:
tabWrite("texture {pigment{ color srgb <%6f,%6f,%6f> }}\n" % (col[0], col[1], col[2]))
else:
tabWrite("texture {pigment{ color srgb <%6f,%6f,%6f> }}" % (col[0], col[1], col[2]))
tabStr = tab * tabLevel
if material:
# Multiply diffuse with SSS Color
if material.pov_subsurface_scattering.use:
diffuse_color = [i * j for i, j in zip(material.pov_subsurface_scattering.color[:], material.diffuse_color[:])]
key = diffuse_color[0], diffuse_color[1], diffuse_color[2], \
material_index
vertCols[key] = [-1]
else:
diffuse_color = material.diffuse_color[:]
key = diffuse_color[0], diffuse_color[1], diffuse_color[2], \
material_index
vertCols[key] = [-1]
tabWrite("\n}\n")
# Face indices
tabWrite("\nface_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
material_index = f.material_index
if vcol_layer:
cols = [vcol_layer[l].color[:] for l in f.loops]
if not me_materials or me_materials[material_index] is None: # No materials
if linebreaksinlists:
file.write(",\n")
# vert count
file.write(tabStr + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
Maurice Raybaud
committed
else:
material = me_materials[material_index]
if me.vertex_colors: #and material.use_vertex_color_paint:
# Color per vertex - vertex color
col1 = cols[0]
col2 = cols[1]
col3 = cols[2]
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
else:
# Color per material - flat material color
if material.pov_subsurface_scattering.use:
diffuse_color = [i * j for i, j in zip(material.pov_subsurface_scattering.color[:], material.diffuse_color[:])]
else:
diffuse_color = material.diffuse_color[:]
ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], \
diffuse_color[2], f.material_index][0]
# ci are zero based index so we'll subtract 1 from them
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>, %d,%d,%d" % \
(fv[0], fv[1], fv[2], ci1-1, ci2-1, ci3-1)) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>, %d,%d,%d" % \
(fv[0], fv[1], fv[2], ci1-1, ci2-1, ci3-1)) # vert count
file.write("\n")
tabWrite("}\n")
# normal_indices indices
tabWrite("normal_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for fi, fv in enumerate(faces_verts):
if me_faces[fi].use_smooth:
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" %\
(uniqueNormals[verts_normals[fv[0]]][0],\
uniqueNormals[verts_normals[fv[1]]][0],\
uniqueNormals[verts_normals[fv[2]]][0])) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>" %\
(uniqueNormals[verts_normals[fv[0]]][0],\
uniqueNormals[verts_normals[fv[1]]][0],\
uniqueNormals[verts_normals[fv[2]]][0])) # vert count
Maurice Raybaud
committed
else:
idx = uniqueNormals[faces_normals[fi]][0]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" % (idx, idx, idx)) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
file.write("\n")
tabWrite("}\n")
if uv_layer:
tabWrite("uv_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for f in me_faces:
uvs = [uv_layer[l].uv[:] for l in f.loops]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" % (
uniqueUVs[uvs[0]][0],\
uniqueUVs[uvs[1]][0],\
uniqueUVs[uvs[2]][0]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (
uniqueUVs[uvs[0]][0],\
uniqueUVs[uvs[1]][0],\
uniqueUVs[uvs[2]][0]))
Maurice Raybaud
committed
file.write("\n")
tabWrite("}\n")
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
#XXX BOOLEAN
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
if me.materials:
try:
material = me.materials[0] # dodgy
writeObjectMaterial(material, ob)
except IndexError:
print(me)
# POV object modifiers such as
# hollow / sturm / double_illuminate etc.
write_object_modifiers(scene,ob,file)
#Importance for radiosity sampling added here:
tabWrite("radiosity { \n")
tabWrite("importance %3g \n" % importance)
tabWrite("}\n")
Maurice Raybaud
committed
tabWrite("}\n") # End of mesh block
facesMaterials = [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
if me_materials:
for f in me_faces:
if f.material_index not in facesMaterials:
facesMaterials.append(f.material_index)
# No vertex colors, so write material colors as vertex colors
for i, material in enumerate(me_materials):
if material and material.pov.material_use_nodes == False: # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Multiply diffuse with SSS Color
if material.pov_subsurface_scattering.use:
diffuse_color = [i * j for i, j in zip(material.pov_subsurface_scattering.color[:], material.diffuse_color[:])]
key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat
vertCols[key] = [-1]
else:
diffuse_color = material.diffuse_color[:]
key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat
vertCols[key] = [-1]
idx = 0
LocalMaterialNames = []
for col, index in vertCols.items():
#if me_materials:
mater = me_materials[col[3]]
if me_materials is None: #XXX working?
material_finish = DEF_MAT_NAME # not working properly,
trans = 0.0
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
else:
shading.writeTextureInfluence(mater, materialNames,
LocalMaterialNames,
path_image, lampCount,
imageFormat, imgMap,
imgMapTransforms,
tabWrite, comments,
string_strip_hyphen,
safety, col, os, preview_dir, unpacked_images)
###################################################################
index[0] = idx
idx += 1
# Vert Colors
tabWrite("texture_list {\n")
# In case there's is no material slot, give at least one texture
#(an empty one so it uses pov default)
if len(vertCols)==0:
file.write(tabStr + "1")
else:
file.write(tabStr + "%s" % (len(vertCols))) # vert count
Maurice Raybaud
committed
# below "material" alias, added check ob.active_material
# to avoid variable referenced before assignment error
try:
material = ob.active_material
except IndexError:
#when no material slot exists,
material=None
# WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if material and ob.active_material is not None and material.pov.material_use_nodes == False:
if material.pov.replacement_text != "":
file.write("\n")
file.write(" texture{%s}\n" % material.pov.replacement_text)
# Loop through declared materials list
for cMN in LocalMaterialNames:
if material != "Default":
file.write("\n texture{MAT_%s}\n" % cMN)
#use string_strip_hyphen(materialNames[material]))
#or Something like that to clean up the above?
elif material and material.pov.material_use_nodes:
for index in facesMaterials:
faceMaterial = string_strip_hyphen(bpy.path.clean_name(me_materials[index].name))
file.write("\n texture{%s}\n" % faceMaterial)
# END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Maurice Raybaud
committed
else:
file.write(" texture{}\n")
tabWrite("}\n")
# Face indices
tabWrite("face_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
Maurice Raybaud
committed
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
material_index = f.material_index
Maurice Raybaud
committed
if vcol_layer:
cols = [vcol_layer[l].color[:] for l in f.loops]
if not me_materials or me_materials[material_index] is None: # No materials
if linebreaksinlists:
file.write(",\n")
# vert count
file.write(tabStr + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
material = me_materials[material_index]
ci1 = ci2 = ci3 = f.material_index
if me.vertex_colors: #and material.use_vertex_color_paint:
# Color per vertex - vertex color
col1 = cols[0]
col2 = cols[1]
col3 = cols[2]
ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
elif material.pov.material_use_nodes:
ci1 = ci2 = ci3 = 0
else:
# Color per material - flat material color
if material.pov_subsurface_scattering.use:
diffuse_color = [i * j for i, j in
zip(material.pov_subsurface_scattering.color[:],
material.diffuse_color[:])]
else:
diffuse_color = material.diffuse_color[:]
ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], \
diffuse_color[2], f.material_index][0]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>, %d,%d,%d" % \
(fv[0], fv[1], fv[2], ci1, ci2, ci3)) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>, %d,%d,%d" % \
(fv[0], fv[1], fv[2], ci1, ci2, ci3)) # vert count
file.write("\n")
tabWrite("}\n")
# normal_indices indices
tabWrite("normal_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for fi, fv in enumerate(faces_verts):
if me_faces[fi].use_smooth:
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" %\
(uniqueNormals[verts_normals[fv[0]]][0],\
uniqueNormals[verts_normals[fv[1]]][0],\
uniqueNormals[verts_normals[fv[2]]][0])) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>" %\
(uniqueNormals[verts_normals[fv[0]]][0],\
uniqueNormals[verts_normals[fv[1]]][0],\
uniqueNormals[verts_normals[fv[2]]][0])) # vert count
idx = uniqueNormals[faces_normals[fi]][0]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" % (idx, idx, idx)) # vertcount
else:
file.write(", ")
file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
file.write("\n")
tabWrite("}\n")
if uv_layer:
tabWrite("uv_indices {\n")
tabWrite("%d" % (len(me_faces))) # faces count
tabStr = tab * tabLevel
for f in me_faces:
uvs = [uv_layer[l].uv[:] for l in f.loops]
if linebreaksinlists:
file.write(",\n")
file.write(tabStr + "<%d,%d,%d>" % (
uniqueUVs[uvs[0]][0],\
uniqueUVs[uvs[1]][0],\
uniqueUVs[uvs[2]][0]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (
uniqueUVs[uvs[0]][0],\
uniqueUVs[uvs[1]][0],\
uniqueUVs[uvs[2]][0]))
file.write("\n")
tabWrite("}\n")
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
#XXX BOOLEAN
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
if me.materials:
try:
material = me.materials[0] # dodgy
writeObjectMaterial(material, ob)
except IndexError:
print(me)
# POV object modifiers such as
# hollow / sturm / double_illuminate etc.
write_object_modifiers(scene,ob,file)
#Importance for radiosity sampling added here:
tabWrite("radiosity { \n")
tabWrite("importance %3g \n" % importance)
tabWrite("}\n")
tabWrite("}\n") # End of mesh block
ob_eval.to_mesh_clear()
if csg:
duplidata_ref = []
_dupnames_seen = dict() # avoid duplicate output during introspection
#matrix = global_matrix @ ob.matrix_world
if ob.is_instancer:
tabWrite("\n//--DupliObjects in %s--\n\n"% ob.name)
#ob.dupli_list_create(scene) #deprecated in 2.8
depsgraph = bpy.context.evaluated_depsgraph_get()
dup = ""
if ob.is_modified(scene, 'RENDER'):
#modified object always unique so using object name rather than data name
dup = "#declare OB%s = union{\n" %(string_strip_hyphen(bpy.path.clean_name(ob.name)))
else:
dup = "#declare DATA%s = union{\n" %(string_strip_hyphen(bpy.path.clean_name(ob.name)))
for eachduplicate in depsgraph.object_instances:
if eachduplicate.is_instance: # Real dupli instance filtered because original included in list since 2.8
_dupname = eachduplicate.object.name
_dupobj = bpy.data.objects[_dupname]
# BEGIN introspection for troubleshooting purposes
if not "name" in dir(_dupobj.data):
if _dupname not in _dupnames_seen:
print("WARNING: bpy.data.objects[%s].data (of type %s) has no 'name' attribute" % (_dupname, type(_dupobj.data)))
for _thing in dir(_dupobj):
print("|| %s.%s = %s" % (_dupname, _thing, getattr(_dupobj, _thing)))
_dupnames_seen[_dupname] = 1
print("''=> Unparseable objects so far: %s" % (_dupnames_seen))
else:
_dupnames_seen[_dupname] += 1
continue # don't try to parse data objects with no name attribute
# END introspection for troubleshooting purposes
duplidataname = "OB"+string_strip_hyphen(bpy.path.clean_name(_dupobj.data.name))
dupmatrix = eachduplicate.matrix_world.copy() #has to be copied to not store instance since 2.8
dup += ("\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" %(string_strip_hyphen(bpy.path.clean_name(_dupobj.data.name)), MatrixAsPovString(ob.matrix_world.inverted() @ dupmatrix)))
#add object to a list so that it is not rendered for some instance_types
if ob.instance_type not in {'COLLECTION'} and duplidataname not in duplidata_ref:
duplidata_ref.append(duplidataname) #older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
#ob.dupli_list_clear()# just do not store any reference to instance since 2.8
Maurice Raybaud
committed
else:
print("WARNING: Unparseable objects in current .blend file:\n''=> %s" % (_dupnames_seen))
print("duplidata_ref = %s" % (duplidata_ref))
for data_name, inst in data_ref.items():
for ob_name, matrix_str in inst:
if ob_name not in duplidata_ref: #.items() for a dictionary
tabWrite("\n//----Blender Object Name:%s----\n" % ob_name)
if ob.pov.object_as == '':
tabWrite("object { \n")
tabWrite("%s\n" % data_name)
tabWrite("%s\n" % matrix_str)
tabWrite("}\n")
else:
no_boolean = True
for mod in ob.modifiers:
if mod.type == 'BOOLEAN':
operation = None
no_boolean = False
if mod.operation == 'INTERSECT':
operation = 'intersection'
else:
operation = mod.operation.lower()
mod_ob_name = string_strip_hyphen(bpy.path.clean_name(mod.object.name))
mod_matrix = global_matrix @ mod.object.matrix_world
mod_ob_matrix = MatrixAsPovString(mod_matrix)
tabWrite("%s { \n"%operation)
tabWrite("object { \n")
tabWrite("%s\n" % data_name)
tabWrite("%s\n" % matrix_str)
tabWrite("}\n")
tabWrite("object { \n")
tabWrite("%s\n" % ('DATA'+ mod_ob_name))
tabWrite("%s\n" % mod_ob_matrix)
tabWrite("}\n")
tabWrite("}\n")
break
if no_boolean:
tabWrite("object { \n")
tabWrite("%s\n" % data_name)
tabWrite("%s\n" % matrix_str)
tabWrite("}\n")
Maurice Raybaud
committed
"""write world as POV backgrounbd and sky_sphere to exported file """
matrix = global_matrix @ camera.matrix_world
#############Maurice####################################
#These lines added to get sky gradient (visible with PNG output)
if world:
#For simple flat background:
if not world.pov.use_sky_blend:
Bastien Montagne
committed
# Non fully transparent background could premultiply alpha and avoid anti-aliasing
# display issue:
if render.alpha_mode == 'TRANSPARENT':
Bastien Montagne
committed
tabWrite("background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n" % \
#Currently using no alpha with Sky option:
elif render.alpha_mode == 'SKY':
tabWrite("background {rgbt<%.3g, %.3g, %.3g, 0>}\n" % (world.pov.horizon_color[:]))
# XXX Does not exists anymore
#else:
#tabWrite("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
for t in world.texture_slots: # risk to write several sky_spheres but maybe ok.
if t and t.texture.type is not None:
Bastien Montagne
committed
# XXX No enable checkbox for world textures yet (report it?)
#if t and t.texture.type == 'IMAGE' and t.use:
if t and t.texture.type == 'IMAGE':
if t.texture.image.filepath != image_filename:
t.texture.image.filepath = image_filename
if image_filename != "" and t.use_map_blend:
texturesBlend = image_filename
#colvalue = t.default_value
t_blend = t
Bastien Montagne
committed
Bastien Montagne
committed
# Commented below was an idea to make the Background image oriented as camera
# taken here:
#http://news.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
Bastien Montagne
committed
# Replace 4/3 by the ratio of each image found by some custom or existing
# function
#mappingBlend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees" \
# "(atan((camLocation - camLookAt).x/(camLocation - " \
# "camLookAt).y)) rotate x*degrees(atan((camLocation - " \
# "camLookAt).y/(camLocation - camLookAt).z)) rotate y*" \
# "degrees(atan((camLocation - camLookAt).z/(camLocation - " \
# "camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % \
# (t_blend.offset.x / 10 , t_blend.offset.y / 10 ,
# t_blend.offset.z / 10, t_blend.scale.x ,
# t_blend.scale.y , t_blend.scale.z))
#using camera rotation valuesdirectly from blender seems much easier
if t_blend.texture_coords == 'ANGMAP':
mappingBlend = ""
Maurice Raybaud
committed
else:
# 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
# UV scale is 0.5,0.5 in blender and 0,0 in POV
# required for the sky_sphere not to repeat
mappingBlend = "scale 2 scale <%.4g,%.4g,%.4g> translate -1 " \
"translate <%.4g,%.4g,%.4g> rotate<0,0,0> " % \
(1.0 / t_blend.scale.y),
0.5-(0.5/t_blend.scale.x)- t_blend.offset.x,
0.5-(0.5/t_blend.scale.y)- t_blend.offset.y,
t_blend.offset.z)
Bastien Montagne
committed
# The initial position and rotation of the pov camera is probably creating
# the rotation offset should look into it someday but at least background
# won't rotate with the camera now.
# Putting the map on a plane would not introduce the skysphere distortion and
# allow for better image scale matching but also some waay to chose depth and
# size of the plane relative to camera.
tabWrite("sky_sphere {\n")
tabWrite("pigment {\n")
Bastien Montagne
committed
tabWrite("image_map{%s \"%s\" %s}\n" % \
(imageFormat(texturesBlend), texturesBlend, imgMapBG(t_blend)))
tabWrite("}\n")
tabWrite("%s\n" % (mappingBlend))
Bastien Montagne
committed
# The following layered pigment opacifies to black over the texture for
# transmit below 1 or otherwise adds to itself
Maurice Raybaud
committed
tabWrite("pigment {rgb 0 transmit %s}\n" % (t.texture.intensity))
tabWrite("}\n")
#tabWrite("scale 2\n")
#tabWrite("translate -1\n")
#For only Background gradient
if worldTexCount == 0:
tabWrite("sky_sphere {\n")
tabWrite("pigment {\n")
Bastien Montagne
committed
# maybe Should follow the advice of POV doc about replacing gradient
# for skysphere..5.5
tabWrite("gradient y\n")
tabWrite("color_map {\n")
# XXX Does not exists anymore
#if render.alpha_mode == 'STRAIGHT':
#tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
#tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
if render.alpha_mode == 'TRANSPARENT':
tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.horizon_color[:]))
Bastien Montagne
committed
# aa premult not solved with transmit 1
tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.zenith_color[:]))
tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.horizon_color[:]))
tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.zenith_color[:]))
tabWrite("}\n")
tabWrite("}\n")
tabWrite("}\n")
Bastien Montagne
committed
# Sky_sphere alpha (transmit) is not translating into image alpha the same
# way as 'background'
#if world.pov.light_settings.use_indirect_light:
Bastien Montagne
committed
# scene.pov.radio_enable=1
# Maybe change the above to a function copyInternalRenderer settings when
Bastien Montagne
committed
# user pushes a button, then:
#scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
Bastien Montagne
committed
# and other such translations but maybe this would not be allowed either?
###############################################################
tabWrite("fog {\n")
if mist.falloff=='LINEAR':
tabWrite("distance %.6f\n" % ((mist.start+mist.depth)*0.368))
elif mist.falloff=='QUADRATIC': # n**2 or squrt(n)?
tabWrite("distance %.6f\n" % ((mist.start+mist.depth)**2*0.368))
elif mist.falloff=='INVERSE_QUADRATIC': # n**2 or squrt(n)?
tabWrite("distance %.6f\n" % ((mist.start+mist.depth)**2*0.368))
Bastien Montagne
committed
tabWrite("color rgbt<%.3g, %.3g, %.3g, %.3g>\n" % \
(*world.pov.horizon_color, 1.0 - mist.intensity))
#tabWrite("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
#tabWrite("fog_alt %.6f\n" % mist.height) #XXX right?
#tabWrite("turbulence 0.2\n")
#tabWrite("turb_depth 0.3\n")
tabWrite("fog_type 1\n") #type2 for height
tabWrite("}\n")
Bastien Montagne
committed
if scene.pov.media_enable:
tabWrite("media {\n")
tabWrite("scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n" % \
(int(scene.pov.media_scattering_type),
*(scene.pov.media_diffusion_color[:])))
if scene.pov.media_scattering_type == '5':
tabWrite("eccentricity %.3g\n" % scene.pov.media_eccentricity)
tabWrite("}\n")
tabWrite("absorption %.12f*<%.4g, %.4g, %.4g>\n" % \
(scene.pov.media_absorption_scale,
*(scene.pov.media_absorption_color[:])))
tabWrite("\n")
Bastien Montagne
committed
tabWrite("samples %.d\n" % scene.pov.media_samples)
tabWrite("}\n")
"""write all POV global settings to exported file """
tabWrite("global_settings {\n")
tabWrite("assumed_gamma 1.0\n")
Bastien Montagne
committed
tabWrite("max_trace_level %d\n" % scene.pov.max_trace_level)
Maurice Raybaud
committed
if scene.pov.charset != 'ascii':
file.write(" charset %s\n"%scene.pov.charset)
if scene.pov.global_settings_advanced:
if scene.pov.radio_enable == False:
Maurice Raybaud
committed
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(" 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)
Bastien Montagne
committed
if scene.pov.radio_enable:
tabWrite("radiosity {\n")
Bastien Montagne
committed
tabWrite("adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
tabWrite("brightness %.4g\n" % scene.pov.radio_brightness)
tabWrite("count %d\n" % scene.pov.radio_count)
tabWrite("error_bound %.4g\n" % scene.pov.radio_error_bound)
tabWrite("gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
tabWrite("low_error_factor %.4g\n" % scene.pov.radio_low_error_factor)
tabWrite("maximum_reuse %.4g\n" % scene.pov.radio_maximum_reuse)
Bastien Montagne
committed
tabWrite("minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
tabWrite("nearest_count %d\n" % scene.pov.radio_nearest_count)
tabWrite("pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
tabWrite("pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
tabWrite("recursion_limit %d\n" % scene.pov.radio_recursion_limit)
Maurice Raybaud
committed
tabWrite("always_sample %d\n" % scene.pov.radio_always_sample)
tabWrite("normal %d\n" % scene.pov.radio_normal)
tabWrite("media %d\n" % scene.pov.radio_media)
tabWrite("subsurface %d\n" % scene.pov.radio_subsurface)
tabWrite("}\n")
Bastien Montagne
committed
onceSss = 1
onceAmbient = 1
oncePhotons = 1
if material.pov_subsurface_scattering.use and onceSss:
Bastien Montagne
committed
# In pov, the scale has reversed influence compared to blender. these number
# should correct that
tabWrite("mm_per_unit %.6f\n" % \
(material.pov_subsurface_scattering.scale * 1000.0))
# 1000 rather than scale * (-100.0) + 15.0))
Bastien Montagne
committed
# In POV-Ray, the scale factor for all subsurface shaders needs to be the same
# formerly sslt_samples were multiplied by 100 instead of 10
sslt_samples = (11 - material.pov_subsurface_scattering.error_threshold) * 10
tabWrite("subsurface { samples %d, %d }\n" % (sslt_samples, sslt_samples / 10))
Bastien Montagne
committed
onceSss = 0
Bastien Montagne
committed
if world and onceAmbient:
tabWrite("ambient_light rgb<%.3g, %.3g, %.3g>\n" % world.pov.ambient_color[:])
Bastien Montagne
committed
onceAmbient = 0
Maurice Raybaud
committed
Maurice Raybaud
committed
if scene.pov.photon_enable:
if (oncePhotons and
(material.pov.refraction_type == "2" or
material.pov.photons_reflection == True)):
tabWrite("photons {\n")
tabWrite("spacing %.6f\n" % scene.pov.photon_spacing)
tabWrite("max_trace_level %d\n" % scene.pov.photon_max_trace_level)
tabWrite("adc_bailout %.3g\n" % scene.pov.photon_adc_bailout)
tabWrite("gather %d, %d\n" % (scene.pov.photon_gather_min,
scene.pov.photon_gather_max))
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)
tabWrite('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):
Maurice Raybaud
committed
tabWrite("}\n")
oncePhotons = 0
tabWrite("}\n")
Maurice Raybaud
committed
def exportCustomCode():
"""write all POV user defined custom code to exported file """
# Write CurrentAnimation Frame for use in Custom POV Code
file.write("#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current)
#Change path and uncomment to add an animated include file by hand:
file.write("//#include \"/home/user/directory/animation_include_file.inc\"\n")
Campbell Barton
committed
for txt in bpy.data.texts:
Maurice Raybaud
committed
if txt.pov.custom_code == 'both':
Campbell Barton
committed
# Why are the newlines needed?
file.write("\n")
file.write(txt.as_string())
file.write("\n")
Maurice Raybaud
committed
#sel = renderable_objects(scene) #removed for booleans
Bastien Montagne
committed
file.write("//----------------------------------------------\n" \
"//--Exported with POV-Ray exporter for Blender--\n" \
"//----------------------------------------------\n\n")
file.write("#version 3.7;\n")
file.write("#declare Default_texture = texture{pigment {rgb 0.8} "
"finish {brilliance 3.8} }\n\n")
file.write("\n//--Global settings--\n\n")
file.write("\n//--Custom Code--\n\n")
exportCustomCode()
if comments:
file.write("\n//--Patterns Definitions--\n\n")
LocalPatternNames = []
for texture in bpy.data.textures: #ok?
if texture.users > 0:
currentPatName = string_strip_hyphen(bpy.path.clean_name(texture.name))
#string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
#use above list to prevent writing texture instances several times and assign in mats?
Maurice Raybaud
committed
if (texture.type not in {'NONE', 'IMAGE'} and texture.pov.tex_pattern_type == 'emulator')or(texture.type in {'NONE', 'IMAGE'} and texture.pov.tex_pattern_type != 'emulator'):
Maurice Raybaud
committed
file.write("\n#declare PAT_%s = \n" % currentPatName)
file.write(shading.exportPattern(texture, string_strip_hyphen))
file.write("\n//--Background--\n\n")
file.write("\n//--Cameras--\n\n")
file.write("\n//--Lamps--\n\n")
for ob in bpy.data.objects:
if ob.type == 'MESH':
for mod in ob.modifiers:
if mod.type == 'BOOLEAN':
if mod.object not in csg_list:
csg_list.append(mod.object)
if csg_list != []:
csg = False
sel = no_renderable_objects(scene)
exportMeshes(scene, sel, csg)
csg = True
sel = renderable_objects(scene)
exportLamps([L for L in sel if (L.type == 'LIGHT' and L.pov.object_as != 'RAINBOW')])
if comments:
file.write("\n//--Rainbows--\n\n")
exportRainbows([L for L in sel if (L.type == 'LIGHT' and L.pov.object_as == 'RAINBOW')])
if comments:
file.write("\n//--Special Curves--\n\n")
for c in sel:
if c.is_modified(scene, 'RENDER'):
continue #don't export as pov curves objects with modifiers, but as mesh
elif c.type == 'CURVE' and (c.pov.curveshape in {'lathe','sphere_sweep','loft','birail'}):
file.write("\n//--Material Definitions--\n\n")
# write a default pigment for objects with no material (comment out to show black)
Maurice Raybaud
committed
file.write("#default{ pigment{ color srgb 0.8 }}\n")
# Convert all materials to strings we can access directly per vertex.
shading.writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, None) # default material
if material.pov.material_use_nodes:
ntree = material.node_tree
povMatName=string_strip_hyphen(bpy.path.clean_name(material.name))
if len(ntree.nodes)==0:
file.write('#declare %s = texture {%s}\n'%(povMatName,color))
else:
shading.write_nodes(scene,povMatName,ntree,file)
for node in ntree.nodes:
if node:
if node.bl_idname == "PovrayOutputNode":
if node.inputs["Texture"].is_linked:
for link in ntree.links:
if link.to_node.bl_idname == "PovrayOutputNode":
povMatName=string_strip_hyphen(bpy.path.clean_name(link.from_node.name))+"_%s"%povMatName
else:
file.write('#declare %s = texture {%s}\n'%(povMatName,color))
else:
shading.writeMaterial(using_uberpov, DEF_MAT_NAME, scene, tabWrite, safety, comments, uniqueName, materialNames, material)
# attributes are all the variables needed by the other python file...
file.write("\n")
exportMeta([m for m in sel if m.type == 'META'])
file.write("//--Mesh objects--\n")
exportMeshes(scene, sel, csg)
#What follow used to happen here:
#exportCamera()
#exportWorld(scene.world)
#exportGlobalSettings(scene)
# MR:..and the order was important for implementing pov 3.7 baking
Bastien Montagne
committed
# (mesh camera) comment for the record
Constantin Rahn
committed
# CR: Baking should be a special case than. If "baking", than we could change the order.
#print("pov file closed %s" % file.closed)
#print("pov file closed %s" % file.closed)
def write_pov_ini(scene, filename_ini, filename_log, filename_pov, filename_image):
feature_set = bpy.context.preferences.addons[__package__].preferences.branch_feature_set_povray
using_uberpov = (feature_set=='uberpov')
#scene = bpy.data.scenes[0]
scene = bpy.context.scene
x = int(render.resolution_x * render.resolution_percentage * 0.01)
y = int(render.resolution_y * render.resolution_percentage * 0.01)
file.write("Version=3.7\n")
#write povray text stream to temporary file of same name with _log suffix
#file.write("All_File='%s'\n" % filename_log)
# DEBUG.OUT log if none specified:
file.write("All_File=1\n")
file.write("Input_File_Name='%s'\n" % filename_pov)
file.write("Output_File_Name='%s'\n" % filename_image)
file.write("Width=%d\n" % x)
file.write("Height=%d\n" % y)
# Border render.
if render.use_border:
file.write("Start_Column=%4g\n" % render.border_min_x)
file.write("End_Column=%4g\n" % (render.border_max_x))
file.write("Start_Row=%4g\n" % (1.0 - render.border_max_y))
file.write("End_Row=%4g\n" % (1.0 - render.border_min_y))
file.write("Bounding_Method=2\n") # The new automatic BSP is faster in most scenes
Bastien Montagne
committed
# Activated (turn this back off when better live exchange is done between the two programs
# (see next comment)
file.write("Display=1\n")
file.write("Pause_When_Done=0\n")
Bastien Montagne
committed
# PNG, with POV-Ray 3.7, can show background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
file.write("Output_File_Type=N\n")
#file.write("Output_File_Type=T\n") # TGA, best progressive loading
file.write("Output_Alpha=1\n")
Bastien Montagne
committed
if scene.pov.antialias_enable:
# method 2 (recursive) with higher max subdiv forced because no mipmapping in POV-Ray
# needs higher sampling.
# aa_mapping = {"5": 2, "8": 3, "11": 4, "16": 5}
if using_uberpov:
method = {"0": 1, "1": 2, "2": 3}
else:
method = {"0": 1, "1": 2, "2": 2}
file.write("Antialias=on\n")
Bastien Montagne
committed
file.write("Antialias_Depth=%d\n" % scene.pov.antialias_depth)
file.write("Antialias_Threshold=%.3g\n" % scene.pov.antialias_threshold)
if using_uberpov and scene.pov.antialias_method == '2':
file.write("Sampling_Method=%s\n" % method[scene.pov.antialias_method])
file.write("Antialias_Confidence=%.3g\n" % scene.pov.antialias_confidence)
else:
file.write("Sampling_Method=%s\n" % method[scene.pov.antialias_method])
Bastien Montagne
committed
file.write("Antialias_Gamma=%.3g\n" % scene.pov.antialias_gamma)
if scene.pov.jitter_enable:
file.write("Jitter=on\n")
Bastien Montagne
committed
file.write("Jitter_Amount=%3g\n" % scene.pov.jitter_amount)
file.write("Jitter=off\n") # prevent animation flicker
file.write("Antialias=off\n")
#print("ini file closed %s" % file.closed)
#print("ini file closed %s" % file.closed)
bl_label = "Persitence Of Vision"
bl_use_shading_nodes_custom = False
Campbell Barton
committed
@staticmethod
def _locate_binary():
addon_prefs = bpy.context.preferences.addons[__package__].preferences
Campbell Barton
committed
# Use the system preference if its set.
pov_binary = addon_prefs.filepath_povray
if pov_binary:
if os.path.exists(pov_binary):
return pov_binary
else:
print("User Preferences path to povray %r NOT FOUND, checking $PATH" % pov_binary)
Campbell Barton
committed
# Windows Only
# assume if there is a 64bit binary that the user has a 64bit capable OS
if sys.platform[:3] == "win":
import winreg
win_reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
"Software\\POV-Ray\\v3.7\\Windows")
Campbell Barton
committed
win_home = winreg.QueryValueEx(win_reg_key, "Home")[0]
# First try 64bits UberPOV
pov_binary = os.path.join(win_home, "bin", "uberpov64.exe")
if os.path.exists(pov_binary):
return pov_binary
# Then try 64bits POV
Campbell Barton
committed
pov_binary = os.path.join(win_home, "bin", "pvengine64.exe")
if os.path.exists(pov_binary):
return pov_binary
# Then try 32bits UberPOV
pov_binary = os.path.join(win_home, "bin", "uberpov32.exe")
if os.path.exists(pov_binary):
# Then try 32bits POV
Campbell Barton
committed
pov_binary = os.path.join(win_home, "bin", "pvengine.exe")
if os.path.exists(pov_binary):
return pov_binary
# search the path all os's
pov_binary_default = "povray"
os_path_ls = os.getenv("PATH").split(':') + [""]
for dir_name in os_path_ls:
pov_binary = os.path.join(dir_name, pov_binary_default)
if os.path.exists(pov_binary):
return pov_binary
return ""
def _export(self, depsgraph, povPath, renderImagePath):
"""gather all necessary output files paths user defined and auto generated and export there"""
scene = bpy.context.scene
Bastien Montagne
committed
if scene.pov.tempfiles_enable:
self._temp_file_in = tempfile.NamedTemporaryFile(suffix=".pov", delete=False).name
Bastien Montagne
committed
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
#self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
self._temp_file_log = os.path.join(tempfile.gettempdir(), "alltext.out")
else:
self._temp_file_in = povPath + ".pov"
Bastien Montagne
committed
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
self._temp_file_out = renderImagePath + ".png"
#self._temp_file_out = renderImagePath + ".tga"
self._temp_file_ini = povPath + ".ini"
logPath = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
self._temp_file_log = os.path.join(logPath, "alltext.out")
'''
self._temp_file_in = "/test.pov"
Bastien Montagne
committed
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
self._temp_file_out = "/test.png"
#self._temp_file_out = "/test.tga"
self._temp_file_ini = "/test.ini"
'''
Maurice Raybaud
committed
if scene.pov.text_block == "":
def info_callback(txt):
self.update_stats("", "POV-Ray 3.7: " + txt)
Maurice Raybaud
committed
# os.makedirs(user_dir, exist_ok=True) # handled with previews
os.makedirs(preview_dir, exist_ok=True)
Maurice Raybaud
committed
write_pov(self._temp_file_in, scene, info_callback)
else:
pass
def _render(self, depsgraph):
"""Export necessary files and render image."""
os.remove(self._temp_file_out) # so as not to load the old file
Campbell Barton
committed
pov_binary = PovrayRender._locate_binary()
if not pov_binary:
print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
return False
write_pov_ini(scene, self._temp_file_ini, self._temp_file_log, self._temp_file_in, self._temp_file_out)
print ("***-STARTING-***")
Doug Hammond
committed
extra_args = []
Bastien Montagne
committed
if scene.pov.command_line_switches != "":
for newArg in scene.pov.command_line_switches.split(" "):
Constantin Rahn
committed
extra_args.append(newArg)
self._is_windows = False
self._is_windows = True
if"/EXIT" not in extra_args and not scene.pov.pov_editor:
extra_args.append("/EXIT")
Doug Hammond
committed
else:
Campbell Barton
committed
# added -d option to prevent render window popup which leads to segfault on linux
extra_args.append("-d")
Campbell Barton
committed
# Start Rendering!
try:
self._process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
# TODO, report api
print("POV-Ray 3.7: could not execute '%s'" % pov_binary)
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
Campbell Barton
committed
else:
print("Engine ready!...")
Campbell Barton
committed
print("Command line arguments passed: " + str(extra_args))
return True
# Now that we have a valid process
for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
for i in range(5):
try:
os.unlink(f)
break
except OSError:
# Wait a bit before retrying file might be still in use by Blender,
# and Windows does not know how to delete a file in use!
time.sleep(self.DELAY)
for i in unpacked_images:
for c in range(5):
try:
os.unlink(i)
break
except OSError:
# Wait a bit before retrying file might be still in use by Blender,
# and Windows does not know how to delete a file in use!
time.sleep(self.DELAY)
def render(self, depsgraph):
"""Export necessary files from text editor and render image."""
scene = bpy.context.scene
x = int(r.resolution_x * r.resolution_percentage * 0.01)
y = int(r.resolution_y * r.resolution_percentage * 0.01)
Maurice Raybaud
committed
print("***INITIALIZING***")
# This makes some tests on the render, returning True if all goes good, and False if
# it was finished one way or the other.
# It also pauses the script (time.sleep())
def _test_wait():
time.sleep(self.DELAY)
# User interrupts the rendering
print("***POV INTERRUPTED***")
return False
Doug Hammond
committed
poll_result = self._process.poll()
# POV process is finisehd, one way or the other
if poll_result < 0:
print("***POV PROCESS FAILED : %s ***" % poll_result)
self.update_stats("", "POV-Ray 3.7: Failed")
return False
return True
if bpy.context.scene.pov.text_block !="":
Maurice Raybaud
committed
if scene.pov.tempfiles_enable:
self._temp_file_in = tempfile.NamedTemporaryFile(suffix=".pov", delete=False).name
self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
#self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
self._temp_file_log = os.path.join(tempfile.gettempdir(), "alltext.out")
else:
povPath = scene.pov.text_block
renderImagePath = os.path.splitext(povPath)[0]
self._temp_file_out =os.path.join(preview_dir, renderImagePath )
self._temp_file_in = os.path.join(preview_dir, povPath)
self._temp_file_ini = os.path.join(preview_dir, (os.path.splitext(self._temp_file_in)[0]+".INI"))
self._temp_file_log = os.path.join(preview_dir, "alltext.out")
Maurice Raybaud
committed
Maurice Raybaud
committed
'''
try:
os.remove(self._temp_file_in) # so as not to load the old file
except OSError:
pass
Maurice Raybaud
committed
print(scene.pov.text_block)
text = bpy.data.texts[scene.pov.text_block]
file=open("%s"%self._temp_file_in,"w")
# Why are the newlines needed?
file.write("\n")
file.write(text.as_string())
Maurice Raybaud
committed
file.close()
# has to be called to update the frame on exporting animations
scene.frame_set(scene.frame_current)
Maurice Raybaud
committed
pov_binary = PovrayRender._locate_binary()
if not pov_binary:
print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
return False
Maurice Raybaud
committed
# start ini UI options export
self.update_stats("", "POV-Ray 3.7: Exporting ini options from Blender")
Maurice Raybaud
committed
write_pov_ini(scene, self._temp_file_ini, self._temp_file_log, self._temp_file_in, self._temp_file_out)
print ("***-STARTING-***")
extra_args = []
Maurice Raybaud
committed
if scene.pov.command_line_switches != "":
for newArg in scene.pov.command_line_switches.split(" "):
extra_args.append(newArg)
if sys.platform[:3] == "win":
if"/EXIT" not in extra_args and not scene.pov.pov_editor:
extra_args.append("/EXIT")
else:
Maurice Raybaud
committed
# added -d option to prevent render window popup which leads to segfault on linux
extra_args.append("-d")
# Start Rendering!
try:
if sys.platform[:3] != "win" and scene.pov.sdl_window_enable: #segfault on linux == False !!!
env = {'POV_DISPLAY_SCALED': 'off'}
env.update(os.environ)
self._process = subprocess.Popen([pov_binary, self._temp_file_ini],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
env=env)
else:
self._process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args,
Maurice Raybaud
committed
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
# TODO, report api
print("POV-Ray 3.7: could not execute '%s'" % pov_binary)
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
else:
print("Engine ready!...")
print("Command line arguments passed: " + str(extra_args))
#return True
self.update_stats("", "POV-Ray 3.7: Parsing File")
Maurice Raybaud
committed
Maurice Raybaud
committed
# Indented in main function now so repeated here but still not working
Maurice Raybaud
committed
# to bring back render result to its buffer
Maurice Raybaud
committed
if os.path.exists(self._temp_file_out):
xmin = int(r.border_min_x * x)
ymin = int(r.border_min_y * y)
xmax = int(r.border_max_x * x)
ymax = int(r.border_max_y * y)
Maurice Raybaud
committed
lay = result.layers[0]
Maurice Raybaud
committed
time.sleep(self.DELAY)
try:
lay.load_from_file(self._temp_file_out)
except RuntimeError:
print("***POV ERROR WHILE READING OUTPUT FILE***")
self.end_result(result)
#print(self._temp_file_log) #bring the pov log to blender console with proper path?
with open(self._temp_file_log) as f: # The with keyword automatically closes the file when you are done
Maurice Raybaud
committed
self.update_stats("", "")
Maurice Raybaud
committed
Maurice Raybaud
committed
if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
Maurice Raybaud
committed
else:
Maurice Raybaud
committed
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
##WIP output format
## if r.image_settings.file_format == 'OPENEXR':
## fformat = 'EXR'
## render.image_settings.color_mode = 'RGBA'
## else:
## fformat = 'TGA'
## r.image_settings.file_format = 'TARGA'
## r.image_settings.color_mode = 'RGBA'
blendSceneName = bpy.data.filepath.split(os.path.sep)[-1].split(".")[0]
povSceneName = ""
povPath = ""
renderImagePath = ""
# has to be called to update the frame on exporting animations
scene.frame_set(scene.frame_current)
if not scene.pov.tempfiles_enable:
# check paths
povPath = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
if povPath == "":
if bpy.data.is_saved:
povPath = bpy.path.abspath("//")
else:
Maurice Raybaud
committed
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
povPath = tempfile.gettempdir()
elif povPath.endswith("/"):
if povPath == "/":
povPath = bpy.path.abspath("//")
else:
povPath = bpy.path.abspath(scene.pov.scene_path)
if not os.path.exists(povPath):
try:
os.makedirs(povPath)
except:
import traceback
traceback.print_exc()
print("POV-Ray 3.7: Cannot create scenes directory: %r" % povPath)
self.update_stats("", "POV-Ray 3.7: Cannot create scenes directory %r" % \
povPath)
time.sleep(2.0)
#return
'''
# Bug in POV-Ray RC3
renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
if renderImagePath == "":
if bpy.data.is_saved:
renderImagePath = bpy.path.abspath("//")
else:
renderImagePath = tempfile.gettempdir()
#print("Path: " + renderImagePath)
elif path.endswith("/"):
if renderImagePath == "/":
renderImagePath = bpy.path.abspath("//")
else:
renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
if not os.path.exists(path):
print("POV-Ray 3.7: Cannot find render image directory")
Maurice Raybaud
committed
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
self.update_stats("", "POV-Ray 3.7: Cannot find render image directory")
time.sleep(2.0)
return
'''
# check name
if scene.pov.scene_name == "":
if blendSceneName != "":
povSceneName = blendSceneName
else:
povSceneName = "untitled"
else:
povSceneName = scene.pov.scene_name
if os.path.isfile(povSceneName):
povSceneName = os.path.basename(povSceneName)
povSceneName = povSceneName.split('/')[-1].split('\\')[-1]
if not povSceneName:
print("POV-Ray 3.7: Invalid scene name")
self.update_stats("", "POV-Ray 3.7: Invalid scene name")
time.sleep(2.0)
#return
povSceneName = os.path.splitext(povSceneName)[0]
print("Scene name: " + povSceneName)
print("Export path: " + povPath)
povPath = os.path.join(povPath, povSceneName)
povPath = os.path.realpath(povPath)
# for now this has to be the same like the pov output. Bug in POV-Ray RC3.
# renderImagePath = renderImagePath + "\\" + povSceneName
renderImagePath = povPath # Bugfix for POV-Ray RC3 bug
# renderImagePath = os.path.realpath(renderImagePath) # Bugfix for POV-Ray RC3 bug
#print("Export path: %s" % povPath)
#print("Render Image path: %s" % renderImagePath)
# start export
self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
self._export(depsgraph, povPath, renderImagePath)
Maurice Raybaud
committed
self.update_stats("", "POV-Ray 3.7: Parsing File")
if not self._render(depsgraph):
Maurice Raybaud
committed
self.update_stats("", "POV-Ray 3.7: Not found")
#return
#r = scene.render
# compute resolution
#x = int(r.resolution_x * r.resolution_percentage * 0.01)
#y = int(r.resolution_y * r.resolution_percentage * 0.01)
# Wait for the file to be created
# XXX This is no more valid, as 3.7 always creates output file once render is finished!
parsing = re.compile(br"= \[Parsing\.\.\.\] =")
rendering = re.compile(br"= \[Rendering\.\.\.\] =")
percent = re.compile(r"\(([0-9]{1,3})%\)")
# print("***POV WAITING FOR FILE***")
data = b""
last_line = ""
while _test_wait():
Maurice Raybaud
committed
# POV in Windows did not output its stdout/stderr, it displayed them in its GUI
# But now writes file
Maurice Raybaud
committed
if self._is_windows:
self.update_stats("", "POV-Ray 3.7: Rendering File")
else:
t_data = self._process.stdout.read(10000)
if not t_data:
continue
Maurice Raybaud
committed
data += t_data
# XXX This is working for UNIX, not sure whether it might need adjustments for
# other OSs
# First replace is for windows
t_data = str(t_data).replace('\\r\\n', '\\n').replace('\\r', '\r')
lines = t_data.split('\\n')
last_line += lines[0]
lines[0] = last_line
print('\n'.join(lines), end="")
last_line = lines[-1]
if rendering.search(data):
_pov_rendering = True
match = percent.findall(str(data))
if match:
self.update_stats("", "POV-Ray 3.7: Rendering File (%s%%)" % match[-1])
else:
self.update_stats("", "POV-Ray 3.7: Rendering File")
Maurice Raybaud
committed
elif parsing.search(data):
self.update_stats("", "POV-Ray 3.7: Parsing File")
Maurice Raybaud
committed
if os.path.exists(self._temp_file_out):
# print("***POV FILE OK***")
#self.update_stats("", "POV-Ray 3.7: Rendering")
Maurice Raybaud
committed
# prev_size = -1
Maurice Raybaud
committed
xmin = int(r.border_min_x * x)
ymin = int(r.border_min_y * y)
xmax = int(r.border_max_x * x)
ymax = int(r.border_max_y * y)
Maurice Raybaud
committed
# print("***POV UPDATING IMAGE***")
result = self.begin_result(0, 0, x, y)
Bastien Montagne
committed
# XXX, tests for border render.
Maurice Raybaud
committed
#result = self.begin_result(xmin, ymin, xmax - xmin, ymax - ymin)
#result = self.begin_result(0, 0, xmax - xmin, ymax - ymin)
lay = result.layers[0]
Maurice Raybaud
committed
# This assumes the file has been fully written We wait a bit, just in case!
time.sleep(self.DELAY)
Campbell Barton
committed
try:
lay.load_from_file(self._temp_file_out)
# XXX, tests for border render.
#lay.load_from_file(self._temp_file_out, xmin, ymin)
except RuntimeError:
Maurice Raybaud
committed
print("***POV ERROR WHILE READING OUTPUT FILE***")
Campbell Barton
committed
Maurice Raybaud
committed
# Not needed right now, might only be useful if we find a way to use temp raw output of
# pov 3.7 (in which case it might go under _test_wait()).
'''
def update_image():
# possible the image wont load early on.
Campbell Barton
committed
try:
Maurice Raybaud
committed
lay.load_from_file(self._temp_file_out)
# XXX, tests for border render.
#lay.load_from_file(self._temp_file_out, xmin, ymin)
#lay.load_from_file(self._temp_file_out, xmin, ymin)
except RuntimeError:
Campbell Barton
committed
pass
Maurice Raybaud
committed
# Update while POV-Ray renders
while True:
# print("***POV RENDER LOOP***")
Campbell Barton
committed
Maurice Raybaud
committed
# test if POV-Ray exists
if self._process.poll() is not None:
print("***POV PROCESS FINISHED***")
update_image()
break
Campbell Barton
committed
Maurice Raybaud
committed
# user exit
if self.test_break():
try:
self._process.terminate()
print("***POV PROCESS INTERRUPTED***")
except OSError:
pass
Campbell Barton
committed
Maurice Raybaud
committed
break
Campbell Barton
committed
Maurice Raybaud
committed
# Would be nice to redirect the output
# stdout_value, stderr_value = self._process.communicate() # locks
Maurice Raybaud
committed
# check if the file updated
new_size = os.path.getsize(self._temp_file_out)
Maurice Raybaud
committed
if new_size != prev_size:
update_image()
prev_size = new_size
Maurice Raybaud
committed
time.sleep(self.DELAY)
'''
Maurice Raybaud
committed
self.end_result(result)
Maurice Raybaud
committed
else:
print("***POV FILE NOT FOUND***")
print("***POV FILE FINISHED***")
#print(filename_log) #bring the pov log to blender console with proper path?
with open(self._temp_file_log) as f: # The with keyword automatically closes the file when you are done
print(f.read())
Maurice Raybaud
committed
self.update_stats("", "")
if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
self._cleanup()
##################################################################################
#################################Operators########################################
##################################################################################
class RenderPovTexturePreview(Operator):
"""Export only files necessary to texture preview and render image."""
bl_idname = "tex.preview_update"
bl_label = "Update preview"
def execute(self, context):
tex=bpy.context.object.active_material.active_texture #context.texture
texPrevName=string_strip_hyphen(bpy.path.clean_name(tex.name))+"_prev"
Maurice Raybaud
committed
## Make sure Preview directory exists and is empty
if not os.path.isdir(preview_dir):
os.mkdir(preview_dir)
iniPrevFile=os.path.join(preview_dir, "Preview.ini")
inputPrevFile=os.path.join(preview_dir, "Preview.pov")
outputPrevFile=os.path.join(preview_dir, texPrevName)
##################### ini ##########################################
fileIni=open("%s"%iniPrevFile,"w")
fileIni.write('Version=3.7\n')
fileIni.write('Input_File_Name="%s"\n'%inputPrevFile)
fileIni.write('Output_File_Name="%s.png"\n'%outputPrevFile)
fileIni.write('Library_Path="%s"\n' % preview_dir)
fileIni.write('Width=256\n')
fileIni.write('Height=256\n')
fileIni.write('Pause_When_Done=0\n')
fileIni.write('Output_File_Type=N\n')
fileIni.write('Output_Alpha=1\n')
fileIni.write('Antialias=on\n')
fileIni.write('Sampling_Method=2\n')
fileIni.write('Antialias_Depth=3\n')
fileIni.write('-d\n')
fileIni.close()
##################### pov ##########################################
filePov=open("%s"%inputPrevFile,"w")
PATname = "PAT_"+string_strip_hyphen(bpy.path.clean_name(tex.name))
filePov.write("#declare %s = \n"%PATname)
filePov.write(shading.exportPattern(tex, string_strip_hyphen))
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
filePov.write("#declare Plane =\n")
filePov.write("mesh {\n")
filePov.write(" triangle {<-2.021,-1.744,2.021>,<-2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n")
filePov.write(" triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n")
filePov.write(" texture{%s}\n"%PATname)
filePov.write("}\n")
filePov.write("object {Plane}\n")
filePov.write("light_source {\n")
filePov.write(" <0,4.38,-1.92e-07>\n")
filePov.write(" color rgb<4, 4, 4>\n")
filePov.write(" parallel\n")
filePov.write(" point_at <0, 0, -1>\n")
filePov.write("}\n")
filePov.write("camera {\n")
filePov.write(" location <0, 0, 0>\n")
filePov.write(" look_at <0, 0, -1>\n")
filePov.write(" right <-1.0, 0, 0>\n")
filePov.write(" up <0, 1, 0>\n")
filePov.write(" angle 96.805211\n")
filePov.write(" rotate <-90.000003, -0.000000, 0.000000>\n")
filePov.write(" translate <0.000000, 0.000000, 0.000000>\n")
filePov.write("}\n")
filePov.close()
##################### end write ##########################################
pov_binary = PovrayRender._locate_binary()
if sys.platform[:3] == "win":
p1=subprocess.Popen(["%s"%pov_binary,"/EXIT","%s"%iniPrevFile],
stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
p1=subprocess.Popen(["%s"%pov_binary,"-d","%s"%iniPrevFile],
stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
p1.wait()
tex.use_nodes = True
tree = tex.node_tree
links = tree.links
for n in tree.nodes:
tree.nodes.remove(n)
pathPrev="%s.png"%outputPrevFile
im.image = bpy.data.images.load(pathPrev)
name=pathPrev
name=name.split("/")
name=name[len(name)-1]
im.location = 200,200
previewer = tree.nodes.new('TextureNodeOutput')
previewer.label = "Preview"
previewer.location = 400,400
links.new(im.outputs[0],previewer.inputs[0])
#tex.type="IMAGE" # makes clip extend possible
#tex.extension="CLIP"
Maurice Raybaud
committed
class RunPovTextRender(Operator):
"""Export files depending on text editor options and render image."""
Maurice Raybaud
committed
bl_idname = "text.run"
bl_label = "Run"
bl_context = "text"
bl_description = "Run a render with this text only"
Maurice Raybaud
committed
def execute(self, context):
scene = context.scene
scene.pov.text_block = context.space_data.text.name
Maurice Raybaud
committed
bpy.ops.render.render()
Maurice Raybaud
committed
Maurice Raybaud
committed
#empty text name property engain
scene.pov.text_block = ""
return {'FINISHED'}
classes = (
PovrayRender,
RenderPovTexturePreview,
RunPovTextRender,
)
def register():
#from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):