1 # ***** BEGIN GPL LICENSE BLOCK *****
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # #**** END GPL LICENSE BLOCK #****
26 from math
import atan
, pi
, degrees
, sqrt
, cos
, sin
35 import tempfile
# generate temporary files with random names
36 from bpy
.types
import Operator
37 from imghdr
import what
# imghdr is a python lib to identify image file types
38 from bpy
.utils
import register_class
40 from . import df3
# for smoke rendering
41 from . import shading
# for BI POV shaders emulation
42 from . import primitives
# for import and export of POV specific primitives
43 from . import nodes
# for POV specific nodes
45 ##############################SF###########################
46 ##############find image texture
47 def imageFormat(imgF
):
48 """Identify input image filetypes to transmit to POV."""
49 # First use the below explicit extensions to identify image file prospects
63 }.get(os
.path
.splitext(imgF
)[-1].upper(), "")
64 # Then, use imghdr to really identify the filetype as it can be different
66 # maybe add a check for if path exists here?
67 print(" WARNING: texture image has no extension") # too verbose
69 ext
= what(imgF
) # imghdr is a python lib to identify image file types
74 """Translate mapping type from Blender UI to POV syntax and return that string."""
76 texdata
= bpy
.data
.textures
[ts
.texture
]
77 if ts
.mapping
== 'FLAT':
78 image_map
= "map_type 0 "
79 elif ts
.mapping
== 'SPHERE':
80 image_map
= "map_type 1 "
81 elif ts
.mapping
== 'TUBE':
82 image_map
= "map_type 2 "
84 ## map_type 3 and 4 in development (?) (ENV in pov 3.8)
85 ## for POV-Ray, currently they just seem to default back to Flat (type 0)
86 # elif ts.mapping=="?":
87 # image_map = " map_type 3 "
88 # elif ts.mapping=="?":
89 # image_map = " map_type 4 "
90 if ts
.use_interpolation
: # Available if image sampling class reactivated?
91 image_map
+= " interpolate 2 "
92 if texdata
.extension
== 'CLIP':
95 # if ts.mapping=='CUBE':
96 # image_map+= "warp { cubic } rotate <-90,0,180>"
97 # no direct cube type mapping. Though this should work in POV 3.7
98 # it doesn't give that good results(best suited to environment maps?)
100 # print(" No texture image found ")
104 def imgMapTransforms(ts
):
105 """Translate mapping transformations from Blender UI to POV syntax and return that string."""
106 # XXX TODO: unchecked textures give error of variable referenced before assignment XXX
107 # POV-Ray "scale" is not a number of repetitions factor, but ,its
108 # inverse, a standard scale factor.
109 # 0.5 Offset is needed relatively to scale because center of the
110 # scale is 0.5,0.5 in blender and 0,0 in POV
111 # Strange that the translation factor for scale is not the same as for
113 # TODO: verify both matches with blender internal.
114 image_map_transforms
= ""
115 image_map_transforms
= (
116 "scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>"
126 # image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
127 # ( 1.0 / ts.scale.x,
130 # (0.5 / ts.scale.x) + ts.offset.x,
131 # (0.5 / ts.scale.y) + ts.offset.y,
133 # 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>" % \
140 return image_map_transforms
144 """Translate world mapping from Blender UI to POV syntax and return that string."""
145 tex
= bpy
.data
.textures
[wts
.texture
]
147 # texture_coords refers to the mapping of world textures:
148 if wts
.texture_coords
== 'VIEW' or wts
.texture_coords
== 'GLOBAL':
149 image_mapBG
= " map_type 0 "
150 elif wts
.texture_coords
== 'ANGMAP':
151 image_mapBG
= " map_type 1 "
152 elif wts
.texture_coords
== 'TUBE':
153 image_mapBG
= " map_type 2 "
155 if tex
.use_interpolation
:
156 image_mapBG
+= " interpolate 2 "
157 if tex
.extension
== 'CLIP':
158 image_mapBG
+= " once "
160 # if wts.mapping == 'CUBE':
161 # image_mapBG += "warp { cubic } rotate <-90,0,180>"
162 # no direct cube type mapping. Though this should work in POV 3.7
163 # it doesn't give that good results(best suited to environment maps?)
164 # if image_mapBG == "":
165 # print(" No background texture image found ")
169 def path_image(image
):
170 """Conform a path string to POV syntax to avoid POV errors."""
171 return bpy
.path
.abspath(image
.filepath
, library
=image
.library
).replace(
174 # .replace("\\","/") to get only forward slashes as it's what POV prefers,
178 # end find image texture
179 # -----------------------------------------------------------------------------
182 def string_strip_hyphen(name
):
183 """Remove hyphen characters from a string to avoid POV errors."""
184 return name
.replace("-", "")
187 def safety(name
, Level
):
188 """append suffix characters to names of various material declinations.
190 Material declinations are necessary to POV syntax and used in shading.py
191 by the povHasnoSpecularMaps function to create the finish map trick and
192 the suffixes avoid name collisions.
194 name -- the initial material name as a string
195 Level -- the enum number of the Level being written:
196 Level=1 is for texture with No specular nor Mirror reflection
197 Level=2 is for texture with translation of spec and mir levels
198 for when no map influences them
199 Level=3 is for texture with Maximum Spec and Mirror
208 name
= string_strip_hyphen(name
)
212 return prefix
+ name
+ "0" # used for 0 of specular map
214 return prefix
+ name
+ "1" # used for 1 of specular map
217 ##############end safety string name material
218 ##############################EndSF###########################
223 def is_renderable(scene
, ob
):
224 return not ob
.hide_render
and ob
not in csg_list
227 def renderable_objects(scene
):
228 return [ob
for ob
in bpy
.data
.objects
if is_renderable(scene
, ob
)]
231 def no_renderable_objects(scene
):
232 return [ob
for ob
in csg_list
]
238 user_dir
= bpy
.utils
.resource_path('USER')
239 preview_dir
= os
.path
.join(user_dir
, "preview")
241 ## Make sure Preview directory exists and is empty
242 smokePath
= os
.path
.join(preview_dir
, "smoke.df3")
244 def write_global_setting(scene,file):
245 file.write("global_settings {\n")
246 file.write(" assumed_gamma %.6f\n"%scene.pov.assumed_gamma)
247 if scene.pov.global_settings_advanced:
248 if scene.pov.radio_enable == False:
249 file.write(" adc_bailout %.6f\n"%scene.pov.adc_bailout)
250 file.write(" ambient_light <%.6f,%.6f,%.6f>\n"%scene.pov.ambient_light[:])
251 file.write(" irid_wavelength <%.6f,%.6f,%.6f>\n"%scene.pov.irid_wavelength[:])
252 file.write(" charset %s\n"%scene.pov.charset)
253 file.write(" max_trace_level %s\n"%scene.pov.max_trace_level)
254 file.write(" max_intersections %s\n"%scene.pov.max_intersections)
255 file.write(" number_of_waves %s\n"%scene.pov.number_of_waves)
256 file.write(" noise_generator %s\n"%scene.pov.noise_generator)
258 # below properties not added to __init__ yet to avoid conflicts with material sss scale
259 # unless it would override then should be interfaced also in scene units property tab
261 # if scene.pov.sslt_enable:
262 # file.write(" mm_per_unit %s\n"%scene.pov.mm_per_unit)
263 # file.write(" subsurface {\n")
264 # file.write(" samples %s, %s\n"%(scene.pov.sslt_samples_max,scene.pov.sslt_samples_min))
265 # if scene.pov.sslt_radiosity:
266 # file.write(" radiosity on\n")
269 if scene.pov.radio_enable:
270 file.write(" radiosity {\n")
271 file.write(" pretrace_start %.6f\n"%scene.pov.radio_pretrace_start)
272 file.write(" pretrace_end %.6f\n"%scene.pov.radio_pretrace_end)
273 file.write(" count %s\n"%scene.pov.radio_count)
274 file.write(" nearest_count %s\n"%scene.pov.radio_nearest_count)
275 file.write(" error_bound %.6f\n"%scene.pov.radio_error_bound)
276 file.write(" recursion_limit %s\n"%scene.pov.radio_recursion_limit)
277 file.write(" low_error_factor %.6f\n"%scene.pov.radio_low_error_factor)
278 file.write(" gray_threshold %.6f\n"%scene.pov.radio_gray_threshold)
279 file.write(" maximum_reuse %.6f\n"%scene.pov.radio_maximum_reuse)
280 file.write(" minimum_reuse %.6f\n"%scene.pov.radio_minimum_reuse)
281 file.write(" brightness %.6f\n"%scene.pov.radio_brightness)
282 file.write(" adc_bailout %.6f\n"%scene.pov.radio_adc_bailout)
283 if scene.pov.radio_normal:
284 file.write(" normal on\n")
285 if scene.pov.radio_always_sample:
286 file.write(" always_sample on\n")
287 if scene.pov.radio_media:
288 file.write(" media on\n")
289 if scene.pov.radio_subsurface:
290 file.write(" subsurface on\n")
293 if scene.pov.photon_enable:
294 file.write(" photons {\n")
295 if scene.pov.photon_enable_count:
296 file.write(" count %s\n"%scene.pov.photon_count)
298 file.write(" spacing %.6g\n"%scene.pov.photon_spacing)
299 if scene.pov.photon_gather:
300 file.write(" gather %s, %s\n"%(scene.pov.photon_gather_min,scene.pov.photon_gather_max))
301 if scene.pov.photon_autostop:
302 file.write(" autostop %.4g\n"%scene.pov.photon_autostop_value)
303 if scene.pov.photon_jitter_enable:
304 file.write(" jitter %.4g\n"%scene.pov.photon_jitter)
305 file.write(" max_trace_level %s\n"%scene.pov.photon_max_trace_level)
306 if scene.pov.photon_adc:
307 file.write(" adc_bailout %.6f\n"%scene.pov.photon_adc_bailout)
308 if scene.pov.photon_media_enable:
309 file.write(" media %s, %s\n"%(scene.pov.photon_media_steps,scene.pov.photon_media_factor))
310 if scene.pov.photon_map_file_save_load in {'save'}:
311 filePhName = 'Photon_map_file.ph'
312 if scene.pov.photon_map_file != '':
313 filePhName = scene.pov.photon_map_file+'.ph'
314 filePhDir = tempfile.gettempdir()
315 path = bpy.path.abspath(scene.pov.photon_map_dir)
316 if os.path.exists(path):
318 fullFileName = os.path.join(filePhDir,filePhName)
319 file.write(' save_file "%s"\n'%fullFileName)
320 scene.pov.photon_map_file = fullFileName
321 if scene.pov.photon_map_file_save_load in {'load'}:
322 fullFileName = bpy.path.abspath(scene.pov.photon_map_file)
323 if os.path.exists(fullFileName):
324 file.write(' load_file "%s"\n'%fullFileName)
330 def write_object_modifiers(scene
, ob
, File
):
331 """Translate some object level POV statements from Blender UI
332 to POV syntax and write to exported file """
334 # Maybe return that string to be added instead of directly written.
338 for mod in ob.modifiers:
341 if mod.type == 'BOOLEAN':
342 if ob.pov.boolean_mod == "POV":
343 File.write("\tinside_vector <%.6g, %.6g, %.6g>\n" %
344 (ob.pov.inside_vector[0],
345 ob.pov.inside_vector[1],
346 ob.pov.inside_vector[2]))
351 File
.write("\thollow\n")
352 if ob
.pov
.double_illuminate
:
353 File
.write("\tdouble_illuminate\n")
355 File
.write("\tsturm\n")
357 File
.write("\tno_shadow\n")
359 File
.write("\tno_image\n")
360 if ob
.pov
.no_reflection
:
361 File
.write("\tno_reflection\n")
362 if ob
.pov
.no_radiosity
:
363 File
.write("\tno_radiosity\n")
365 File
.write("\tinverse\n")
367 File
.write("\thierarchy\n")
369 # XXX, Commented definitions
371 if scene.pov.photon_enable:
372 File.write("photons {\n")
374 File.write("target %.4g\n"%ob.pov.target_value)
375 if ob.pov.refraction:
376 File.write("refraction on\n")
377 if ob.pov.reflection:
378 File.write("reflection on\n")
379 if ob.pov.pass_through:
380 File.write("pass_through\n")
382 if ob.pov.object_ior > 1:
383 File.write("interior {\n")
384 File.write("ior %.4g\n"%ob.pov.object_ior)
385 if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
386 File.write("ior %.4g\n"%ob.pov.dispersion_value)
387 File.write("ior %s\n"%ob.pov.dispersion_samples)
388 if scene.pov.photon_enable == False:
389 File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
393 def write_pov(filename
, scene
=None, info_callback
=None):
394 """Main export process from Blender UI to POV syntax and write to exported file """
399 file = open(filename
, "w")
403 scene
= bpy
.data
.scenes
[0]
405 render
= scene
.render
407 global_matrix
= mathutils
.Matrix
.Rotation(-pi
/ 2.0, 4, 'X')
408 comments
= scene
.pov
.comments_enable
and not scene
.pov
.tempfiles_enable
409 linebreaksinlists
= (
410 scene
.pov
.list_lf_enable
and not scene
.pov
.tempfiles_enable
412 feature_set
= bpy
.context
.preferences
.addons
[
414 ].preferences
.branch_feature_set_povray
415 using_uberpov
= feature_set
== 'uberpov'
416 pov_binary
= PovrayRender
._locate
_binary
()
419 print("Unofficial UberPOV feature set chosen in preferences")
421 print("Official POV-Ray 3.7 feature set chosen in preferences")
422 if 'uber' in pov_binary
:
424 "The name of the binary suggests you are probably rendering with Uber POV engine"
428 "The name of the binary suggests you are probably rendering with standard POV engine"
431 def setTab(tabtype
, spaces
):
433 if tabtype
== 'NONE':
435 elif tabtype
== 'TAB':
437 elif tabtype
== 'SPACE':
438 TabStr
= spaces
* " "
441 tab
= setTab(scene
.pov
.indentation_character
, scene
.pov
.indentation_spaces
)
442 if not scene
.pov
.tempfiles_enable
:
445 """Indent POV syntax from brackets levels and write to exported file """
454 tabLevel
= tabLevel
+ brackets
456 print("Indentation Warning: tabLevel = %s" % tabLevel
)
459 file.write("%s" % tab
* tabLevel
)
462 tabLevel
= tabLevel
+ brackets
467 """write directly to exported file if user checked autonamed temp files (faster)."""
471 def uniqueName(name
, nameSeq
):
472 """Increment any generated POV name that could get identical to avoid collisions"""
474 if name
not in nameSeq
:
475 name
= string_strip_hyphen(name
)
480 while name
in nameSeq
:
481 name
= "%s_%.3d" % (name_orig
, i
)
483 name
= string_strip_hyphen(name
)
486 def writeMatrix(matrix
):
487 """Translate some tranform matrix from Blender UI
488 to POV syntax and write to exported file """
490 "matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n"
507 def MatrixAsPovString(matrix
):
508 """Translate some tranform matrix from Blender UI
509 to POV syntax and return that string """
511 "matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n"
529 def writeObjectMaterial(material
, ob
):
530 """Translate some object level material from Blender UI (VS data level)
531 to POV interior{} syntax and write it to exported file """
533 # DH - modified some variables to be function local, avoiding RNA write
534 # this should be checked to see if it is functionally correct
536 # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
537 # if material and material.transparency_method == 'RAYTRACE':
539 # But there can be only one!
541 material
.pov_subsurface_scattering
.use
542 ): # SSS IOR get highest priority
543 tabWrite("interior {\n")
544 tabWrite("ior %.6f\n" % material
.pov_subsurface_scattering
.ior
)
545 # Then the raytrace IOR taken from raytrace transparency properties and used for
546 # reflections if IOR Mirror option is checked.
547 elif material
.pov
.mirror_use_IOR
:
548 tabWrite("interior {\n")
549 tabWrite("ior %.6f\n" % material
.pov_raytrace_transparency
.ior
)
550 elif material
.pov
.transparency_method
== 'Z_TRANSPARENCY':
551 tabWrite("interior {\n")
552 tabWrite("ior 1.0\n")
554 tabWrite("interior {\n")
555 tabWrite("ior %.6f\n" % material
.pov_raytrace_transparency
.ior
)
557 pov_fake_caustics
= False
558 pov_photons_refraction
= False
559 pov_photons_reflection
= False
561 if material
.pov
.photons_reflection
:
562 pov_photons_reflection
= True
563 if not material
.pov
.refraction_caustics
:
564 pov_fake_caustics
= False
565 pov_photons_refraction
= False
566 elif material
.pov
.refraction_type
== "1":
567 pov_fake_caustics
= True
568 pov_photons_refraction
= False
569 elif material
.pov
.refraction_type
== "2":
570 pov_fake_caustics
= False
571 pov_photons_refraction
= True
573 # If only Raytrace transparency is set, its IOR will be used for refraction, but user
574 # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
575 # Last, if none of the above is specified, user can set up 'un-physical' fresnel
576 # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
577 if material
.pov
.caustics_enable
:
578 if pov_fake_caustics
:
580 "caustics %.3g\n" % material
.pov
.fake_caustics_power
582 if pov_photons_refraction
:
583 # Default of 1 means no dispersion
585 "dispersion %.6f\n" % material
.pov
.photons_dispersion
588 "dispersion_samples %.d\n"
589 % material
.pov
.photons_dispersion_samples
592 # Other interior args
594 material
.pov
.use_transparency
595 and material
.pov
.transparency_method
== 'RAYTRACE'
598 # In Blender this value has always been reversed compared to what tooltip says.
599 # 100.001 rather than 100 so that it does not get to 0
600 # which deactivates the feature in POV
602 "fade_distance %.3g\n"
603 % (100.001 - material
.pov_raytrace_transparency
.depth_max
)
608 % material
.pov_raytrace_transparency
.falloff
612 "fade_color <%.3g, %.3g, %.3g>\n"
613 % material
.pov
.interior_fade_color
[:]
616 # (variable) dispersion_samples (constant count for now)
619 material
.pov
.photons_reflection
620 or material
.pov
.refraction_type
== "2"
623 tabWrite("target %.3g\n" % ob
.pov
.spacing_multiplier
)
624 if not ob
.pov
.collect_photons
:
625 tabWrite("collect off\n")
626 if pov_photons_refraction
:
627 tabWrite("refraction on\n")
628 if pov_photons_reflection
:
629 tabWrite("reflection on\n")
633 DEF_MAT_NAME
= "" # or "Default"?
636 """Translate camera from Blender UI to POV syntax and write to exported file."""
637 camera
= scene
.camera
639 # DH disabled for now, this isn't the correct context
642 ) # bpy.context.active_object # does not always work MR
643 matrix
= global_matrix
@ camera
.matrix_world
644 focal_point
= camera
.data
.dof
.focus_distance
647 Qsize
= render
.resolution_x
/ render
.resolution_y
649 "#declare camLocation = <%.6f, %.6f, %.6f>;\n"
650 % matrix
.translation
[:]
653 "#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
654 % tuple([degrees(e
) for e
in matrix
.to_3x3().to_euler()])
657 tabWrite("camera {\n")
659 scene
.pov
.baking_enable
661 and active_object
.type == 'MESH'
665 ) # distribution 3 is what we want here
666 tabWrite("mesh{%s}\n" % active_object
.name
)
668 tabWrite("location <0,0,.01>")
669 tabWrite("direction <0,0,-1>")
672 if camera
.data
.type == 'ORTHO':
673 SensorHeightRatio
= render
.resolution_x
* camera
.data
.ortho_scale
/ render
.resolution_y
674 tabWrite("orthographic\n")
675 # Blender angle is radian so should be converted to degrees:
676 # % (camera.data.angle * (180.0 / pi) )
677 # but actually argument is not compulsory after angle in pov ortho mode
679 tabWrite("right <%6f, 0, 0>\n" % -camera
.data
.ortho_scale
)
680 tabWrite("location <0, 0, 0>\n")
681 tabWrite("look_at <0, 0, -1>\n")
682 tabWrite("up <0, %6f, 0>\n" % (camera
.data
.ortho_scale
/ Qsize
))
684 elif camera
.data
.type == 'PANO':
685 tabWrite("panoramic\n")
686 tabWrite("location <0, 0, 0>\n")
687 tabWrite("look_at <0, 0, -1>\n")
688 tabWrite("right <%s, 0, 0>\n" % -Qsize
)
689 tabWrite("up <0, 1, 0>\n")
691 "angle %f\n" % (360.0 * atan(16.0 / camera
.data
.lens
) / pi
)
693 elif camera
.data
.type == 'PERSP':
694 # Standard camera otherwise would be default in pov
695 tabWrite("location <0, 0, 0>\n")
696 tabWrite("look_at <0, 0, -1>\n")
697 tabWrite("right <%s, 0, 0>\n" % -Qsize
)
698 tabWrite("up <0, 1, 0>\n")
700 "angle %f\n" % ( 2 * atan(camera
.data
.sensor_width
/ 2 / camera
.data
.lens
) * 180.0 / pi
)
704 "rotate <%.6f, %.6f, %.6f>\n"
705 % tuple([degrees(e
) for e
in matrix
.to_3x3().to_euler()])
707 tabWrite("translate <%.6f, %.6f, %.6f>\n" % matrix
.translation
[:])
708 if camera
.data
.dof
.use_dof
and (
709 focal_point
!= 0 or camera
.data
.dof
.focus_object
713 % (1 / camera
.data
.dof
.aperture_fstop
* 1000)
716 "blur_samples %d %d\n"
718 camera
.data
.pov
.dof_samples_min
,
719 camera
.data
.pov
.dof_samples_max
,
722 tabWrite("variance 1/%d\n" % camera
.data
.pov
.dof_variance
)
723 tabWrite("confidence %.3g\n" % camera
.data
.pov
.dof_confidence
)
724 if camera
.data
.dof
.focus_object
:
725 focalOb
= scene
.objects
[camera
.data
.dof
.focus_object
.name
]
726 matrixBlur
= global_matrix
@ focalOb
.matrix_world
728 "focal_point <%.4f,%.4f,%.4f>\n"
729 % matrixBlur
.translation
[:]
732 tabWrite("focal_point <0, 0, %f>\n" % focal_point
)
733 if camera
.data
.pov
.normal_enable
:
735 "normal {%s %.4f turbulence %.4f scale %.4f}\n"
737 camera
.data
.pov
.normal_patterns
,
738 camera
.data
.pov
.cam_normal
,
739 camera
.data
.pov
.turbulence
,
740 camera
.data
.pov
.scale
,
745 def exportLamps(lamps
):
746 """Translate lights from Blender UI to POV syntax and write to exported file."""
748 # Incremented after each lamp export to declare its target
749 # currently used for Fresnel diffuse shader as their slope vector:
756 matrix
= global_matrix
@ ob
.matrix_world
758 # Color is no longer modified by energy
759 color
= tuple([c
for c
in lamp
.color
])
761 tabWrite("light_source {\n")
762 tabWrite("< 0,0,0 >\n")
763 tabWrite("color srgb<%.3g, %.3g, %.3g>\n" % color
)
765 if lamp
.type == 'POINT':
767 elif lamp
.type == 'SPOT':
768 tabWrite("spotlight\n")
770 # Falloff is the main radius from the centre line
772 "falloff %.2f\n" % (degrees(lamp
.spot_size
) / 2.0)
773 ) # 1 TO 179 FOR BOTH
777 (degrees(lamp
.spot_size
) / 2.0)
778 * (1.0 - lamp
.spot_blend
)
782 # Blender does not have a tightness equivalent, 0 is most like blender default.
783 tabWrite("tightness 0\n") # 0:10f
785 tabWrite("point_at <0, 0, -1>\n")
786 if lamp
.pov
.use_halo
:
787 tabWrite("looks_like{\n")
788 tabWrite("sphere{<0,0,0>,%.6f\n" % lamp
.distance
)
790 tabWrite("material{\n")
791 tabWrite("texture{\n")
793 "pigment{rgbf<1,1,1,%.4f>}\n"
794 % (lamp
.pov
.halo_intensity
* 5.0)
797 tabWrite("interior{\n")
799 tabWrite("emission 1\n")
800 tabWrite("scattering {1, 0.5}\n")
801 tabWrite("density{\n")
802 tabWrite("spherical\n")
803 tabWrite("color_map{\n")
804 tabWrite("[0.0 rgb <0,0,0>]\n")
805 tabWrite("[0.5 rgb <1,1,1>]\n")
806 tabWrite("[1.0 rgb <1,1,1>]\n")
814 elif lamp
.type == 'SUN':
815 tabWrite("parallel\n")
816 tabWrite("point_at <0, 0, -1>\n") # *must* be after 'parallel'
818 elif lamp
.type == 'AREA':
819 tabWrite("fade_distance %.6f\n" % (lamp
.distance
/ 2.0))
820 # Area lights have no falloff type, so always use blenders lamp quad equivalent
822 tabWrite("fade_power %d\n" % 2)
824 samples_x
= lamp
.pov
.shadow_ray_samples_x
825 if lamp
.shape
== 'SQUARE':
827 samples_y
= samples_x
830 samples_y
= lamp
.pov
.shadow_ray_samples_y
833 "area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n"
834 % (size_x
, size_y
, samples_x
, samples_y
)
836 tabWrite("area_illumination\n")
837 if lamp
.pov
.shadow_ray_sample_method
== 'CONSTANT_JITTERED':
838 if lamp
.pov
.use_jitter
:
841 tabWrite("adaptive 1\n")
844 # No shadow checked either at global or light level:
845 if not scene
.pov
.use_shadows
or (
846 lamp
.pov
.shadow_method
== 'NOSHADOW'
848 tabWrite("shadowless\n")
850 # Sun shouldn't be attenuated. Area lights have no falloff attribute so they
851 # are put to type 2 attenuation a little higher above.
852 if lamp
.type not in {'SUN', 'AREA'}:
853 if lamp
.falloff_type
== 'INVERSE_SQUARE':
855 "fade_distance %.6f\n" % (sqrt(lamp
.distance
/ 2.0))
858 "fade_power %d\n" % 2
859 ) # Use blenders lamp quad equivalent
860 elif lamp
.falloff_type
== 'INVERSE_LINEAR':
861 tabWrite("fade_distance %.6f\n" % (lamp
.distance
/ 2.0))
862 tabWrite("fade_power %d\n" % 1) # Use blenders lamp linear
863 elif lamp
.falloff_type
== 'CONSTANT':
864 tabWrite("fade_distance %.6f\n" % (lamp
.distance
/ 2.0))
865 tabWrite("fade_power %d\n" % 3)
866 # Use blenders lamp constant equivalent no attenuation.
867 # Using Custom curve for fade power 3 for now.
868 elif lamp
.falloff_type
== 'CUSTOM_CURVE':
869 tabWrite("fade_power %d\n" % 4)
877 # v(A,B) rotates vector A about origin by vector B.
879 "#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
891 ####################################################################################################
892 def exportRainbows(rainbows
):
893 """write all POV rainbows primitives to exported file """
895 povdataname
= ob
.data
.name
# enough?
896 angle
= degrees(ob
.data
.spot_size
/ 2.5) # radians in blender (2
897 width
= ob
.data
.spot_blend
* 10
898 distance
= ob
.data
.shadow_buffer_clip_start
900 # angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
901 # width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
903 # cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
905 # v(A,B) rotates vector A about origin by vector B.
906 # and avoid a 0 length vector by adding 1
908 # file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
909 # (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
910 # ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
916 ) # not taking matrix into account
917 rmatrix
= global_matrix
@ ob
.matrix_world
919 # ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
920 # XXX Is result of the below offset by 90 degrees?
921 up
= ob
.matrix_world
.to_3x3()[1].xyz
# * global_matrix
925 # tabWrite("#declare %s = rainbow {\n"%povdataname)
927 # clumsy for now but remove the rainbow from instancing
928 # system because not an object. use lamps later instead of meshes
930 # del data_ref[dataname]
931 tabWrite("rainbow {\n")
933 tabWrite("angle %.4f\n" % angle
)
934 tabWrite("width %.4f\n" % width
)
935 tabWrite("distance %.4f\n" % distance
)
936 tabWrite("arc_angle %.4f\n" % ob
.pov
.arc_angle
)
937 tabWrite("falloff_angle %.4f\n" % ob
.pov
.falloff_angle
)
938 tabWrite("direction <%.4f,%.4f,%.4f>\n" % rmatrix
.translation
[:])
939 tabWrite("up <%.4f,%.4f,%.4f>\n" % (up
[0], up
[1], up
[2]))
940 tabWrite("color_map {\n")
941 tabWrite("[0.000 color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
942 tabWrite("[0.130 color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
943 tabWrite("[0.298 color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
944 tabWrite("[0.412 color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
945 tabWrite("[0.526 color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
946 tabWrite("[0.640 color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
947 tabWrite("[0.754 color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
948 tabWrite("[0.900 color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
949 tabWrite("[1.000 color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
952 povMatName
= "Default_texture"
953 # tabWrite("texture {%s}\n"%povMatName)
954 write_object_modifiers(scene
, ob
, file)
955 # tabWrite("rotate x*90\n")
956 # matrix = global_matrix @ ob.matrix_world
957 # writeMatrix(matrix)
959 # continue #Don't render proxy mesh, skip to next object
961 ################################XXX LOFT, ETC.
962 def exportCurves(scene
, ob
):
963 """write all curves based POV primitives to exported file """
964 name_orig
= "OB" + ob
.name
965 dataname_orig
= "DATA" + ob
.data
.name
967 name
= string_strip_hyphen(bpy
.path
.clean_name(name_orig
))
968 dataname
= string_strip_hyphen(bpy
.path
.clean_name(dataname_orig
))
970 global_matrix
= mathutils
.Matrix
.Rotation(-pi
/ 2.0, 4, 'X')
971 matrix
= global_matrix
@ ob
.matrix_world
973 if ob
.pov
.curveshape
== 'sphere_sweep':
974 # inlined spheresweep macro, which itself calls Shapes.inc:
975 file.write(' #include "shapes.inc"\n')
978 ' #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
980 file.write(' //input adjusting and inspection\n')
981 file.write(' #if(_resolution <= 1)\n')
982 file.write(' #local res = 1;\n')
983 file.write(' #else\n')
984 file.write(' #local res = int(_resolution);\n')
985 file.write(' #end\n')
987 ' #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n'
989 file.write(' #error ""\n')
991 ' #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
993 file.write(' #error ""\n')
995 ' #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
997 file.write(' #error ""\n')
998 file.write(' #else\n')
1000 ' #local n_of_seg = div(dimension_size(_points_array,1), 4);\n'
1002 file.write(' #local ctrl_pts_array = array[n_of_seg]\n')
1003 file.write(' #local ctrl_rs_array = array[n_of_seg]\n')
1004 file.write(' #for(i, 0, n_of_seg-1)\n')
1006 ' #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'
1009 ' #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'
1011 file.write(' #end\n')
1012 file.write(' #end\n')
1014 file.write(' //drawing\n')
1015 file.write(' #local mockup1 =\n')
1016 file.write(' #if(_merge_shape) merge{ #else union{ #end\n')
1017 file.write(' #for(i, 0, n_of_seg-1)\n')
1018 file.write(' #local has_head = true;\n')
1019 file.write(' #if(i = 0)\n')
1021 ' #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'
1023 file.write(' #local has_head = false;\n')
1024 file.write(' #end\n')
1025 file.write(' #else\n')
1027 ' #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'
1029 file.write(' #local has_head = false;\n')
1030 file.write(' #end\n')
1031 file.write(' #end\n')
1032 file.write(' #if(has_head = true)\n')
1033 file.write(' sphere{\n')
1035 ' ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n'
1038 file.write(' #end\n')
1039 file.write(' #local para_t = (1/2)/res;\n')
1041 ' #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'
1044 ' #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'
1047 ' #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n'
1049 file.write(' object{\n')
1051 ' Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n'
1054 file.write(' #end\n')
1055 file.write(' sphere{\n')
1056 file.write(' this_point, this_radius\n')
1058 file.write(' #for(j, 1, res-1)\n')
1059 file.write(' #local last_point = this_point;\n')
1061 ' #local last_radius = this_radius;\n'
1063 file.write(' #local para_t = (1/2+j)/res;\n')
1065 ' #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'
1068 ' #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'
1071 ' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
1073 file.write(' object{\n')
1075 ' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
1078 file.write(' #end\n')
1079 file.write(' sphere{\n')
1080 file.write(' this_point, this_radius\n')
1082 file.write(' #end\n')
1083 file.write(' #local last_point = this_point;\n')
1084 file.write(' #local last_radius = this_radius;\n')
1086 ' #local this_point = ctrl_pts_array[i][3];\n'
1089 ' #local this_radius = ctrl_rs_array[i][3];\n'
1092 ' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
1094 file.write(' object{\n')
1096 ' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
1099 file.write(' #end\n')
1100 file.write(' sphere{\n')
1101 file.write(' this_point, this_radius\n')
1103 file.write(' #end\n')
1105 file.write(' mockup1\n')
1106 file.write(' #end\n')
1108 for spl
in ob
.data
.splines
:
1109 if spl
.type == "BEZIER":
1111 if ob
.pov
.curveshape
in {'loft', 'birail'}:
1113 for spline
in ob
.data
.splines
:
1115 tabWrite('#declare %s%s=spline {\n' % (dataname
, n
))
1116 tabWrite('cubic_spline\n')
1117 lp
= len(spline
.points
)
1120 point
= spline
.points
[lp
- 1]
1121 x
, y
, z
, w
= point
.co
[:]
1122 tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d
, x
, y
, z
))
1124 for point
in spline
.points
:
1125 x
, y
, z
, w
= point
.co
[:]
1126 tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d
, x
, y
, z
))
1129 point
= spline
.points
[i
]
1130 x
, y
, z
, w
= point
.co
[:]
1131 tabWrite('%.6f, <%.6f,%.6f,%.6f>\n' % (d
, x
, y
, z
))
1134 if ob
.pov
.curveshape
in {'loft'}:
1135 n
= len(ob
.data
.splines
)
1136 tabWrite('#declare %s = array[%s]{\n' % (dataname
, (n
+ 3)))
1137 tabWrite('spline{%s%s},\n' % (dataname
, n
))
1139 tabWrite('spline{%s%s},\n' % (dataname
, (i
+ 1)))
1140 tabWrite('spline{%s1},\n' % (dataname
))
1141 tabWrite('spline{%s2}\n' % (dataname
))
1143 # Use some of the Meshmaker.inc macro, here inlined
1144 file.write('#macro CheckFileName(FileName)\n')
1145 file.write(' #local Len=strlen(FileName);\n')
1146 file.write(' #if(Len>0)\n')
1147 file.write(' #if(file_exists(FileName))\n')
1148 file.write(' #if(Len>=4)\n')
1150 ' #local Ext=strlwr(substr(FileName,Len-3,4))\n'
1153 ' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
1155 file.write(' #local Return=99;\n')
1156 file.write(' #else\n')
1157 file.write(' #local Return=0;\n')
1158 file.write(' #end\n')
1159 file.write(' #else\n')
1160 file.write(' #local Return=0;\n')
1161 file.write(' #end\n')
1162 file.write(' #else\n')
1163 file.write(' #if(Len>=4)\n')
1165 ' #local Ext=strlwr(substr(FileName,Len-3,4))\n'
1168 ' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
1170 file.write(' #if (strcmp(Ext,".obj")=0)\n')
1171 file.write(' #local Return=2;\n')
1172 file.write(' #end\n')
1173 file.write(' #if (strcmp(Ext,".pcm")=0)\n')
1174 file.write(' #local Return=3;\n')
1175 file.write(' #end\n')
1176 file.write(' #if (strcmp(Ext,".arr")=0)\n')
1177 file.write(' #local Return=4;\n')
1178 file.write(' #end\n')
1179 file.write(' #else\n')
1180 file.write(' #local Return=1;\n')
1181 file.write(' #end\n')
1182 file.write(' #else\n')
1183 file.write(' #local Return=1;\n')
1184 file.write(' #end\n')
1185 file.write(' #end\n')
1186 file.write(' #else\n')
1187 file.write(' #local Return=1;\n')
1188 file.write(' #end\n')
1189 file.write(' (Return)\n')
1190 file.write('#end\n')
1192 file.write('#macro BuildSpline(Arr, SplType)\n')
1193 file.write(' #local Ds=dimension_size(Arr,1);\n')
1194 file.write(' #local Asc=asc(strupr(SplType));\n')
1195 file.write(' #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
1196 file.write(' #local Asc=76;\n')
1198 ' #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n'
1200 file.write(' #end\n')
1201 file.write(' spline {\n')
1202 file.write(' #switch (Asc)\n')
1203 file.write(' #case (67) //C cubic_spline\n')
1204 file.write(' cubic_spline\n')
1205 file.write(' #break\n')
1206 file.write(' #case (76) //L linear_spline\n')
1207 file.write(' linear_spline\n')
1208 file.write(' #break\n')
1209 file.write(' #case (78) //N linear_spline\n')
1210 file.write(' natural_spline\n')
1211 file.write(' #break\n')
1212 file.write(' #case (81) //Q Quadratic_spline\n')
1213 file.write(' quadratic_spline\n')
1214 file.write(' #break\n')
1215 file.write(' #end\n')
1216 file.write(' #local Add=1/((Ds-2)-1);\n')
1217 file.write(' #local J=0-Add;\n')
1218 file.write(' #local I=0;\n')
1219 file.write(' #while (I<Ds)\n')
1221 file.write(' Arr[I]\n')
1222 file.write(' #local I=I+1;\n')
1223 file.write(' #local J=J+Add;\n')
1224 file.write(' #end\n')
1226 file.write('#end\n')
1229 '#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n'
1231 # suppressed some file checking from original macro because no more separate files
1232 file.write(' #local Write=0;\n')
1234 ' #debug concat("\\n\\n Building mesh2: \\n - vertex_vectors\\n")\n'
1236 file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
1237 file.write(' #switch (Write)\n')
1238 file.write(' #case(1)\n')
1239 file.write(' #write(\n')
1240 file.write(' MeshFile,\n')
1241 file.write(' " vertex_vectors {\\n",\n')
1242 file.write(' " ", str(NumVertices,0,0),"\\n "\n')
1244 file.write(' #break\n')
1245 file.write(' #case(2)\n')
1246 file.write(' #write(\n')
1247 file.write(' MeshFile,\n')
1248 file.write(' "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
1250 file.write(' #break\n')
1251 file.write(' #case(3)\n')
1252 file.write(' #write(\n')
1253 file.write(' MeshFile,\n')
1254 file.write(' str(2*NumVertices,0,0),",\\n"\n')
1256 file.write(' #break\n')
1257 file.write(' #case(4)\n')
1258 file.write(' #write(\n')
1259 file.write(' MeshFile,\n')
1261 ' "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
1264 file.write(' #break\n')
1265 file.write(' #end\n')
1266 file.write(' mesh2 {\n')
1267 file.write(' vertex_vectors {\n')
1268 file.write(' NumVertices\n')
1269 file.write(' #local I=0;\n')
1270 file.write(' #while (I<NumVertices)\n')
1271 file.write(' VecArr[I]\n')
1272 file.write(' #switch(Write)\n')
1273 file.write(' #case(1)\n')
1274 file.write(' #write(MeshFile, VecArr[I])\n')
1275 file.write(' #break\n')
1276 file.write(' #case(2)\n')
1277 file.write(' #write(\n')
1278 file.write(' MeshFile,\n')
1280 ' "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n'
1283 file.write(' #break\n')
1284 file.write(' #case(3)\n')
1285 file.write(' #write(\n')
1286 file.write(' MeshFile,\n')
1288 ' VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n'
1291 file.write(' #break\n')
1292 file.write(' #case(4)\n')
1293 file.write(' #write(MeshFile, VecArr[I])\n')
1294 file.write(' #break\n')
1295 file.write(' #end\n')
1296 file.write(' #local I=I+1;\n')
1297 file.write(' #if(Write=1 | Write=4)\n')
1298 file.write(' #if(mod(I,3)=0)\n')
1299 file.write(' #write(MeshFile,"\\n ")\n')
1300 file.write(' #end\n')
1301 file.write(' #end \n')
1302 file.write(' #end\n')
1303 file.write(' #switch(Write)\n')
1304 file.write(' #case(1)\n')
1305 file.write(' #write(MeshFile,"\\n }\\n")\n')
1306 file.write(' #break\n')
1307 file.write(' #case(2)\n')
1308 file.write(' #write(MeshFile,"\\n")\n')
1309 file.write(' #break\n')
1310 file.write(' #case(3)\n')
1311 file.write(' // do nothing\n')
1312 file.write(' #break\n')
1313 file.write(' #case(4) \n')
1314 file.write(' #write(MeshFile,"\\n}\\n")\n')
1315 file.write(' #break\n')
1316 file.write(' #end\n')
1319 file.write(' #debug concat(" - normal_vectors\\n") \n')
1320 file.write(' #local NumVertices=dimension_size(NormArr,1);\n')
1321 file.write(' #switch(Write)\n')
1322 file.write(' #case(1)\n')
1323 file.write(' #write(\n')
1324 file.write(' MeshFile,\n')
1325 file.write(' " normal_vectors {\\n",\n')
1326 file.write(' " ", str(NumVertices,0,0),"\\n "\n')
1328 file.write(' #break\n')
1329 file.write(' #case(2)\n')
1330 file.write(' #write(\n')
1331 file.write(' MeshFile,\n')
1333 ' "# Normals: ",str(NumVertices,0,0),"\\n"\n'
1336 file.write(' #break\n')
1337 file.write(' #case(3)\n')
1338 file.write(' // do nothing\n')
1339 file.write(' #break\n')
1340 file.write(' #case(4)\n')
1341 file.write(' #write(\n')
1342 file.write(' MeshFile,\n')
1344 ' "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
1347 file.write(' #break\n')
1348 file.write(' #end\n')
1349 file.write(' normal_vectors {\n')
1350 file.write(' NumVertices\n')
1351 file.write(' #local I=0;\n')
1352 file.write(' #while (I<NumVertices)\n')
1353 file.write(' NormArr[I]\n')
1354 file.write(' #switch(Write)\n')
1355 file.write(' #case(1)\n')
1356 file.write(' #write(MeshFile NormArr[I])\n')
1357 file.write(' #break\n')
1358 file.write(' #case(2)\n')
1359 file.write(' #write(\n')
1360 file.write(' MeshFile,\n')
1362 ' "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n'
1365 file.write(' #break\n')
1366 file.write(' #case(3)\n')
1367 file.write(' #write(\n')
1368 file.write(' MeshFile,\n')
1370 ' NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n'
1373 file.write(' #break\n')
1374 file.write(' #case(4)\n')
1375 file.write(' #write(MeshFile NormArr[I])\n')
1376 file.write(' #break\n')
1377 file.write(' #end\n')
1378 file.write(' #local I=I+1;\n')
1379 file.write(' #if(Write=1 | Write=4) \n')
1380 file.write(' #if(mod(I,3)=0)\n')
1381 file.write(' #write(MeshFile,"\\n ")\n')
1382 file.write(' #end\n')
1383 file.write(' #end\n')
1384 file.write(' #end\n')
1385 file.write(' #switch(Write)\n')
1386 file.write(' #case(1)\n')
1387 file.write(' #write(MeshFile,"\\n }\\n")\n')
1388 file.write(' #break\n')
1389 file.write(' #case(2)\n')
1390 file.write(' #write(MeshFile,"\\n")\n')
1391 file.write(' #break\n')
1392 file.write(' #case(3)\n')
1393 file.write(' //do nothing\n')
1394 file.write(' #break\n')
1395 file.write(' #case(4)\n')
1396 file.write(' #write(MeshFile,"\\n}\\n")\n')
1397 file.write(' #break\n')
1398 file.write(' #end\n')
1401 file.write(' #debug concat(" - uv_vectors\\n") \n')
1402 file.write(' #local NumVertices=dimension_size(UVArr,1);\n')
1403 file.write(' #switch(Write)\n')
1404 file.write(' #case(1)\n')
1405 file.write(' #write(\n')
1406 file.write(' MeshFile, \n')
1407 file.write(' " uv_vectors {\\n",\n')
1408 file.write(' " ", str(NumVertices,0,0),"\\n "\n')
1410 file.write(' #break\n')
1411 file.write(' #case(2)\n')
1412 file.write(' #write(\n')
1413 file.write(' MeshFile,\n')
1415 ' "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n'
1418 file.write(' #break\n')
1419 file.write(' #case(3)\n')
1421 ' // do nothing, *.pcm does not support uv-vectors\n'
1423 file.write(' #break\n')
1424 file.write(' #case(4)\n')
1425 file.write(' #write(\n')
1426 file.write(' MeshFile,\n')
1428 ' "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
1431 file.write(' #break\n')
1432 file.write(' #end\n')
1433 file.write(' uv_vectors {\n')
1434 file.write(' NumVertices\n')
1435 file.write(' #local I=0;\n')
1436 file.write(' #while (I<NumVertices)\n')
1437 file.write(' UVArr[I]\n')
1438 file.write(' #switch(Write)\n')
1439 file.write(' #case(1)\n')
1440 file.write(' #write(MeshFile UVArr[I])\n')
1441 file.write(' #break\n')
1442 file.write(' #case(2)\n')
1443 file.write(' #write(\n')
1444 file.write(' MeshFile,\n')
1446 ' "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n'
1449 file.write(' #break\n')
1450 file.write(' #case(3)\n')
1451 file.write(' //do nothing\n')
1452 file.write(' #break\n')
1453 file.write(' #case(4)\n')
1454 file.write(' #write(MeshFile UVArr[I])\n')
1455 file.write(' #break\n')
1456 file.write(' #end\n')
1457 file.write(' #local I=I+1; \n')
1458 file.write(' #if(Write=1 | Write=4)\n')
1459 file.write(' #if(mod(I,3)=0)\n')
1460 file.write(' #write(MeshFile,"\\n ")\n')
1461 file.write(' #end \n')
1462 file.write(' #end\n')
1463 file.write(' #end \n')
1464 file.write(' #switch(Write)\n')
1465 file.write(' #case(1)\n')
1466 file.write(' #write(MeshFile,"\\n }\\n")\n')
1467 file.write(' #break\n')
1468 file.write(' #case(2)\n')
1469 file.write(' #write(MeshFile,"\\n")\n')
1470 file.write(' #break\n')
1471 file.write(' #case(3)\n')
1472 file.write(' //do nothing\n')
1473 file.write(' #break\n')
1474 file.write(' #case(4)\n')
1475 file.write(' #write(MeshFile,"\\n}\\n")\n')
1476 file.write(' #break\n')
1477 file.write(' #end\n')
1480 file.write(' #debug concat(" - face_indices\\n") \n')
1481 file.write(' #declare NumFaces=U*V*2;\n')
1482 file.write(' #switch(Write)\n')
1483 file.write(' #case(1)\n')
1484 file.write(' #write(\n')
1485 file.write(' MeshFile,\n')
1486 file.write(' " face_indices {\\n"\n')
1487 file.write(' " ", str(NumFaces,0,0),"\\n "\n')
1489 file.write(' #break\n')
1490 file.write(' #case(2)\n')
1491 file.write(' #write (\n')
1492 file.write(' MeshFile,\n')
1493 file.write(' "# faces: ",str(NumFaces,0,0),"\\n"\n')
1495 file.write(' #break\n')
1496 file.write(' #case(3)\n')
1497 file.write(' #write (\n')
1498 file.write(' MeshFile,\n')
1499 file.write(' "0,",str(NumFaces,0,0),",\\n"\n')
1501 file.write(' #break\n')
1502 file.write(' #case(4)\n')
1503 file.write(' #write(\n')
1504 file.write(' MeshFile,\n')
1506 ' "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n "\n'
1509 file.write(' #break\n')
1510 file.write(' #end\n')
1511 file.write(' face_indices {\n')
1512 file.write(' NumFaces\n')
1513 file.write(' #local I=0;\n')
1514 file.write(' #local H=0;\n')
1515 file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
1516 file.write(' #while (I<V)\n')
1517 file.write(' #local J=0;\n')
1518 file.write(' #while (J<U)\n')
1519 file.write(' #local Ind=(I*U)+I+J;\n')
1521 ' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
1523 file.write(' #switch(Write)\n')
1524 file.write(' #case(1)\n')
1525 file.write(' #write(\n')
1526 file.write(' MeshFile,\n')
1528 ' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
1531 file.write(' #break\n')
1532 file.write(' #case(2)\n')
1533 file.write(' #write(\n')
1534 file.write(' MeshFile,\n')
1536 ' "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'
1539 ' "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'
1542 file.write(' #break\n')
1543 file.write(' #case(3)\n')
1544 file.write(' #write(\n')
1545 file.write(' MeshFile,\n')
1547 ' Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
1550 ' Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
1553 file.write(' #break\n')
1554 file.write(' #case(4)\n')
1555 file.write(' #write(\n')
1556 file.write(' MeshFile,\n')
1558 ' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n'
1561 file.write(' #break\n')
1562 file.write(' #end\n')
1563 file.write(' #local J=J+1;\n')
1564 file.write(' #local H=H+1;\n')
1565 file.write(' #if(Write=1 | Write=4)\n')
1566 file.write(' #if(mod(H,3)=0)\n')
1567 file.write(' #write(MeshFile,"\\n ")\n')
1568 file.write(' #end \n')
1569 file.write(' #end\n')
1570 file.write(' #end\n')
1571 file.write(' #local I=I+1;\n')
1572 file.write(' #end\n')
1574 file.write(' #switch(Write)\n')
1575 file.write(' #case(1)\n')
1576 file.write(' #write(MeshFile, "\\n }\\n}")\n')
1577 file.write(' #fclose MeshFile\n')
1578 file.write(' #debug concat(" Done writing\\n")\n')
1579 file.write(' #break\n')
1580 file.write(' #case(2)\n')
1581 file.write(' #fclose MeshFile\n')
1582 file.write(' #debug concat(" Done writing\\n")\n')
1583 file.write(' #break\n')
1584 file.write(' #case(3)\n')
1585 file.write(' #fclose MeshFile\n')
1586 file.write(' #debug concat(" Done writing\\n")\n')
1587 file.write(' #break\n')
1588 file.write(' #case(4)\n')
1589 file.write(' #write(MeshFile, "\\n}\\n}")\n')
1590 file.write(' #fclose MeshFile\n')
1591 file.write(' #debug concat(" Done writing\\n")\n')
1592 file.write(' #break\n')
1593 file.write(' #end\n')
1595 file.write('#end\n')
1598 '#macro MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)\n'
1600 file.write(' #declare Build=CheckFileName(FileName);\n')
1601 file.write(' #if(Build=0)\n')
1603 ' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n'
1605 file.write(' #include FileName\n')
1606 file.write(' object{Surface}\n')
1607 file.write(' #else\n')
1608 file.write(' #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
1609 file.write(' #local NumFaces=SplRes*InterpRes*2;\n')
1611 ' #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n'
1613 file.write(' #local VecArr=array[NumVertices]\n')
1614 file.write(' #local NormArr=array[NumVertices]\n')
1615 file.write(' #local UVArr=array[NumVertices]\n')
1616 file.write(' #local N=dimension_size(SplineArray,1);\n')
1617 file.write(' #local TempSplArr0=array[N];\n')
1618 file.write(' #local TempSplArr1=array[N];\n')
1619 file.write(' #local TempSplArr2=array[N];\n')
1620 file.write(' #local PosStep=1/SplRes;\n')
1621 file.write(' #local InterpStep=1/InterpRes;\n')
1622 file.write(' #local Count=0;\n')
1623 file.write(' #local Pos=0;\n')
1624 file.write(' #while(Pos<=1)\n')
1625 file.write(' #local I=0;\n')
1626 file.write(' #if (Pos=0)\n')
1627 file.write(' #while (I<N)\n')
1629 ' #local Spl=spline{SplineArray[I]}\n'
1632 ' #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n'
1635 ' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n'
1638 ' #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n'
1640 file.write(' #local I=I+1;\n')
1641 file.write(' #end\n')
1643 ' #local S0=BuildSpline(TempSplArr0, Interp_type)\n'
1646 ' #local S1=BuildSpline(TempSplArr1, Interp_type)\n'
1649 ' #local S2=BuildSpline(TempSplArr2, Interp_type)\n'
1651 file.write(' #else\n')
1652 file.write(' #while (I<N)\n')
1654 ' #local Spl=spline{SplineArray[I]}\n'
1657 ' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n'
1659 file.write(' #local I=I+1;\n')
1660 file.write(' #end\n')
1662 ' #local S1=BuildSpline(TempSplArr1, Interp_type)\n'
1664 file.write(' #end\n')
1665 file.write(' #local J=0;\n')
1666 file.write(' #while (J<=1)\n')
1667 file.write(' #local P0=<0,0,0>+S0(J);\n')
1668 file.write(' #local P1=<0,0,0>+S1(J);\n')
1669 file.write(' #local P2=<0,0,0>+S2(J);\n')
1670 file.write(' #local P3=<0,0,0>+S0(J+InterpStep);\n')
1671 file.write(' #local P4=<0,0,0>+S0(J-InterpStep);\n')
1672 file.write(' #local B1=P4-P0;\n')
1673 file.write(' #local B2=P2-P0;\n')
1674 file.write(' #local B3=P3-P0;\n')
1675 file.write(' #local B4=P1-P0;\n')
1676 file.write(' #local N1=vcross(B1,B2);\n')
1677 file.write(' #local N2=vcross(B2,B3);\n')
1678 file.write(' #local N3=vcross(B3,B4);\n')
1679 file.write(' #local N4=vcross(B4,B1);\n')
1681 ' #local Norm=vnormalize((N1+N2+N3+N4));\n'
1683 file.write(' #local VecArr[Count]=P0;\n')
1684 file.write(' #local NormArr[Count]=Norm;\n')
1685 file.write(' #local UVArr[Count]=<J,Pos>;\n')
1686 file.write(' #local J=J+InterpStep;\n')
1687 file.write(' #local Count=Count+1;\n')
1688 file.write(' #end\n')
1689 file.write(' #local S2=spline{S0}\n')
1690 file.write(' #local S0=spline{S1}\n')
1692 ' #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n'
1694 file.write(' #local Pos=Pos+PosStep;\n')
1695 file.write(' #end\n')
1697 ' BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n'
1699 file.write(' #end\n')
1700 file.write('#end\n\n')
1703 '#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n'
1705 file.write(' #declare Build=CheckFileName(FileName);\n')
1706 file.write(' #if(Build=0)\n')
1708 ' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n'
1710 file.write(' #include FileName\n')
1711 file.write(' object{Surface}\n')
1712 file.write(' #else\n')
1713 file.write(' #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
1714 file.write(' #local NumFaces=Iter_U*Iter_V*2;\n')
1716 ' #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n'
1718 file.write(' #declare VecArr=array[NumVertices] \n')
1719 file.write(' #declare NormArr=array[NumVertices] \n')
1720 file.write(' #local UVArr=array[NumVertices] \n')
1721 file.write(' #local Spl1_0=Spl1(0);\n')
1722 file.write(' #local Spl2_0=Spl2(0);\n')
1723 file.write(' #local Spl3_0=Spl3(0);\n')
1724 file.write(' #local Spl4_0=Spl4(0);\n')
1725 file.write(' #local UStep=1/Iter_U;\n')
1726 file.write(' #local VStep=1/Iter_V;\n')
1727 file.write(' #local Count=0;\n')
1728 file.write(' #local I=0;\n')
1729 file.write(' #while (I<=1)\n')
1730 file.write(' #local Im=1-I;\n')
1731 file.write(' #local J=0;\n')
1732 file.write(' #while (J<=1)\n')
1733 file.write(' #local Jm=1-J;\n')
1735 ' #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n'
1738 ' #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n'
1741 ' LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n'
1743 file.write(' #declare VecArr[Count]=P0;\n')
1744 file.write(' #local UVArr[Count]=<J,I>;\n')
1745 file.write(' #local J=J+UStep;\n')
1746 file.write(' #local Count=Count+1;\n')
1747 file.write(' #end\n')
1748 file.write(' #debug concat(\n')
1750 ' "\r Done ", str(Count,0,0)," vertices : ",\n'
1752 file.write(' str(100*Count/NumVertices,0,2)," %"\n')
1754 file.write(' #local I=I+VStep;\n')
1755 file.write(' #end\n')
1757 ' #debug "\r Normals "\n'
1759 file.write(' #local Count=0;\n')
1760 file.write(' #local I=0;\n')
1761 file.write(' #while (I<=Iter_V)\n')
1762 file.write(' #local J=0;\n')
1763 file.write(' #while (J<=Iter_U)\n')
1764 file.write(' #local Ind=(I*Iter_U)+I+J;\n')
1765 file.write(' #local P0=VecArr[Ind];\n')
1766 file.write(' #if(J=0)\n')
1767 file.write(' #local P1=P0+(P0-VecArr[Ind+1]);\n')
1768 file.write(' #else\n')
1769 file.write(' #local P1=VecArr[Ind-1];\n')
1770 file.write(' #end\n')
1771 file.write(' #if (J=Iter_U)\n')
1772 file.write(' #local P2=P0+(P0-VecArr[Ind-1]);\n')
1773 file.write(' #else\n')
1774 file.write(' #local P2=VecArr[Ind+1];\n')
1775 file.write(' #end\n')
1776 file.write(' #if (I=0)\n')
1778 ' #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n'
1780 file.write(' #else\n')
1781 file.write(' #local P3=VecArr[Ind-Iter_U-1];\n')
1782 file.write(' #end\n')
1783 file.write(' #if (I=Iter_V)\n')
1785 ' #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n'
1787 file.write(' #else\n')
1788 file.write(' #local P4=VecArr[Ind+Iter_U+1];\n')
1789 file.write(' #end\n')
1790 file.write(' #local B1=P4-P0;\n')
1791 file.write(' #local B2=P2-P0;\n')
1792 file.write(' #local B3=P3-P0;\n')
1793 file.write(' #local B4=P1-P0;\n')
1794 file.write(' #local N1=vcross(B1,B2);\n')
1795 file.write(' #local N2=vcross(B2,B3);\n')
1796 file.write(' #local N3=vcross(B3,B4);\n')
1797 file.write(' #local N4=vcross(B4,B1);\n')
1798 file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
1799 file.write(' #declare NormArr[Count]=Norm;\n')
1800 file.write(' #local J=J+1;\n')
1801 file.write(' #local Count=Count+1;\n')
1802 file.write(' #end\n')
1804 ' #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n'
1806 file.write(' #local I=I+1;\n')
1807 file.write(' #end\n')
1809 ' BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n'
1811 file.write(' #end\n')
1812 file.write('#end\n\n')
1814 if len(ob
.data
.splines
) == 0:
1815 tabWrite("\n//dummy sphere to represent empty curve location\n")
1816 tabWrite("#declare %s =\n" % dataname
)
1818 "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
1819 % (ob
.location
.x
, ob
.location
.y
, ob
.location
.z
)
1820 ) # ob.name > povdataname)
1821 # And non empty curves
1823 if bezier_sweep
== False:
1824 tabWrite("#declare %s =\n" % dataname
)
1825 if ob
.pov
.curveshape
== 'sphere_sweep' and bezier_sweep
== False:
1826 tabWrite("union {\n")
1827 for spl
in ob
.data
.splines
:
1828 if spl
.type != "BEZIER":
1830 if spl
.type == "NURBS":
1833 numPoints
= len(points
)
1834 if spl
.use_cyclic_u
:
1838 "sphere_sweep { %s_spline %s,\n"
1839 % (spl_type
, numPoints
)
1841 if spl
.use_cyclic_u
:
1842 pt1
= points
[len(points
) - 1]
1845 "<%.4g,%.4g,%.4g>,%.4g\n"
1850 pt1
.radius
* ob
.data
.bevel_depth
,
1856 "<%.4g,%.4g,%.4g>,%.4g\n"
1861 pt
.radius
* ob
.data
.bevel_depth
,
1864 if spl
.use_cyclic_u
:
1865 for i
in range(0, 2):
1869 "<%.4g,%.4g,%.4g>,%.4g\n"
1874 endPt
.radius
* ob
.data
.bevel_depth
,
1879 # below not used yet?
1880 if ob
.pov
.curveshape
== 'sor':
1881 for spl
in ob
.data
.splines
:
1882 if spl
.type in {'POLY', 'NURBS'}:
1884 numPoints
= len(points
)
1885 tabWrite("sor { %s,\n" % numPoints
)
1888 tabWrite("<%.4g,%.4g>\n" % (wpt
[0], wpt
[1]))
1890 tabWrite("box { 0,0\n")
1891 if ob
.pov
.curveshape
in {'lathe', 'prism'}:
1892 spl
= ob
.data
.splines
[0]
1893 if spl
.type == "BEZIER":
1894 points
= spl
.bezier_points
1895 lenCur
= len(points
) - 1
1898 if ob
.pov
.curveshape
in {'prism'}:
1899 height
= ob
.data
.extrude
1900 ifprism
= '-%s, %s,' % (height
, height
)
1904 "%s { bezier_spline %s %s,\n"
1905 % (ob
.pov
.curveshape
, ifprism
, lenPts
)
1907 for i
in range(0, lenCur
):
1909 pR
= points
[i
].handle_right
1911 if i
== lenCur
- 1 and ob
.pov
.curveshape
in {'prism'}:
1913 pL
= points
[end
].handle_left
1915 line
= "<%.4g,%.4g>" % (p1
[0], p1
[1])
1916 line
+= "<%.4g,%.4g>" % (pR
[0], pR
[1])
1917 line
+= "<%.4g,%.4g>" % (pL
[0], pL
[1])
1918 line
+= "<%.4g,%.4g>" % (p2
[0], p2
[1])
1919 tabWrite("%s\n" % line
)
1922 lenCur
= len(points
)
1925 if ob
.pov
.curveshape
in {'prism'}:
1926 height
= ob
.data
.extrude
1927 ifprism
= '-%s, %s,' % (height
, height
)
1929 spl_type
= 'quadratic'
1930 if spl
.type == 'POLY':
1933 "%s { %s_spline %s %s,\n"
1934 % (ob
.pov
.curveshape
, spl_type
, ifprism
, lenPts
)
1936 if ob
.pov
.curveshape
in {'prism'}:
1937 pt
= points
[len(points
) - 1]
1939 tabWrite("<%.4g,%.4g>\n" % (wpt
[0], wpt
[1]))
1942 tabWrite("<%.4g,%.4g>\n" % (wpt
[0], wpt
[1]))
1943 if ob
.pov
.curveshape
in {'prism'}:
1947 tabWrite("<%.4g,%.4g>\n" % (wpt
[0], wpt
[1]))
1949 for p
in range(len(ob
.data
.splines
)):
1951 depth
= ob
.data
.bevel_depth
1952 spl
= ob
.data
.splines
[p
]
1953 points
= spl
.bezier_points
1954 lenCur
= len(points
) - 1
1955 numPoints
= lenCur
* 4
1956 if spl
.use_cyclic_u
:
1960 "#declare %s_points_%s = array[%s]{\n"
1961 % (dataname
, p
, numPoints
)
1963 for i
in range(lenCur
):
1965 pR
= points
[i
].handle_right
1967 if spl
.use_cyclic_u
and i
== (lenCur
- 1):
1969 pL
= points
[end
].handle_left
1971 r3
= points
[end
].radius
* depth
1972 r0
= points
[i
].radius
* depth
1973 r1
= 2 / 3 * r0
+ 1 / 3 * r3
1974 r2
= 1 / 3 * r0
+ 2 / 3 * r3
1975 br
.append((r0
, r1
, r2
, r3
))
1976 line
= "<%.4g,%.4g,%.4f>" % (p1
[0], p1
[1], p1
[2])
1977 line
+= "<%.4g,%.4g,%.4f>" % (pR
[0], pR
[1], pR
[2])
1978 line
+= "<%.4g,%.4g,%.4f>" % (pL
[0], pL
[1], pL
[2])
1979 line
+= "<%.4g,%.4g,%.4f>" % (p2
[0], p2
[1], p2
[2])
1980 tabWrite("%s\n" % line
)
1983 "#declare %s_radii_%s = array[%s]{\n"
1984 % (dataname
, p
, len(br
) * 4)
1988 '%.4f,%.4f,%.4f,%.4f\n'
1989 % (Tuple
[0], Tuple
[1], Tuple
[2], Tuple
[3])
1992 if len(ob
.data
.splines
) == 1:
1993 tabWrite('#declare %s = object{\n' % dataname
)
1995 ' Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'
1996 % (ob
.data
.resolution_u
, dataname
, p
, dataname
, p
)
1999 tabWrite('#declare %s = union{\n' % dataname
)
2000 for p
in range(len(ob
.data
.splines
)):
2002 ' object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'
2003 % (ob
.data
.resolution_u
, dataname
, p
, dataname
, p
)
2005 # tabWrite('#include "bezier_spheresweep.inc"\n') #now inlined
2006 # 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))
2007 if ob
.pov
.curveshape
in {'loft'}:
2009 'object {MSM(%s,%s,"c",%s,"")\n'
2010 % (dataname
, ob
.pov
.res_u
, ob
.pov
.res_v
)
2012 if ob
.pov
.curveshape
in {'birail'}:
2013 splines
= '%s1,%s2,%s3,%s4' % (
2020 'object {Coons(%s, %s, %s, "")\n'
2021 % (splines
, ob
.pov
.res_u
, ob
.pov
.res_v
)
2023 povMatName
= "Default_texture"
2024 if ob
.active_material
:
2025 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2027 material
= ob
.active_material
2028 writeObjectMaterial(material
, ob
)
2031 # tabWrite("texture {%s}\n"%povMatName)
2032 if ob
.pov
.curveshape
in {'prism'}:
2033 tabWrite("rotate <90,0,0>\n")
2034 tabWrite("scale y*-1\n")
2037 #################################################################
2039 def exportMeta(metas
):
2040 """write all POV blob primitives and Blender Metas to exported file """
2041 # TODO - blenders 'motherball' naming is not supported.
2043 if comments
and len(metas
) >= 1:
2044 file.write("//--Blob objects--\n\n")
2045 # Get groups of metaballs by blender name prefix.
2049 prefix
= ob
.name
.split(".")[0]
2050 if not prefix
in meta_group
:
2051 meta_group
[prefix
] = ob
# .data.threshold
2054 for elem
in ob
.data
.elements
2056 in {'BALL', 'ELLIPSOID', 'CAPSULE', 'CUBE', 'PLANE'}
2058 if prefix
in meta_elems
:
2059 meta_elems
[prefix
].extend(elems
)
2061 meta_elems
[prefix
] = elems
2065 tabWrite("\n//dummy sphere to represent empty meta location\n")
2067 "sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
2068 % (ob
.location
.x
, ob
.location
.y
, ob
.location
.z
)
2069 ) # ob.name > povdataname)
2072 for mg
, ob
in meta_group
.items():
2073 if len(meta_elems
[mg
]) != 0:
2075 "blob{threshold %.4g // %s \n"
2076 % (ob
.data
.threshold
, mg
)
2078 for elems
in meta_elems
[mg
]:
2081 stiffness
= elem
.stiffness
2082 if elem
.use_negative
:
2083 stiffness
= -stiffness
2084 if elem
.type == 'BALL':
2086 "sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g "
2096 global_matrix
@ elems
[1].matrix_world
2099 elif elem
.type == 'ELLIPSOID':
2101 "sphere{ <%.6g, %.6g, %.6g>,%.4g,%.4g "
2103 loc
.x
/ elem
.size_x
,
2104 loc
.y
/ elem
.size_y
,
2105 loc
.z
/ elem
.size_z
,
2111 "scale <%.6g, %.6g, %.6g>"
2112 % (elem
.size_x
, elem
.size_y
, elem
.size_z
)
2115 global_matrix
@ elems
[1].matrix_world
2118 elif elem
.type == 'CAPSULE':
2120 "cylinder{ <%.6g, %.6g, %.6g>,<%.6g, %.6g, %.6g>,%.4g,%.4g "
2122 (loc
.x
- elem
.size_x
),
2125 (loc
.x
+ elem
.size_x
),
2132 # tabWrite("scale <%.6g, %.6g, %.6g>" % (elem.size_x, elem.size_y, elem.size_z))
2134 global_matrix
@ elems
[1].matrix_world
2138 elif elem
.type == 'CUBE':
2140 "cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
2153 global_matrix
@ elems
[1].matrix_world
2157 "cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
2170 global_matrix
@ elems
[1].matrix_world
2174 "cylinder { -z*8, +z*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1,1/4> scale <%.6g, %.6g, %.6g>\n"
2187 global_matrix
@ elems
[1].matrix_world
2191 elif elem
.type == 'PLANE':
2193 "cylinder { -x*8, +x*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1/4,1,1> scale <%.6g, %.6g, %.6g>\n"
2206 global_matrix
@ elems
[1].matrix_world
2210 "cylinder { -y*8, +y*8,%.4g,%.4g translate<%.6g,%.6g,%.6g> scale <1,1/4,1> scale <%.6g, %.6g, %.6g>\n"
2223 global_matrix
@ elems
[1].matrix_world
2228 material
= elems
[1].data
.materials
[
2230 ] # lame! - blender cant do enything else.
2234 diffuse_color
= material
.diffuse_color
2235 trans
= 1.0 - material
.pov
.alpha
2237 material
.use_transparency
2238 and material
.transparency_method
== 'RAYTRACE'
2241 material
.pov_raytrace_transparency
.filter
2242 * (1.0 - material
.alpha
)
2244 trans
= (1.0 - material
.pov
.alpha
) - povFilter
2247 material_finish
= materialNames
[material
.name
]
2249 "pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n"
2259 "finish{%s} " % safety(material_finish
, Level
=2)
2263 "pigment{srgb 1} finish{%s} "
2264 % (safety(DEF_MAT_NAME
, Level
=2))
2267 writeObjectMaterial(material
, ob
)
2268 # writeObjectMaterial(material, elems[1])
2270 "radiosity{importance %3g}\n"
2271 % ob
.pov
.importance_value
2273 tabWrite("}\n\n") # End of Metaball block
2278 # important because no elements will break parsing.
2279 elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
2282 tabWrite("blob {\n")
2283 tabWrite("threshold %.4g\n" % meta.threshold)
2284 importance = ob.pov.importance_value
2287 material = meta.materials[0] # lame! - blender cant do enything else.
2291 for elem in elements:
2294 stiffness = elem.stiffness
2295 if elem.use_negative:
2296 stiffness = - stiffness
2298 if elem.type == 'BALL':
2300 tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
2301 (loc.x, loc.y, loc.z, elem.radius, stiffness))
2303 # After this wecould do something simple like...
2304 # "pigment {Blue} }"
2305 # except we'll write the color
2307 elif elem.type == 'ELLIPSOID':
2308 # location is modified by scale
2309 tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" %
2310 (loc.x / elem.size_x,
2311 loc.y / elem.size_y,
2312 loc.z / elem.size_z,
2313 elem.radius, stiffness))
2314 tabWrite("scale <%.6g, %.6g, %.6g> \n" %
2315 (elem.size_x, elem.size_y, elem.size_z))
2318 diffuse_color = material.diffuse_color
2319 trans = 1.0 - material.pov.alpha
2320 if material.use_transparency and material.transparency_method == 'RAYTRACE':
2321 povFilter = material.pov_raytrace_transparency.filter * (1.0 - material.alpha)
2322 trans = (1.0 - material.pov.alpha) - povFilter
2326 material_finish = materialNames[material.name]
2328 tabWrite("pigment {srgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" %
2329 (diffuse_color[0], diffuse_color[1], diffuse_color[2],
2331 tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
2334 tabWrite("pigment {srgb 1} \n")
2335 # Write the finish last.
2336 tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
2338 writeObjectMaterial(material, elems[1])
2340 writeMatrix(global_matrix @ ob.matrix_world)
2341 # Importance for radiosity sampling added here
2342 tabWrite("radiosity { \n")
2343 # importance > ob.pov.importance_value
2344 tabWrite("importance %3g \n" % importance)
2347 tabWrite("}\n") # End of Metaball block
2349 if comments and len(metas) >= 1:
2353 DEF_OBJ_NAME
= "Default"
2355 def exportMeshes(scene
, sel
, csg
):
2356 """write all meshes as POV mesh2{} syntax to exported file """
2357 #some numpy functions to speed up mesh export
2359 # TODO: also write a numpy function to read matrices at object level?
2360 # feed below with mesh object.data, but only after doing data.calc_loop_triangles()
2361 def read_verts_co(self
, mesh
):
2362 #'float64' would be a slower 64-bit floating-point number numpy datatype
2363 # using 'float32' vert coordinates for now until any issue is reported
2364 mverts_co
= np
.zeros((len(mesh
.vertices
)*3), dtype
=np
.float32
)
2365 mesh
.vertices
.foreach_get("co", mverts_co
)
2366 return np
.reshape(mverts_co
, (len(mesh
.vertices
), 3))
2368 def read_verts_idx(self
, mesh
):
2369 mverts_idx
= np
.zeros((len(mesh
.vertices
)), dtype
=np
.int64
)
2370 mesh
.vertices
.foreach_get("index", mverts_idx
)
2371 return np
.reshape(mverts_idx
, (len(mesh
.vertices
), 1))
2373 def read_verts_norms(self
, mesh
):
2374 #'float64' would be a slower 64-bit floating-point number numpy datatype
2375 # using less accurate 'float16' normals for now until any issue is reported
2376 mverts_no
= np
.zeros((len(mesh
.vertices
)*3), dtype
=np
.float16
)
2377 mesh
.vertices
.foreach_get("normal", mverts_no
)
2378 return np
.reshape(mverts_no
, (len(mesh
.vertices
), 3))
2380 def read_faces_idx(self
, mesh
):
2381 mfaces_idx
= np
.zeros((len(mesh
.loop_triangles
)), dtype
=np
.int64
)
2382 mesh
.loop_triangles
.foreach_get("index", mfaces_idx
)
2383 return np
.reshape(mfaces_idx
, (len(mesh
.loop_triangles
), 1))
2385 def read_faces_verts_indices(self
, mesh
):
2386 mfaces_verts_idx
= np
.zeros((len(mesh
.loop_triangles
)*3), dtype
=np
.int64
)
2387 mesh
.loop_triangles
.foreach_get("vertices", mfaces_verts_idx
)
2388 return np
.reshape(mfaces_verts_idx
, (len(mesh
.loop_triangles
), 3))
2390 #Why is below different from verex indices?
2391 def read_faces_verts_loops(self
, mesh
):
2392 mfaces_verts_loops
= np
.zeros((len(mesh
.loop_triangles
)*3), dtype
=np
.int64
)
2393 mesh
.loop_triangles
.foreach_get("loops", mfaces_verts_loops
)
2394 return np
.reshape(mfaces_verts_loops
, (len(mesh
.loop_triangles
), 3))
2396 def read_faces_norms(self
, mesh
):
2397 #'float64' would be a slower 64-bit floating-point number numpy datatype
2398 # using less accurate 'float16' normals for now until any issue is reported
2399 mfaces_no
= np
.zeros((len(mesh
.loop_triangles
)*3), dtype
=np
.float16
)
2400 mesh
.loop_triangles
.foreach_get("normal", mfaces_no
)
2401 return np
.reshape(mfaces_no
, (len(mesh
.loop_triangles
), 3))
2403 def read_faces_smooth(self
, mesh
):
2404 mfaces_smth
= np
.zeros((len(mesh
.loop_triangles
)*1), dtype
=np
.bool)
2405 mesh
.loop_triangles
.foreach_get("use_smooth", mfaces_smth
)
2406 return np
.reshape(mfaces_smth
, (len(mesh
.loop_triangles
), 1))
2408 def read_faces_material_indices(self
, mesh
):
2409 mfaces_mats_idx
= np
.zeros((len(mesh
.loop_triangles
)), dtype
=np
.int16
)
2410 mesh
.loop_triangles
.foreach_get("material_index", mfaces_mats_idx
)
2411 return np
.reshape(mfaces_mats_idx
, (len(mesh
.loop_triangles
), 1))
2416 # def hasUniqueMaterial():
2417 # # Grab materials attached to object instances ...
2418 # if hasattr(ob, 'material_slots'):
2419 # for ms in ob.material_slots:
2420 # if ms.material is not None and ms.link == 'OBJECT':
2421 # if ms.material in obmatslist:
2424 # obmatslist.append(ms.material)
2426 # def hasObjectMaterial(ob):
2427 # # Grab materials attached to object instances ...
2428 # if hasattr(ob, 'material_slots'):
2429 # for ms in ob.material_slots:
2430 # if ms.material is not None and ms.link == 'OBJECT':
2431 # # If there is at least one material slot linked to the object
2432 # # and not the data (mesh), always create a new, "private" data instance.
2435 # For objects using local material(s) only!
2436 # This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
2437 # As only objects using:
2439 # * EXACTLY the same materials, in EXACTLY the same sockets.
2440 # ... can share a same instance in POV export.
2443 def checkObjectMaterials(ob
, name
, dataname
):
2444 if hasattr(ob
, 'material_slots'):
2445 has_local_mats
= False
2447 for ms
in ob
.material_slots
:
2448 if ms
.material
is not None:
2449 key
.append(ms
.material
.name
)
2450 if ms
.link
== 'OBJECT' and not has_local_mats
:
2451 has_local_mats
= True
2453 # Even if the slot is empty, it is important to grab it...
2456 # If this object uses local material(s), lets find if another object
2457 # using the same data and exactly the same list of materials
2458 # (in the same slots) has already been processed...
2459 # Note that here also, we use object name as new, unique dataname for Pov.
2460 key
= tuple(key
) # Lists are not hashable...
2461 if key
not in obmats2data
:
2462 obmats2data
[key
] = name
2463 return obmats2data
[key
]
2468 def store(scene
, ob
, name
, dataname
, matrix
):
2469 # The Object needs to be written at least once but if its data is
2470 # already in data_ref this has already been done.
2471 # This func returns the "povray" name of the data, or None
2472 # if no writing is needed.
2473 if ob
.is_modified(scene
, 'RENDER'):
2475 # Create unique entry in data_ref by using object name
2476 # (always unique in Blender) as data name.
2477 data_ref
[name
] = [(name
, MatrixAsPovString(matrix
))]
2479 # Here, we replace dataname by the value returned by checkObjectMaterials, only if
2480 # it is not evaluated to False (i.e. only if the object uses some local material(s)).
2481 dataname
= checkObjectMaterials(ob
, name
, dataname
) or dataname
2482 if dataname
in data_ref
:
2483 # Data already known, just add the object instance.
2484 data_ref
[dataname
].append((name
, MatrixAsPovString(matrix
)))
2485 # No need to write data
2488 # Data not yet processed, create a new entry in data_ref.
2489 data_ref
[dataname
] = [(name
, MatrixAsPovString(matrix
))]
2492 def exportSmoke(smoke_obj_name
):
2493 # if LuxManager.CurrentScene.name == 'preview':
2494 # return 1, 1, 1, 1.0
2497 smoke_obj
= bpy
.data
.objects
[smoke_obj_name
]
2500 # Search smoke domain target for smoke modifiers
2501 for mod
in smoke_obj
.modifiers
:
2502 if mod
.name
== 'Smoke':
2503 if mod
.smoke_type
== 'FLOW':
2504 if mod
.flow_settings
.smoke_flow_type
== 'BOTH':
2507 if mod
.flow_settings
.smoke_flow_type
== 'SMOKE':
2510 if mod
.flow_settings
.smoke_flow_type
== 'FIRE':
2513 if mod
.smoke_type
== 'DOMAIN':
2515 smoke_modifier
= mod
2518 if domain
is not None:
2519 # if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
2520 # Blender version 2.71 supports direct access to smoke data structure
2521 set = mod
.domain_settings
2523 for v
in set.density_grid
:
2524 channeldata
.append(v
.real
)
2526 ## Usage en voxel texture:
2528 # if channel == 'density':
2529 # for v in set.density_grid:
2530 # channeldata.append(v.real)
2532 # if channel == 'fire':
2533 # for v in set.flame_grid:
2534 # channeldata.append(v.real)
2536 resolution
= set.resolution_max
2538 big_res
.append(set.domain_resolution
[0])
2539 big_res
.append(set.domain_resolution
[1])
2540 big_res
.append(set.domain_resolution
[2])
2542 if set.use_high_resolution
:
2543 big_res
[0] = big_res
[0] * (set.amplify
+ 1)
2544 big_res
[1] = big_res
[1] * (set.amplify
+ 1)
2545 big_res
[2] = big_res
[2] * (set.amplify
+ 1)
2548 ##gather smoke domain settings
2549 # BBox = domain.bound_box
2550 # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
2551 # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
2552 # set = mod.domain_settings
2553 # resolution = set.resolution_max
2554 # smokecache = set.point_cache
2555 # ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
2562 # if res_x * res_y * res_z > 0:
2565 # big_res.append(res_x)
2566 # big_res.append(res_y)
2567 # big_res.append(res_z)
2569 # max = domain.dimensions[0]
2570 # if (max - domain.dimensions[1]) < -eps:
2571 # max = domain.dimensions[1]
2573 # if (max - domain.dimensions[2]) < -eps:
2574 # max = domain.dimensions[2]
2576 # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
2577 # int(round(resolution * domain.dimensions[1] / max, 0)),
2578 # int(round(resolution * domain.dimensions[2] / max, 0))]
2580 # if set.use_high_resolution:
2581 # big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
2582 # big_res[2] * (set.amplify + 1)]
2584 # if channel == 'density':
2585 # channeldata = density
2587 # if channel == 'fire':
2588 # channeldata = fire
2590 # sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
2591 # if not os.path.exists( sc_fr ):
2592 # os.makedirs(sc_fr)
2594 # smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
2595 # smoke_path = '/'.join([sc_fr, smoke_filename])
2597 # with open(smoke_path, 'wb') as smoke_file:
2598 # # Binary densitygrid file format
2601 # smoke_file.write(b'SMOKE') #magic number
2602 # smoke_file.write(struct.pack('<I', big_res[0]))
2603 # smoke_file.write(struct.pack('<I', big_res[1]))
2604 # smoke_file.write(struct.pack('<I', big_res[2]))
2606 # smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
2608 # LuxLog('Binary SMOKE file written: %s' % (smoke_path))
2610 # return big_res[0], big_res[1], big_res[2], channeldata
2612 mydf3
= df3
.df3(big_res
[0], big_res
[1], big_res
[2])
2613 sim_sizeX
, sim_sizeY
, sim_sizeZ
= mydf3
.size()
2614 for x
in range(sim_sizeX
):
2615 for y
in range(sim_sizeY
):
2616 for z
in range(sim_sizeZ
):
2622 ((z
* sim_sizeY
+ y
) * sim_sizeX
+ x
)
2626 mydf3
.exportDF3(smokePath
)
2627 print('Binary smoke.df3 file written in preview directory')
2629 file.write("\n//--Smoke--\n\n")
2631 # Note: We start with a default unit cube.
2632 # This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
2633 # coordinates from the start, and avoid scale/translate operations at the end...
2634 file.write("box{<0,0,0>, <1,1,1>\n")
2635 file.write(" pigment{ rgbt 1 }\n")
2636 file.write(" hollow\n")
2637 file.write(" interior{ //---------------------\n")
2638 file.write(" media{ method 3\n")
2640 " emission <1,1,1>*1\n"
2641 ) # 0>1 for dark smoke to white vapour
2642 file.write(" scattering{ 1, // Type\n")
2643 file.write(" <1,1,1>*0.1\n")
2644 file.write(" } // end scattering\n")
2646 " density{density_file df3 \"%s\"\n"
2649 file.write(" color_map {\n")
2650 file.write(" [0.00 rgb 0]\n")
2651 file.write(" [0.05 rgb 0]\n")
2652 file.write(" [0.20 rgb 0.2]\n")
2653 file.write(" [0.30 rgb 0.6]\n")
2654 file.write(" [0.40 rgb 1]\n")
2655 file.write(" [1.00 rgb 1]\n")
2656 file.write(" } // end color_map\n")
2657 file.write(" } // end of density\n")
2659 " samples %i // higher = more precise\n"
2663 " } // end of media --------------------------\n"
2665 file.write(" } // end of interior\n")
2667 # START OF TRANSFORMATIONS
2669 # Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
2670 # loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
2671 bbox
= smoke_obj
.bound_box
2673 abs(bbox
[6][0] - bbox
[0][0]),
2674 abs(bbox
[6][1] - bbox
[0][1]),
2675 abs(bbox
[6][2] - bbox
[0][2]),
2678 # We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
2679 file.write("scale<%.6g,%.6g,%.6g>\n" % (dim
[0], dim
[1], dim
[2]))
2681 # We offset our cube such that (0,0,0) coordinate matches Blender's object center.
2683 "translate<%.6g,%.6g,%.6g>\n"
2684 % (bbox
[0][0], bbox
[0][1], bbox
[0][2])
2687 # We apply object's transformations to get final loc/rot/size in world space!
2688 # Note: we could combine the two previous transformations with this matrix directly...
2689 writeMatrix(global_matrix
@ smoke_obj
.matrix_world
)
2691 # END OF TRANSFORMATIONS
2695 # file.write(" interpolate 1\n")
2696 # file.write(" frequency 0\n")
2697 # file.write(" }\n")
2702 # subtract original from the count of their instances as were not counted before 2.8
2703 if not (ob
.is_instancer
and ob
.original
!= ob
):
2706 # XXX I moved all those checks here, as there is no need to compute names
2707 # for object we won't export here!
2710 'CAMERA', #'EMPTY', #empties can bear dupligroups
2717 for mod
in ob
.modifiers
:
2718 if mod
and hasattr(mod
, 'smoke_type'):
2720 if mod
.smoke_type
== 'DOMAIN':
2721 exportSmoke(ob
.name
)
2722 break # don't render domain mesh or flow emitter mesh, skip to next object.
2725 renderEmitter
= True
2726 if hasattr(ob
, 'particle_systems'):
2727 renderEmitter
= False
2728 if ob
.show_instancer_for_render
:
2729 renderEmitter
= True
2730 for pSys
in ob
.particle_systems
:
2733 for m
in ob
.modifiers
2735 and (m
.type == 'PARTICLE_SYSTEM')
2738 (pSys
.settings
.render_type
== 'PATH')
2740 and (pSys
.name
== mod
.particle_system
.name
)
2742 tstart
= time
.time()
2746 pSys
.settings
.material
- 1
2748 and ob
.active_material
is not None
2750 pmaterial
= ob
.material_slots
[
2751 pSys
.settings
.material
- 1
2753 #XXX Todo: replace by pov_(Particles?)_texture_slot
2754 for th
in pmaterial
.texture_slots
:
2760 and th
.texture
.image
2765 if th
.use_map_color_diffuse
:
2767 if pmaterial
.strand
.use_blender_units
:
2769 pmaterial
.strand
.root_size
2772 pmaterial
.strand
.tip_size
2774 strandShape
= pmaterial
.strand
.shape
2775 else: # Blender unit conversion
2777 pmaterial
.strand
.root_size
2781 pmaterial
.strand
.tip_size
2784 strandShape
= pmaterial
.strand
.shape
2788 ) # No material assigned in blender, use default one
2792 # Set the number of particles to render count rather than 3d view display
2793 # pSys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
2794 # When you render, the entire dependency graph will be
2795 # evaluated at render resolution, including the particles.
2796 # In the viewport it will be at viewport resolution.
2797 # So there is no need fo render engines to use this function anymore,
2798 # it's automatic now.
2799 steps
= pSys
.settings
.display_step
2802 ) # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
2804 totalNumberOfHairs
= (
2806 + pSys
.settings
.rendered_child_count
2810 '#declare HairArray = array[%i] {\n'
2811 % totalNumberOfHairs
2813 for pindex
in range(0, totalNumberOfHairs
):
2815 # if particle.is_exist and particle.is_visible:
2817 # controlPointCounter = 0
2818 # Each hair is represented as a separate sphere_sweep in POV-Ray.
2820 file.write('sphere_sweep{')
2821 if pSys
.settings
.use_hair_bspline
:
2822 file.write('b_spline ')
2824 '%i,\n' % (steps
+ 2)
2825 ) # +2 because the first point needs tripling to be more than a handle in POV
2827 file.write('linear_spline ')
2828 file.write('%i,\n' % (steps
))
2829 # changing world coordinates to object local coordinates by multiplying with inverted matrix
2830 initCo
= ob
.matrix_world
.inverted() @ (
2832 ob
, particle_no
=pindex
, step
=0
2837 pSys
.settings
.material
- 1
2839 and ob
.active_material
is not None
2841 pmaterial
= ob
.material_slots
[
2842 pSys
.settings
.material
- 1
2844 for th
in pmaterial
.texture_slots
:
2848 and th
.use_map_color_diffuse
2850 # treat POV textures as bitmaps
2854 and th
.texture
.image
2855 and th
.texture_coords
2857 and ob
.data
.uv_textures
2859 ): # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures is not None):
2860 image
= th
.texture
.image
2861 image_width
= image
.size
[
2864 image_height
= image
.size
[
2867 image_pixels
= image
.pixels
[
2870 uv_co
= pSys
.uv_on_emitter(
2884 * (image_height
- 1)
2901 initColor
= (r
, g
, b
, a
)
2903 # only overwrite variable for each competing texture for now
2904 initColor
= th
.texture
.evaluate(
2911 for step
in range(0, steps
):
2912 co
= ob
.matrix_world
.inverted() @ (
2919 # for controlPoint in particle.hair_keys:
2920 if pSys
.settings
.clump_factor
!= 0:
2922 pSys
.settings
.clump_factor
2924 * random
.uniform(0.5, 1)
2927 hDiameter
= strandStart
2930 strandEnd
- strandStart
2932 pSys
.settings
.display_step
2937 and pSys
.settings
.use_hair_bspline
2939 # Write three times the first point to compensate pov Bezier handling
2941 '<%.6g,%.6g,%.6g>,%.7g,\n'
2950 '<%.6g,%.6g,%.6g>,%.7g,\n'
2958 # 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.
2960 # controlPointCounter += 1
2961 # totalNumberOfHairs += len(pSys.particles)# len(particle.hair_keys)
2963 # Each control point is written out, along with the radius of the
2964 # hair at that point.
2966 '<%.6g,%.6g,%.6g>,%.7g'
2975 # All coordinates except the last need a following comma.
2977 if step
!= steps
- 1:
2981 # Write pigment and alpha (between Pov and Blender alpha 0 and 1 are reversed)
2983 '\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
2991 # End the sphere_sweep declaration for this hair
2994 # All but the final sphere_sweep (each array element) needs a terminating comma.
2995 if pindex
!= totalNumberOfHairs
:
3000 # End the array declaration.
3005 if not texturedHair
:
3006 # Pick up the hair material diffuse color and create a default POV-Ray hair texture.
3008 file.write('#ifndef (HairTexture)\n')
3010 ' #declare HairTexture = texture {\n'
3013 ' pigment {srgbt <%s,%s,%s,%s>}\n'
3015 pmaterial
.diffuse_color
[0],
3016 pmaterial
.diffuse_color
[1],
3017 pmaterial
.diffuse_color
[2],
3019 pmaterial
.strand
.width_fade
3025 file.write('#end\n')
3028 # Dynamically create a union of the hairstrands (or a subset of them).
3029 # By default use every hairstrand, commented line is for hand tweaking test renders.
3031 '//Increasing HairStep divides the amount of hair for test renders.\n'
3034 '#ifndef(HairStep) #declare HairStep = 1; #end\n'
3036 file.write('union{\n')
3037 file.write(' #local I = 0;\n')
3039 ' #while (I < %i)\n'
3040 % totalNumberOfHairs
3042 file.write(' object {HairArray[I]')
3043 if not texturedHair
:
3044 file.write(' texture{HairTexture}\n')
3047 # Translucency of the hair:
3048 file.write(' hollow\n')
3049 file.write(' double_illuminate\n')
3050 file.write(' interior {\n')
3051 file.write(' ior 1.45\n')
3052 file.write(' media {\n')
3054 ' scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n'
3057 ' absorption 10/<0.83, 0.75, 0.15>\n'
3059 file.write(' samples 1\n')
3060 file.write(' method 2\n')
3062 ' density {cylindrical\n'
3068 ' [0.0 rgb <0.83, 0.45, 0.35>]\n'
3071 ' [0.5 rgb <0.8, 0.8, 0.4>]\n'
3074 ' [1.0 rgb <1,1,1>]\n'
3082 file.write(' #local I = I + HairStep;\n')
3083 file.write(' #end\n')
3085 writeMatrix(global_matrix
@ ob
.matrix_world
)
3089 'Totals hairstrands written: %i'
3090 % totalNumberOfHairs
3093 'Number of tufts (particle systems)',
3094 len(ob
.particle_systems
),
3097 # Set back the displayed number of particles to preview count
3098 # pSys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
3099 # When you render, the entire dependency graph will be
3100 # evaluated at render resolution, including the particles.
3101 # In the viewport it will be at viewport resolution.
3102 # So there is no need fo render engines to use this function anymore,
3103 # it's automatic now.
3104 if renderEmitter
== False:
3105 continue # don't render mesh, skip to next object.
3107 #############################################
3108 # Generating a name for object just like materials to be able to use it
3109 # (baking for now or anything else).
3110 # XXX I don't understand that if we are here, sel if a non-empty iterable,
3111 # so this condition is always True, IMO -- mont29
3113 name_orig
= "OB" + ob
.name
3114 dataname_orig
= "DATA" + ob
.data
.name
3115 elif ob
.is_instancer
:
3116 if ob
.instance_type
== 'COLLECTION':
3117 name_orig
= "OB" + ob
.name
3118 dataname_orig
= "DATA" + ob
.instance_collection
.name
3120 # hoping only dupligroups have several source datablocks
3121 # ob_dupli_list_create(scene) #deprecated in 2.8
3122 depsgraph
= bpy
.context
.evaluated_depsgraph_get()
3123 for eachduplicate
in depsgraph
.object_instances
:
3125 eachduplicate
.is_instance
3126 ): # Real dupli instance filtered because original included in list since 2.8
3128 "DATA" + eachduplicate
.object.name
3130 # ob.dupli_list_clear() #just don't store any reference to instance since 2.8
3131 elif ob
.type == 'EMPTY':
3132 name_orig
= "OB" + ob
.name
3133 dataname_orig
= "DATA" + ob
.name
3135 name_orig
= DEF_OBJ_NAME
3136 dataname_orig
= DEF_OBJ_NAME
3137 name
= string_strip_hyphen(bpy
.path
.clean_name(name_orig
))
3138 dataname
= string_strip_hyphen(
3139 bpy
.path
.clean_name(dataname_orig
)
3141 ## for slot in ob.material_slots:
3142 ## if slot.material is not None and slot.link == 'OBJECT':
3143 ## obmaterial = slot.material
3145 #############################################
3149 "Object %2.d of %2.d (%s)"
3150 % (ob_num
, len(sel
), ob
.name
)
3153 # if ob.type != 'MESH':
3157 matrix
= global_matrix
@ ob
.matrix_world
3158 povdataname
= store(scene
, ob
, name
, dataname
, matrix
)
3159 if povdataname
is None:
3160 print("This is an instance of " + name
)
3163 print("Writing Down First Occurrence of " + name
)
3165 ############################################Povray Primitives
3166 # special exportCurves() function takes care of writing
3167 # lathe, sphere_sweep, birail, and loft except with modifiers
3169 if not ob
.is_modified(scene
, 'RENDER'):
3170 if ob
.type == 'CURVE' and (
3172 in {'lathe', 'sphere_sweep', 'loft'}
3174 continue # Don't render proxy mesh, skip to next object
3176 if ob
.pov
.object_as
== 'ISOSURFACE':
3177 tabWrite("#declare %s = isosurface{ \n" % povdataname
)
3178 tabWrite("function{ \n")
3179 textName
= ob
.pov
.iso_function_text
3181 node_tree
= bpy
.context
.scene
.node_tree
3182 for node
in node_tree
.nodes
:
3184 node
.bl_idname
== "IsoPropsNode"
3185 and node
.label
== ob
.name
3187 for inp
in node
.inputs
:
3190 "#declare %s = %.6g;\n"
3191 % (inp
.name
, inp
.default_value
)
3194 text
= bpy
.data
.texts
[textName
]
3195 for line
in text
.lines
:
3196 split
= line
.body
.split()
3197 if split
[0] != "#declare":
3198 tabWrite("%s\n" % line
.body
)
3200 tabWrite("abs(x) - 2 + y")
3202 tabWrite("threshold %.6g\n" % ob
.pov
.threshold
)
3203 tabWrite("max_gradient %.6g\n" % ob
.pov
.max_gradient
)
3204 tabWrite("accuracy %.6g\n" % ob
.pov
.accuracy
)
3205 tabWrite("contained_by { ")
3206 if ob
.pov
.contained_by
== "sphere":
3208 "sphere {0,%.6g}}\n" % ob
.pov
.container_scale
3212 "box {-%.6g,%.6g}}\n"
3214 ob
.pov
.container_scale
,
3215 ob
.pov
.container_scale
,
3218 if ob
.pov
.all_intersections
:
3219 tabWrite("all_intersections\n")
3221 if ob
.pov
.max_trace
> 1:
3222 tabWrite("max_trace %.6g\n" % ob
.pov
.max_trace
)
3223 povMatName
= "Default_texture"
3224 if ob
.active_material
:
3225 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3227 material
= ob
.active_material
3228 writeObjectMaterial(material
, ob
)
3231 # tabWrite("texture {%s}\n"%povMatName)
3232 tabWrite("scale %.6g\n" % (1 / ob
.pov
.container_scale
))
3234 continue # Don't render proxy mesh, skip to next object
3236 if ob
.pov
.object_as
== 'SUPERELLIPSOID':
3238 "#declare %s = superellipsoid{ <%.4f,%.4f>\n"
3239 % (povdataname
, ob
.pov
.se_n2
, ob
.pov
.se_n1
)
3241 povMatName
= "Default_texture"
3242 if ob
.active_material
:
3243 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3245 material
= ob
.active_material
3246 writeObjectMaterial(material
, ob
)
3249 # tabWrite("texture {%s}\n"%povMatName)
3250 write_object_modifiers(scene
, ob
, file)
3252 continue # Don't render proxy mesh, skip to next object
3254 if ob
.pov
.object_as
== 'SUPERTORUS':
3255 rMajor
= ob
.pov
.st_major_radius
3256 rMinor
= ob
.pov
.st_minor_radius
3257 ring
= ob
.pov
.st_ring
3258 cross
= ob
.pov
.st_cross
3259 accuracy
= ob
.pov
.st_accuracy
3260 gradient
= ob
.pov
.st_max_gradient
3261 ############Inline Supertorus macro
3263 "#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n"
3265 file.write(" #local CP = 2/MinorControl;\n")
3266 file.write(" #local RP = 2/MajorControl;\n")
3267 file.write(" isosurface {\n")
3269 " 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"
3271 file.write(" threshold 0\n")
3273 " contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n"
3275 file.write(" #if(MaxGradient >= 1)\n")
3276 file.write(" max_gradient MaxGradient\n")
3277 file.write(" #else\n")
3278 file.write(" evaluate 1, 10, 0.1\n")
3279 file.write(" #end\n")
3280 file.write(" accuracy Accuracy\n")
3282 file.write("#end\n")
3285 "#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"
3296 povMatName
= "Default_texture"
3297 if ob
.active_material
:
3298 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3300 material
= ob
.active_material
3301 writeObjectMaterial(material
, ob
)
3304 # tabWrite("texture {%s}\n"%povMatName)
3305 write_object_modifiers(scene
, ob
, file)
3306 tabWrite("rotate x*90\n")
3308 continue # Don't render proxy mesh, skip to next object
3310 if ob
.pov
.object_as
== 'PLANE':
3312 "#declare %s = plane{ <0,0,1>,1\n" % povdataname
3314 povMatName
= "Default_texture"
3315 if ob
.active_material
:
3316 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3318 material
= ob
.active_material
3319 writeObjectMaterial(material
, ob
)
3322 # tabWrite("texture {%s}\n"%povMatName)
3323 write_object_modifiers(scene
, ob
, file)
3324 # tabWrite("rotate x*90\n")
3326 continue # Don't render proxy mesh, skip to next object
3328 if ob
.pov
.object_as
== 'BOX':
3329 tabWrite("#declare %s = box { -1,1\n" % povdataname
)
3330 povMatName
= "Default_texture"
3331 if ob
.active_material
:
3332 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3334 material
= ob
.active_material
3335 writeObjectMaterial(material
, ob
)
3338 # tabWrite("texture {%s}\n"%povMatName)
3339 write_object_modifiers(scene
, ob
, file)
3340 # tabWrite("rotate x*90\n")
3342 continue # Don't render proxy mesh, skip to next object
3344 if ob
.pov
.object_as
== 'CONE':
3345 br
= ob
.pov
.cone_base_radius
3346 cr
= ob
.pov
.cone_cap_radius
3347 bz
= ob
.pov
.cone_base_z
3348 cz
= ob
.pov
.cone_cap_z
3350 "#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"
3351 % (povdataname
, bz
, br
, cz
, cr
)
3353 povMatName
= "Default_texture"
3354 if ob
.active_material
:
3355 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3357 material
= ob
.active_material
3358 writeObjectMaterial(material
, ob
)
3361 # tabWrite("texture {%s}\n"%povMatName)
3362 write_object_modifiers(scene
, ob
, file)
3363 # tabWrite("rotate x*90\n")
3365 continue # Don't render proxy mesh, skip to next object
3367 if ob
.pov
.object_as
== 'CYLINDER':
3368 r
= ob
.pov
.cylinder_radius
3369 x2
= ob
.pov
.cylinder_location_cap
[0]
3370 y2
= ob
.pov
.cylinder_location_cap
[1]
3371 z2
= ob
.pov
.cylinder_location_cap
[2]
3373 "#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n"
3374 % (povdataname
, x2
, y2
, z2
, r
)
3376 povMatName
= "Default_texture"
3377 if ob
.active_material
:
3378 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3380 material
= ob
.active_material
3381 writeObjectMaterial(material
, ob
)
3384 # tabWrite("texture {%s}\n"%povMatName)
3385 # cylinders written at origin, translated below
3386 write_object_modifiers(scene
, ob
, file)
3387 # tabWrite("rotate x*90\n")
3389 continue # Don't render proxy mesh, skip to next object
3391 if ob
.pov
.object_as
== 'HEIGHT_FIELD':
3393 filename
= ob
.pov
.hf_filename
3394 data
+= '"%s"' % filename
3395 gamma
= ' gamma %.4f' % ob
.pov
.hf_gamma
3397 if ob
.pov
.hf_premultiplied
:
3398 data
+= ' premultiplied on'
3399 if ob
.pov
.hf_smooth
:
3401 if ob
.pov
.hf_water
> 0:
3402 data
+= ' water_level %.4f' % ob
.pov
.hf_water
3403 # hierarchy = ob.pov.hf_hierarchy
3405 '#declare %s = height_field { %s\n'
3406 % (povdataname
, data
)
3408 povMatName
= "Default_texture"
3409 if ob
.active_material
:
3410 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3412 material
= ob
.active_material
3413 writeObjectMaterial(material
, ob
)
3416 # tabWrite("texture {%s}\n"%povMatName)
3417 write_object_modifiers(scene
, ob
, file)
3418 tabWrite("rotate x*90\n")
3419 tabWrite("translate <-0.5,0.5,0>\n")
3420 tabWrite("scale <0,-1,0>\n")
3422 continue # Don't render proxy mesh, skip to next object
3424 if ob
.pov
.object_as
== 'SPHERE':
3427 "#declare %s = sphere { 0,%6f\n"
3428 % (povdataname
, ob
.pov
.sphere_radius
)
3430 povMatName
= "Default_texture"
3431 if ob
.active_material
:
3432 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3434 material
= ob
.active_material
3435 writeObjectMaterial(material
, ob
)
3438 # tabWrite("texture {%s}\n"%povMatName)
3439 write_object_modifiers(scene
, ob
, file)
3440 # tabWrite("rotate x*90\n")
3442 continue # Don't render proxy mesh, skip to next object
3444 if ob
.pov
.object_as
== 'TORUS':
3446 "#declare %s = torus { %.4f,%.4f\n"
3449 ob
.pov
.torus_major_radius
,
3450 ob
.pov
.torus_minor_radius
,
3453 povMatName
= "Default_texture"
3454 if ob
.active_material
:
3455 # povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
3457 material
= ob
.active_material
3458 writeObjectMaterial(material
, ob
)
3461 # tabWrite("texture {%s}\n"%povMatName)
3462 write_object_modifiers(scene
, ob
, file)
3463 tabWrite("rotate x*90\n")
3465 continue # Don't render proxy mesh, skip to next object
3467 if ob
.pov
.object_as
== 'PARAMETRIC':
3468 tabWrite("#declare %s = parametric {\n" % povdataname
)
3469 tabWrite("function { %s }\n" % ob
.pov
.x_eq
)
3470 tabWrite("function { %s }\n" % ob
.pov
.y_eq
)
3471 tabWrite("function { %s }\n" % ob
.pov
.z_eq
)
3473 "<%.4f,%.4f>, <%.4f,%.4f>\n"
3481 # Previous to 3.8 default max_gradient 1.0 was too slow
3482 tabWrite("max_gradient 0.001\n")
3483 if ob
.pov
.contained_by
== "sphere":
3484 tabWrite("contained_by { sphere{0, 2} }\n")
3486 tabWrite("contained_by { box{-2, 2} }\n")
3487 tabWrite("max_gradient %.6f\n" % ob
.pov
.max_gradient
)
3488 tabWrite("accuracy %.6f\n" % ob
.pov
.accuracy
)
3489 tabWrite("precompute 10 x,y,z\n")
3491 continue # Don't render proxy mesh, skip to next object
3493 if ob
.pov
.object_as
== 'POLYCIRCLE':
3494 # TODO write below macro Once:
3495 # if write_polytocircle_macro_once == 0:
3496 file.write("/****************************\n")
3497 file.write("This macro was written by 'And'.\n")
3499 "Link:(http://news.povray.org/povray.binaries.scene-files/)\n"
3501 file.write("****************************/\n")
3502 file.write("//from math.inc:\n")
3503 file.write("#macro VPerp_Adjust(V, Axis)\n")
3505 " vnormalize(vcross(vcross(Axis, V), Axis))\n"
3507 file.write("#end\n")
3508 file.write("//Then for the actual macro\n")
3510 "#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n"
3512 file.write("#local p1 = point1 + <0,0,0>;\n")
3513 file.write("#local p2 = point2 + <0,0,0>;\n")
3515 "#local clip_v = vnormalize(clip_direct + <0,0,0>);\n"
3517 file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
3518 file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
3520 ' #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n'
3522 file.write("#end\n\n")
3524 "#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n"
3526 file.write("#local d = vdot(norm, p1);\n")
3527 file.write("plane{\n")
3528 file.write("norm, d\n")
3530 file.write("#end\n\n")
3531 file.write("//polygon to circle\n")
3533 "#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n"
3535 file.write("#local n = int(_polygon_n);\n")
3536 file.write("#if(n < 3)\n")
3537 file.write(" #error " "\n")
3538 file.write("#end\n\n")
3540 "#local front_v = VPerp_Adjust(_side_face, z);\n"
3542 file.write("#if(vdot(front_v, x) >= 0)\n")
3544 " #local face_ang = acos(vdot(-y, front_v));\n"
3546 file.write("#else\n")
3548 " #local face_ang = -acos(vdot(-y, front_v));\n"
3550 file.write("#end\n")
3551 file.write("#local polyg_ext_ang = 2*pi/n;\n")
3553 "#local polyg_outer_r = _polygon_circumscribed_radius;\n"
3556 "#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n"
3558 file.write("#local cycle_r = _circle_radius;\n")
3559 file.write("#local h = _height;\n")
3561 "#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n"
3564 ' #error "error: each side length must be positive"\n'
3566 file.write("#end\n\n")
3567 file.write("#local multi = 1000;\n")
3568 file.write("#local poly_obj =\n")
3569 file.write("polynomial{\n")
3571 file.write("xyz(0,2,2): multi*1,\n")
3572 file.write("xyz(2,0,1): multi*2*h,\n")
3574 "xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n"
3576 file.write("xyz(2,0,0): multi*(-h*h),\n")
3578 "xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n"
3581 "xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n"
3583 file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n")
3585 "xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n"
3588 "xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n"
3590 file.write("sturm\n")
3592 file.write("#local mockup1 =\n")
3593 file.write("difference{\n")
3594 file.write(" cylinder{\n")
3596 " <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n"
3598 file.write(" }\n\n")
3599 file.write(" #for(i, 0, n-1)\n")
3600 file.write(" object{\n")
3601 file.write(" poly_obj\n")
3602 file.write(" inverse\n")
3604 " rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n"
3607 file.write(" object{\n")
3609 " Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n"
3612 " rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n"
3615 file.write(" #end\n")
3617 file.write("object{\n")
3618 file.write("mockup1\n")
3619 file.write("rotate <0, 0, degrees(face_ang)>\n")
3621 file.write("#end\n")
3623 ngon
= ob
.pov
.polytocircle_ngon
3624 ngonR
= ob
.pov
.polytocircle_ngonR
3625 circleR
= ob
.pov
.polytocircle_circleR
3627 "#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"
3628 % (povdataname
, ngon
, ngonR
, circleR
)
3631 continue # Don't render proxy mesh, skip to next object
3633 ############################################else try to export mesh
3635 ob
.is_instancer
== False
3636 ): # except duplis which should be instances groups for now but all duplis later
3637 if ob
.type == 'EMPTY':
3639 "\n//dummy sphere to represent Empty location\n"
3642 "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
3646 # TODO(sergey): PovRay is a render engine, so should be using dependency graph
3647 # which was given to it via render engine API.
3648 depsgraph
= bpy
.context
.evaluated_depsgraph_get()
3649 ob_eval
= ob
.evaluated_get(depsgraph
)
3651 me
= ob_eval
.to_mesh()
3653 # XXX Here? identify the specific exception for mesh object with no data
3654 # XXX So that we can write something for the dataname !
3657 # also happens when curves cant be made into meshes because of no-data
3660 importance
= ob
.pov
.importance_value
3662 me
.calc_loop_triangles()
3663 me_materials
= me
.materials
3664 me_faces
= me
.loop_triangles
[:]
3666 #me_looptris = me.loops
3668 ## otypes = ['int32'] is a 32-bit signed integer number numpy datatype
3669 #get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
3670 #faces_verts_idx = get_v_index(me_looptris)
3673 # if len(me_faces)==0:
3674 # tabWrite("\n//dummy sphere to represent empty mesh location\n")
3675 # 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)
3677 if not me
or not me_faces
:
3679 "\n//dummy sphere to represent empty mesh location\n"
3682 "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
3687 uv_layers
= me
.uv_layers
3688 if len(uv_layers
) > 0:
3689 if me
.uv_layers
.active
and uv_layers
.active
.data
:
3690 uv_layer
= uv_layers
.active
.data
3695 # vcol_layer = me.vertex_colors.active.data
3696 vcol_layer
= me
.vertex_colors
.active
.data
3697 except AttributeError:
3700 faces_verts
= [f
.vertices
[:] for f
in me_faces
]
3701 faces_normals
= [f
.normal
[:] for f
in me_faces
]
3702 verts_normals
= [v
.normal
[:] for v
in me
.vertices
]
3704 # Use named declaration to allow reference e.g. for baking. MR
3706 tabWrite("#declare %s =\n" % povdataname
)
3707 tabWrite("mesh2 {\n")
3708 tabWrite("vertex_vectors {\n")
3709 tabWrite("%d" % len(me
.vertices
)) # vert count
3711 tabStr
= tab
* tabLevel
3712 for v
in me
.vertices
:
3713 if linebreaksinlists
:
3716 tabStr
+ "<%.6f, %.6f, %.6f>" % v
.co
[:]
3721 "<%.6f, %.6f, %.6f>" % v
.co
[:]
3723 # tabWrite("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
3727 # Build unique Normal list
3729 for fi
, f
in enumerate(me_faces
):
3730 fv
= faces_verts
[fi
]
3731 # [-1] is a dummy index, use a list so we can modify in place
3732 if f
.use_smooth
: # Use vertex normals
3734 key
= verts_normals
[v
]
3735 uniqueNormals
[key
] = [-1]
3736 else: # Use face normal
3737 key
= faces_normals
[fi
]
3738 uniqueNormals
[key
] = [-1]
3740 tabWrite("normal_vectors {\n")
3741 tabWrite("%d" % len(uniqueNormals
)) # vert count
3743 tabStr
= tab
* tabLevel
3744 for no
, index
in uniqueNormals
.items():
3745 if linebreaksinlists
:
3748 tabStr
+ "<%.6f, %.6f, %.6f>" % no
3753 "<%.6f, %.6f, %.6f>" % no
3761 vertCols
= {} # Use for material colors also.
3764 # Generate unique UV's
3767 for f
in me_faces
: # me.faces in 2.7
3768 uvs
= [uv_layer
[l
].uv
[:] for l
in f
.loops
]
3771 uniqueUVs
[uv
[:]] = [-1]
3773 tabWrite("uv_vectors {\n")
3775 tabWrite("%d" % len(uniqueUVs
)) # vert count
3777 tabStr
= tab
* tabLevel
3778 for uv
, index
in uniqueUVs
.items():
3779 if linebreaksinlists
:
3781 file.write(tabStr
+ "<%.6f, %.6f>" % uv
)
3784 file.write("<%.6f, %.6f>" % uv
)
3789 # Just add 1 dummy vector, no real UV's
3790 tabWrite('1') # vert count
3791 file.write(',\n\t\t<0.0, 0.0>')
3796 if me
.vertex_colors
:
3797 # Write down vertex colors as a texture for each vertex
3798 tabWrite("texture_list {\n")
3800 "%d\n" % (len(me_faces
) * 3)
3801 ) # assumes we have only triangles
3805 "\n //Vertex colors: one simple pigment texture per vertex\n"
3807 for fi
, f
in enumerate(me_faces
):
3808 # annoying, index may be invalid
3809 material_index
= f
.material_index
3811 material
= me_materials
[material_index
]
3816 ): # and material.use_vertex_color_paint: #Always use vertex color when there is some for now
3819 vcol_layer
[l
].color
[:] for l
in f
.loops
3830 vertCols
[key
] = [VcolIdx
]
3831 if linebreaksinlists
:
3833 "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
3834 % (col
[0], col
[1], col
[2])
3838 "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
3839 % (col
[0], col
[1], col
[2])
3841 tabStr
= tab
* tabLevel
3844 # Multiply diffuse with SSS Color
3846 material
.pov_subsurface_scattering
.use
3851 material
.pov_subsurface_scattering
.color
[
3854 material
.diffuse_color
[:],
3863 vertCols
[key
] = [-1]
3865 diffuse_color
= material
.diffuse_color
[
3874 vertCols
[key
] = [-1]
3878 tabWrite("\nface_indices {\n")
3879 tabWrite("%d" % (len(me_faces
))) # faces count
3880 tabStr
= tab
* tabLevel
3882 for fi
, f
in enumerate(me_faces
):
3883 fv
= faces_verts
[fi
]
3884 material_index
= f
.material_index
3888 vcol_layer
[l
].color
[:] for l
in f
.loops
3893 or me_materials
[material_index
] is None
3895 if linebreaksinlists
:
3901 % (fv
[0], fv
[1], fv
[2])
3906 "<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2])
3909 material
= me_materials
[material_index
]
3912 ): # and material.use_vertex_color_paint:
3913 # Color per vertex - vertex color
3938 # Color per material - flat material color
3940 material
.pov_subsurface_scattering
.use
3945 material
.pov_subsurface_scattering
.color
[
3948 material
.diffuse_color
[:],
3952 diffuse_color
= material
.diffuse_color
[
3955 ci1
= ci2
= ci3
= vertCols
[
3961 # ci are zero based index so we'll subtract 1 from them
3962 if linebreaksinlists
:
3966 + "<%d,%d,%d>, %d,%d,%d"
3979 "<%d,%d,%d>, %d,%d,%d"
3993 # normal_indices indices
3994 tabWrite("normal_indices {\n")
3995 tabWrite("%d" % (len(me_faces
))) # faces count
3996 tabStr
= tab
* tabLevel
3997 for fi
, fv
in enumerate(faces_verts
):
3999 if me_faces
[fi
].use_smooth
:
4000 if linebreaksinlists
:
4007 verts_normals
[fv
[0]]
4010 verts_normals
[fv
[1]]
4013 verts_normals
[fv
[2]]
4023 verts_normals
[fv
[0]]
4026 verts_normals
[fv
[1]]
4029 verts_normals
[fv
[2]]
4034 idx
= uniqueNormals
[faces_normals
[fi
]][0]
4035 if linebreaksinlists
:
4039 + "<%d,%d,%d>" % (idx
, idx
, idx
)
4044 "<%d,%d,%d>" % (idx
, idx
, idx
)
4051 tabWrite("uv_indices {\n")
4052 tabWrite("%d" % (len(me_faces
))) # faces count
4053 tabStr
= tab
* tabLevel
4055 uvs
= [uv_layer
[l
].uv
[:] for l
in f
.loops
]
4057 if linebreaksinlists
:
4063 uniqueUVs
[uvs
[0]][0],
4064 uniqueUVs
[uvs
[1]][0],
4065 uniqueUVs
[uvs
[2]][0],
4073 uniqueUVs
[uvs
[0]][0],
4074 uniqueUVs
[uvs
[1]][0],
4075 uniqueUVs
[uvs
[2]][0],
4084 for mod
in ob
.modifiers
:
4087 if mod
.type == 'BOOLEAN':
4088 if ob
.pov
.boolean_mod
== "POV":
4090 "\tinside_vector <%.6g, %.6g, %.6g>\n"
4092 ob
.pov
.inside_vector
[0],
4093 ob
.pov
.inside_vector
[1],
4094 ob
.pov
.inside_vector
[2],
4101 material
= me
.materials
[0] # dodgy
4102 writeObjectMaterial(material
, ob
)
4106 # POV object modifiers such as
4107 # hollow / sturm / double_illuminate etc.
4108 write_object_modifiers(scene
, ob
, file)
4110 # Importance for radiosity sampling added here:
4111 tabWrite("radiosity { \n")
4112 tabWrite("importance %3g \n" % importance
)
4115 tabWrite("}\n") # End of mesh block
4117 facesMaterials
= [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
4120 if f
.material_index
not in facesMaterials
:
4121 facesMaterials
.append(f
.material_index
)
4122 # No vertex colors, so write material colors as vertex colors
4123 for i
, material
in enumerate(me_materials
):
4127 and material
.pov
.material_use_nodes
== False
4128 ): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4129 # Multiply diffuse with SSS Color
4130 if material
.pov_subsurface_scattering
.use
:
4134 material
.pov_subsurface_scattering
.color
[
4137 material
.diffuse_color
[:],
4146 vertCols
[key
] = [-1]
4148 diffuse_color
= material
.diffuse_color
[
4157 vertCols
[key
] = [-1]
4160 LocalMaterialNames
= []
4161 for col
, index
in vertCols
.items():
4163 mater
= me_materials
[col
[3]]
4164 if me_materials
is None: # XXX working?
4167 ) # not working properly,
4171 shading
.writeTextureInfluence(
4183 string_strip_hyphen
,
4190 ###################################################################
4195 tabWrite("texture_list {\n")
4196 # In case there's is no material slot, give at least one texture
4197 # (an empty one so it uses pov default)
4198 if len(vertCols
) == 0:
4199 file.write(tabStr
+ "1")
4202 tabStr
+ "%s" % (len(vertCols
))
4205 # below "material" alias, added check ob.active_material
4206 # to avoid variable referenced before assignment error
4208 material
= ob
.active_material
4210 # when no material slot exists,
4213 # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4216 and ob
.active_material
is not None
4217 and material
.pov
.material_use_nodes
== False
4219 if material
.pov
.replacement_text
!= "":
4223 % material
.pov
.replacement_text
4227 # Loop through declared materials list
4228 for cMN
in LocalMaterialNames
:
4229 if material
!= "Default":
4231 "\n texture{MAT_%s}\n" % cMN
4233 # use string_strip_hyphen(materialNames[material]))
4234 # or Something like that to clean up the above?
4235 elif material
and material
.pov
.material_use_nodes
:
4236 for index
in facesMaterials
:
4237 faceMaterial
= string_strip_hyphen(
4238 bpy
.path
.clean_name(
4239 me_materials
[index
].name
4243 "\n texture{%s}\n" % faceMaterial
4245 # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4247 file.write(" texture{}\n")
4251 tabWrite("face_indices {\n")
4252 tabWrite("%d" % (len(me_faces
))) # faces count
4253 tabStr
= tab
* tabLevel
4255 for fi
, f
in enumerate(me_faces
):
4256 fv
= faces_verts
[fi
]
4257 material_index
= f
.material_index
4261 vcol_layer
[l
].color
[:] for l
in f
.loops
4266 or me_materials
[material_index
] is None
4268 if linebreaksinlists
:
4274 % (fv
[0], fv
[1], fv
[2])
4279 "<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2])
4282 material
= me_materials
[material_index
]
4283 ci1
= ci2
= ci3
= f
.material_index
4286 ): # and material.use_vertex_color_paint:
4287 # Color per vertex - vertex color
4311 elif material
.pov
.material_use_nodes
:
4314 # Color per material - flat material color
4316 material
.pov_subsurface_scattering
.use
4321 material
.pov_subsurface_scattering
.color
[
4324 material
.diffuse_color
[:],
4328 diffuse_color
= material
.diffuse_color
[
4331 ci1
= ci2
= ci3
= vertCols
[
4338 if linebreaksinlists
:
4342 + "<%d,%d,%d>, %d,%d,%d"
4355 "<%d,%d,%d>, %d,%d,%d"
4369 # normal_indices indices
4370 tabWrite("normal_indices {\n")
4371 tabWrite("%d" % (len(me_faces
))) # faces count
4372 tabStr
= tab
* tabLevel
4373 for fi
, fv
in enumerate(faces_verts
):
4374 if me_faces
[fi
].use_smooth
:
4375 if linebreaksinlists
:
4382 verts_normals
[fv
[0]]
4385 verts_normals
[fv
[1]]
4388 verts_normals
[fv
[2]]
4398 verts_normals
[fv
[0]]
4401 verts_normals
[fv
[1]]
4404 verts_normals
[fv
[2]]
4409 idx
= uniqueNormals
[faces_normals
[fi
]][0]
4410 if linebreaksinlists
:
4414 + "<%d,%d,%d>" % (idx
, idx
, idx
)
4419 "<%d,%d,%d>" % (idx
, idx
, idx
)
4426 tabWrite("uv_indices {\n")
4427 tabWrite("%d" % (len(me_faces
))) # faces count
4428 tabStr
= tab
* tabLevel
4430 uvs
= [uv_layer
[l
].uv
[:] for l
in f
.loops
]
4432 if linebreaksinlists
:
4438 uniqueUVs
[uvs
[0]][0],
4439 uniqueUVs
[uvs
[1]][0],
4440 uniqueUVs
[uvs
[2]][0],
4448 uniqueUVs
[uvs
[0]][0],
4449 uniqueUVs
[uvs
[1]][0],
4450 uniqueUVs
[uvs
[2]][0],
4459 for mod
in ob
.modifiers
:
4462 if mod
.type == 'BOOLEAN':
4463 if ob
.pov
.boolean_mod
== "POV":
4465 "\tinside_vector <%.6g, %.6g, %.6g>\n"
4467 ob
.pov
.inside_vector
[0],
4468 ob
.pov
.inside_vector
[1],
4469 ob
.pov
.inside_vector
[2],
4476 material
= me
.materials
[0] # dodgy
4477 writeObjectMaterial(material
, ob
)
4481 # POV object modifiers such as
4482 # hollow / sturm / double_illuminate etc.
4483 write_object_modifiers(scene
, ob
, file)
4485 # Importance for radiosity sampling added here:
4486 tabWrite("radiosity { \n")
4487 tabWrite("importance %3g \n" % importance
)
4490 tabWrite("}\n") # End of mesh block
4492 ob_eval
.to_mesh_clear()
4498 ) # avoid duplicate output during introspection
4500 # matrix = global_matrix @ ob.matrix_world
4502 tabWrite("\n//--DupliObjects in %s--\n\n" % ob
.name
)
4503 # ob.dupli_list_create(scene) #deprecated in 2.8
4504 depsgraph
= bpy
.context
.evaluated_depsgraph_get()
4506 if ob
.is_modified(scene
, 'RENDER'):
4507 # modified object always unique so using object name rather than data name
4508 dup
= "#declare OB%s = union{\n" % (
4509 string_strip_hyphen(bpy
.path
.clean_name(ob
.name
))
4512 dup
= "#declare DATA%s = union{\n" % (
4513 string_strip_hyphen(bpy
.path
.clean_name(ob
.name
))
4515 for eachduplicate
in depsgraph
.object_instances
:
4517 eachduplicate
.is_instance
4518 ): # Real dupli instance filtered because original included in list since 2.8
4519 _dupname
= eachduplicate
.object.name
4520 _dupobj
= bpy
.data
.objects
[_dupname
]
4521 # BEGIN introspection for troubleshooting purposes
4522 if not "name" in dir(_dupobj
.data
):
4523 if _dupname
not in _dupnames_seen
:
4525 "WARNING: bpy.data.objects[%s].data (of type %s) has no 'name' attribute"
4526 % (_dupname
, type(_dupobj
.data
))
4528 for _thing
in dir(_dupobj
):
4534 getattr(_dupobj
, _thing
),
4537 _dupnames_seen
[_dupname
] = 1
4539 "''=> Unparseable objects so far: %s"
4543 _dupnames_seen
[_dupname
] += 1
4544 continue # don't try to parse data objects with no name attribute
4545 # END introspection for troubleshooting purposes
4546 duplidataname
= "OB" + string_strip_hyphen(
4547 bpy
.path
.clean_name(_dupobj
.data
.name
)
4550 eachduplicate
.matrix_world
.copy()
4551 ) # has to be copied to not store instance since 2.8
4552 dup
+= "\tobject {\n\t\tDATA%s\n\t\t%s\t}\n" % (
4553 string_strip_hyphen(
4554 bpy
.path
.clean_name(_dupobj
.data
.name
)
4557 ob
.matrix_world
.inverted() @ dupmatrix
4560 # add object to a list so that it is not rendered for some instance_types
4562 ob
.instance_type
not in {'COLLECTION'}
4563 and duplidataname
not in duplidata_ref
4565 duplidata_ref
.append(
4567 ) # older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))]
4569 # ob.dupli_list_clear()# just do not store any reference to instance since 2.8
4574 "WARNING: Unparseable objects in current .blend file:\n''=> %s"
4577 print("duplidata_ref = %s" % (duplidata_ref
))
4578 for data_name
, inst
in data_ref
.items():
4579 for ob_name
, matrix_str
in inst
:
4581 ob_name
not in duplidata_ref
4582 ): # .items() for a dictionary
4584 "\n//----Blender Object Name:%s----\n" % ob_name
4586 if ob
.pov
.object_as
== '':
4587 tabWrite("object { \n")
4588 tabWrite("%s\n" % data_name
)
4589 tabWrite("%s\n" % matrix_str
)
4593 for mod
in ob
.modifiers
:
4594 if mod
.type == 'BOOLEAN':
4597 if mod
.operation
== 'INTERSECT':
4598 operation
= 'intersection'
4600 operation
= mod
.operation
.lower()
4601 mod_ob_name
= string_strip_hyphen(
4602 bpy
.path
.clean_name(mod
.object.name
)
4605 global_matrix
@ mod
.object.matrix_world
4607 mod_ob_matrix
= MatrixAsPovString(
4610 tabWrite("%s { \n" % operation
)
4611 tabWrite("object { \n")
4612 tabWrite("%s\n" % data_name
)
4613 tabWrite("%s\n" % matrix_str
)
4615 tabWrite("object { \n")
4616 tabWrite("%s\n" % ('DATA' + mod_ob_name
))
4617 tabWrite("%s\n" % mod_ob_matrix
)
4622 tabWrite("object { \n")
4623 tabWrite("%s\n" % data_name
)
4624 tabWrite("%s\n" % matrix_str
)
4627 def exportWorld(world
):
4628 """write world as POV backgrounbd and sky_sphere to exported file """
4630 camera
= scene
.camera
4631 matrix
= global_matrix
@ camera
.matrix_world
4634 #############Maurice####################################
4635 # These lines added to get sky gradient (visible with PNG output)
4637 # For simple flat background:
4638 if not world
.pov
.use_sky_blend
:
4639 # Non fully transparent background could premultiply alpha and avoid anti-aliasing
4641 if render
.alpha_mode
== 'TRANSPARENT':
4643 "background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n"
4644 % (world
.pov
.horizon_color
[:])
4646 # Currently using no alpha with Sky option:
4647 elif render
.alpha_mode
== 'SKY':
4649 "background {rgbt<%.3g, %.3g, %.3g, 0>}\n"
4650 % (world
.pov
.horizon_color
[:])
4653 # XXX Does not exists anymore
4655 # tabWrite("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
4658 # For Background image textures
4662 world
.pov_texture_slots
4663 ): # risk to write several sky_spheres but maybe ok.
4665 tex
= bpy
.data
.textures
[t
.texture
]
4666 if tex
.type is not None:
4668 # XXX No enable checkbox for world textures yet (report it?)
4669 # if t and tex.type == 'IMAGE' and t.use:
4670 if tex
.type == 'IMAGE':
4671 image_filename
= path_image(tex
.image
)
4672 if tex
.image
.filepath
!= image_filename
:
4673 tex
.image
.filepath
= image_filename
4674 if image_filename
!= "" and t
.use_map_blend
:
4675 texturesBlend
= image_filename
4676 # colvalue = t.default_value
4679 # Commented below was an idea to make the Background image oriented as camera
4681 # http://news.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
4682 # Replace 4/3 by the ratio of each image found by some custom or existing
4684 # mappingBlend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees" \
4685 # "(atan((camLocation - camLookAt).x/(camLocation - " \
4686 # "camLookAt).y)) rotate x*degrees(atan((camLocation - " \
4687 # "camLookAt).y/(camLocation - camLookAt).z)) rotate y*" \
4688 # "degrees(atan((camLocation - camLookAt).z/(camLocation - " \
4689 # "camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % \
4690 # (t_blend.offset.x / 10 , t_blend.offset.y / 10 ,
4691 # t_blend.offset.z / 10, t_blend.scale.x ,
4692 # t_blend.scale.y , t_blend.scale.z))
4693 # using camera rotation valuesdirectly from blender seems much easier
4694 if t_blend
.texture_coords
== 'ANGMAP':
4697 # POV-Ray "scale" is not a number of repetitions factor, but its
4698 # inverse, a standard scale factor.
4699 # 0.5 Offset is needed relatively to scale because center of the
4700 # UV scale is 0.5,0.5 in blender and 0,0 in POV
4701 # Further Scale by 2 and translate by -1 are
4702 # required for the sky_sphere not to repeat
4705 "scale 2 scale <%.4g,%.4g,%.4g> translate -1 "
4706 "translate <%.4g,%.4g,%.4g> rotate<0,0,0> "
4708 (1.0 / t_blend
.scale
.x
),
4709 (1.0 / t_blend
.scale
.y
),
4710 (1.0 / t_blend
.scale
.z
),
4712 - (0.5 / t_blend
.scale
.x
)
4715 - (0.5 / t_blend
.scale
.y
)
4721 # The initial position and rotation of the pov camera is probably creating
4722 # the rotation offset should look into it someday but at least background
4723 # won't rotate with the camera now.
4724 # Putting the map on a plane would not introduce the skysphere distortion and
4725 # allow for better image scale matching but also some waay to chose depth and
4726 # size of the plane relative to camera.
4727 tabWrite("sky_sphere {\n")
4728 tabWrite("pigment {\n")
4730 "image_map{%s \"%s\" %s}\n"
4732 imageFormat(texturesBlend
),
4738 tabWrite("%s\n" % (mappingBlend
))
4739 # The following layered pigment opacifies to black over the texture for
4740 # transmit below 1 or otherwise adds to itself
4742 "pigment {rgb 0 transmit %s}\n" % (tex
.intensity
)
4745 # tabWrite("scale 2\n")
4746 # tabWrite("translate -1\n")
4748 # For only Background gradient
4750 if worldTexCount
== 0:
4751 if world
.pov
.use_sky_blend
:
4752 tabWrite("sky_sphere {\n")
4753 tabWrite("pigment {\n")
4754 # maybe Should follow the advice of POV doc about replacing gradient
4755 # for skysphere..5.5
4756 tabWrite("gradient y\n")
4757 tabWrite("color_map {\n")
4758 # XXX Does not exists anymore
4759 # if render.alpha_mode == 'STRAIGHT':
4760 # tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
4761 # tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
4762 if render
.alpha_mode
== 'TRANSPARENT':
4764 "[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n"
4765 % (world
.pov
.horizon_color
[:])
4767 # aa premult not solved with transmit 1
4769 "[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n"
4770 % (world
.pov
.zenith_color
[:])
4774 "[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n"
4775 % (world
.pov
.horizon_color
[:])
4778 "[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n"
4779 % (world
.pov
.zenith_color
[:])
4784 # Sky_sphere alpha (transmit) is not translating into image alpha the same
4785 # way as 'background'
4787 # if world.pov.light_settings.use_indirect_light:
4788 # scene.pov.radio_enable=1
4790 # Maybe change the above to a function copyInternalRenderer settings when
4791 # user pushes a button, then:
4792 # scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
4793 # and other such translations but maybe this would not be allowed either?
4795 ###############################################################
4797 mist
= world
.mist_settings
4801 if mist
.falloff
== 'LINEAR':
4803 "distance %.6f\n" % ((mist
.start
+ mist
.depth
) * 0.368)
4805 elif mist
.falloff
== 'QUADRATIC': # n**2 or squrt(n)?
4807 "distance %.6f\n" % ((mist
.start
+ mist
.depth
) ** 2 * 0.368)
4809 elif mist
.falloff
== 'INVERSE_QUADRATIC': # n**2 or squrt(n)?
4811 "distance %.6f\n" % ((mist
.start
+ mist
.depth
) ** 2 * 0.368)
4814 "color rgbt<%.3g, %.3g, %.3g, %.3g>\n"
4815 % (*world
.pov
.horizon_color
, 1.0 - mist
.intensity
)
4817 # tabWrite("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
4818 # tabWrite("fog_alt %.6f\n" % mist.height) #XXX right?
4819 # tabWrite("turbulence 0.2\n")
4820 # tabWrite("turb_depth 0.3\n")
4821 tabWrite("fog_type 1\n") # type2 for height
4823 if scene
.pov
.media_enable
:
4824 tabWrite("media {\n")
4826 "scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n"
4828 int(scene
.pov
.media_scattering_type
),
4829 (scene
.pov
.media_diffusion_scale
),
4830 *(scene
.pov
.media_diffusion_color
[:]),
4833 if scene
.pov
.media_scattering_type
== '5':
4834 tabWrite("eccentricity %.3g\n" % scene
.pov
.media_eccentricity
)
4837 "absorption %.12f*<%.4g, %.4g, %.4g>\n"
4839 scene
.pov
.media_absorption_scale
,
4840 *(scene
.pov
.media_absorption_color
[:]),
4844 tabWrite("samples %.d\n" % scene
.pov
.media_samples
)
4847 def exportGlobalSettings(scene
):
4848 """write all POV global settings to exported file """
4849 tabWrite("global_settings {\n")
4850 tabWrite("assumed_gamma 1.0\n")
4851 tabWrite("max_trace_level %d\n" % scene
.pov
.max_trace_level
)
4853 # Deprecated (autodetected in pov3.8):
4854 # if scene.pov.charset != 'ascii':
4855 # file.write(" charset %s\n" % scene.pov.charset)
4856 if scene
.pov
.global_settings_advanced
:
4857 if scene
.pov
.radio_enable
== False:
4858 file.write(" adc_bailout %.6f\n" % scene
.pov
.adc_bailout
)
4860 " ambient_light <%.6f,%.6f,%.6f>\n"
4861 % scene
.pov
.ambient_light
[:]
4864 " irid_wavelength <%.6f,%.6f,%.6f>\n"
4865 % scene
.pov
.irid_wavelength
[:]
4868 " max_intersections %s\n" % scene
.pov
.max_intersections
4870 file.write(" number_of_waves %s\n" % scene
.pov
.number_of_waves
)
4871 file.write(" noise_generator %s\n" % scene
.pov
.noise_generator
)
4872 if scene
.pov
.radio_enable
:
4873 tabWrite("radiosity {\n")
4874 tabWrite("adc_bailout %.4g\n" % scene
.pov
.radio_adc_bailout
)
4875 tabWrite("brightness %.4g\n" % scene
.pov
.radio_brightness
)
4876 tabWrite("count %d\n" % scene
.pov
.radio_count
)
4877 tabWrite("error_bound %.4g\n" % scene
.pov
.radio_error_bound
)
4878 tabWrite("gray_threshold %.4g\n" % scene
.pov
.radio_gray_threshold
)
4880 "low_error_factor %.4g\n" % scene
.pov
.radio_low_error_factor
4882 tabWrite("maximum_reuse %.4g\n" % scene
.pov
.radio_maximum_reuse
)
4883 tabWrite("minimum_reuse %.4g\n" % scene
.pov
.radio_minimum_reuse
)
4884 tabWrite("nearest_count %d\n" % scene
.pov
.radio_nearest_count
)
4885 tabWrite("pretrace_start %.3g\n" % scene
.pov
.radio_pretrace_start
)
4886 tabWrite("pretrace_end %.3g\n" % scene
.pov
.radio_pretrace_end
)
4887 tabWrite("recursion_limit %d\n" % scene
.pov
.radio_recursion_limit
)
4888 tabWrite("always_sample %d\n" % scene
.pov
.radio_always_sample
)
4889 tabWrite("normal %d\n" % scene
.pov
.radio_normal
)
4890 tabWrite("media %d\n" % scene
.pov
.radio_media
)
4891 tabWrite("subsurface %d\n" % scene
.pov
.radio_subsurface
)
4896 for material
in bpy
.data
.materials
:
4897 if material
.pov_subsurface_scattering
.use
and onceSss
:
4898 # In pov, the scale has reversed influence compared to blender. these number
4899 # should correct that
4901 "mm_per_unit %.6f\n"
4902 % (material
.pov_subsurface_scattering
.scale
* 1000.0)
4904 # 1000 rather than scale * (-100.0) + 15.0))
4906 # In POV-Ray, the scale factor for all subsurface shaders needs to be the same
4908 # formerly sslt_samples were multiplied by 100 instead of 10
4910 11 - material
.pov_subsurface_scattering
.error_threshold
4914 "subsurface { samples %d, %d }\n"
4915 % (sslt_samples
, sslt_samples
/ 10)
4919 if world
and onceAmbient
:
4921 "ambient_light rgb<%.3g, %.3g, %.3g>\n"
4922 % world
.pov
.ambient_color
[:]
4926 if scene
.pov
.photon_enable
:
4927 if oncePhotons
and (
4928 material
.pov
.refraction_type
== "2"
4929 or material
.pov
.photons_reflection
== True
4931 tabWrite("photons {\n")
4932 tabWrite("spacing %.6f\n" % scene
.pov
.photon_spacing
)
4934 "max_trace_level %d\n"
4935 % scene
.pov
.photon_max_trace_level
4938 "adc_bailout %.3g\n" % scene
.pov
.photon_adc_bailout
4943 scene
.pov
.photon_gather_min
,
4944 scene
.pov
.photon_gather_max
,
4947 if scene
.pov
.photon_map_file_save_load
in {'save'}:
4948 filePhName
= 'Photon_map_file.ph'
4949 if scene
.pov
.photon_map_file
!= '':
4950 filePhName
= scene
.pov
.photon_map_file
+ '.ph'
4951 filePhDir
= tempfile
.gettempdir()
4952 path
= bpy
.path
.abspath(scene
.pov
.photon_map_dir
)
4953 if os
.path
.exists(path
):
4955 fullFileName
= os
.path
.join(filePhDir
, filePhName
)
4956 tabWrite('save_file "%s"\n' % fullFileName
)
4957 scene
.pov
.photon_map_file
= fullFileName
4958 if scene
.pov
.photon_map_file_save_load
in {'load'}:
4959 fullFileName
= bpy
.path
.abspath(
4960 scene
.pov
.photon_map_file
4962 if os
.path
.exists(fullFileName
):
4963 tabWrite('load_file "%s"\n' % fullFileName
)
4969 def exportCustomCode():
4970 """write all POV user defined custom code to exported file """
4971 # Write CurrentAnimation Frame for use in Custom POV Code
4973 "#declare CURFRAMENUM = %d;\n" % bpy
.context
.scene
.frame_current
4975 # Change path and uncomment to add an animated include file by hand:
4977 "//#include \"/home/user/directory/animation_include_file.inc\"\n"
4979 for txt
in bpy
.data
.texts
:
4980 if txt
.pov
.custom_code
== 'both':
4981 # Why are the newlines needed?
4983 file.write(txt
.as_string())
4986 # sel = renderable_objects(scene) #removed for booleans
4989 "//----------------------------------------------\n"
4990 "//--Exported with POV-Ray exporter for Blender--\n"
4991 "//----------------------------------------------\n\n"
4993 file.write("#version 3.7;\n") #Switch below as soon as 3.8 beta gets easy linked
4994 #file.write("#version 3.8;\n")
4996 "#declare Default_texture = texture{pigment {rgb 0.8} "
4997 "finish {brilliance 3.8} }\n\n"
5000 file.write("\n//--Global settings--\n\n")
5002 exportGlobalSettings(scene
)
5005 file.write("\n//--Custom Code--\n\n")
5009 file.write("\n//--Patterns Definitions--\n\n")
5010 LocalPatternNames
= []
5011 for texture
in bpy
.data
.textures
: # ok?
5012 if texture
.users
> 0:
5013 currentPatName
= string_strip_hyphen(
5014 bpy
.path
.clean_name(texture
.name
)
5016 # string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
5017 LocalPatternNames
.append(currentPatName
)
5018 # use above list to prevent writing texture instances several times and assign in mats?
5020 texture
.type not in {'NONE', 'IMAGE'}
5021 and texture
.pov
.tex_pattern_type
== 'emulator'
5023 texture
.type in {'NONE', 'IMAGE'}
5024 and texture
.pov
.tex_pattern_type
!= 'emulator'
5026 file.write("\n#declare PAT_%s = \n" % currentPatName
)
5027 file.write(shading
.exportPattern(texture
, string_strip_hyphen
))
5030 file.write("\n//--Background--\n\n")
5032 exportWorld(scene
.world
)
5035 file.write("\n//--Cameras--\n\n")
5040 file.write("\n//--Lamps--\n\n")
5042 for ob
in bpy
.data
.objects
:
5043 if ob
.type == 'MESH':
5044 for mod
in ob
.modifiers
:
5045 if mod
.type == 'BOOLEAN':
5046 if mod
.object not in csg_list
:
5047 csg_list
.append(mod
.object)
5050 sel
= no_renderable_objects(scene
)
5051 exportMeshes(scene
, sel
, csg
)
5054 sel
= renderable_objects(scene
)
5057 [L
for L
in sel
if (L
.type == 'LIGHT' and L
.pov
.object_as
!= 'RAINBOW')]
5061 file.write("\n//--Rainbows--\n\n")
5063 [L
for L
in sel
if (L
.type == 'LIGHT' and L
.pov
.object_as
== 'RAINBOW')]
5067 file.write("\n//--Special Curves--\n\n")
5069 if c
.is_modified(scene
, 'RENDER'):
5070 continue # don't export as pov curves objects with modifiers, but as mesh
5071 elif c
.type == 'CURVE' and (
5072 c
.pov
.curveshape
in {'lathe', 'sphere_sweep', 'loft', 'birail'}
5074 exportCurves(scene
, c
)
5077 file.write("\n//--Material Definitions--\n\n")
5078 # write a default pigment for objects with no material (comment out to show black)
5079 file.write("#default{ pigment{ color srgb 0.8 }}\n")
5080 # Convert all materials to strings we can access directly per vertex.
5082 shading
.writeMaterial(
5092 ) # default material
5093 for material
in bpy
.data
.materials
:
5094 if material
.users
> 0:
5095 if material
.pov
.material_use_nodes
:
5096 ntree
= material
.node_tree
5097 povMatName
= string_strip_hyphen(
5098 bpy
.path
.clean_name(material
.name
)
5100 if len(ntree
.nodes
) == 0:
5102 '#declare %s = texture {%s}\n' % (povMatName
, color
)
5105 shading
.write_nodes(scene
, povMatName
, ntree
, file)
5107 for node
in ntree
.nodes
:
5109 if node
.bl_idname
== "PovrayOutputNode":
5110 if node
.inputs
["Texture"].is_linked
:
5111 for link
in ntree
.links
:
5113 link
.to_node
.bl_idname
5114 == "PovrayOutputNode"
5117 string_strip_hyphen(
5118 bpy
.path
.clean_name(
5122 + "_%s" % povMatName
5126 '#declare %s = texture {%s}\n'
5127 % (povMatName
, color
)
5130 shading
.writeMaterial(
5141 # attributes are all the variables needed by the other python file...
5145 exportMeta([m
for m
in sel
if m
.type == 'META'])
5148 file.write("//--Mesh objects--\n")
5151 #tbefore = time.time()
5152 exportMeshes(scene
, sel
, csg
)
5153 #totime = time.time() - tbefore
5154 #print("exportMeshes took" + str(totime))
5156 # What follow used to happen here:
5158 # exportWorld(scene.world)
5159 # exportGlobalSettings(scene)
5160 # MR:..and the order was important for implementing pov 3.7 baking
5161 # (mesh camera) comment for the record
5162 # CR: Baking should be a special case than. If "baking", than we could change the order.
5164 # print("pov file closed %s" % file.closed)
5166 # print("pov file closed %s" % file.closed)
5170 scene
, filename_ini
, filename_log
, filename_pov
, filename_image
5172 """Write ini file."""
5173 feature_set
= bpy
.context
.preferences
.addons
[
5175 ].preferences
.branch_feature_set_povray
5176 using_uberpov
= feature_set
== 'uberpov'
5177 # scene = bpy.data.scenes[0]
5178 scene
= bpy
.context
.scene
5179 render
= scene
.render
5181 x
= int(render
.resolution_x
* render
.resolution_percentage
* 0.01)
5182 y
= int(render
.resolution_y
* render
.resolution_percentage
* 0.01)
5184 file = open(filename_ini
, "w")
5185 file.write("Version=3.8\n")
5186 # write povray text stream to temporary file of same name with _log suffix
5187 # file.write("All_File='%s'\n" % filename_log)
5188 # DEBUG.OUT log if none specified:
5189 file.write("All_File=1\n")
5191 file.write("Input_File_Name='%s'\n" % filename_pov
)
5192 file.write("Output_File_Name='%s'\n" % filename_image
)
5194 file.write("Width=%d\n" % x
)
5195 file.write("Height=%d\n" % y
)
5198 if render
.use_border
:
5199 file.write("Start_Column=%4g\n" % render
.border_min_x
)
5200 file.write("End_Column=%4g\n" % (render
.border_max_x
))
5202 file.write("Start_Row=%4g\n" % (1.0 - render
.border_max_y
))
5203 file.write("End_Row=%4g\n" % (1.0 - render
.border_min_y
))
5206 "Bounding_Method=2\n"
5207 ) # The new automatic BSP is faster in most scenes
5209 # Activated (turn this back off when better live exchange is done between the two programs
5210 # (see next comment)
5211 file.write("Display=1\n")
5212 file.write("Pause_When_Done=0\n")
5213 # PNG, with POV-Ray 3.7, can show background color with alpha. In the long run using the
5214 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
5215 file.write("Output_File_Type=N\n")
5216 # file.write("Output_File_Type=T\n") # TGA, best progressive loading
5217 file.write("Output_Alpha=1\n")
5219 if scene
.pov
.antialias_enable
:
5220 # method 2 (recursive) with higher max subdiv forced because no mipmapping in POV-Ray
5221 # needs higher sampling.
5222 # aa_mapping = {"5": 2, "8": 3, "11": 4, "16": 5}
5224 method
= {"0": 1, "1": 2, "2": 3}
5226 method
= {"0": 1, "1": 2, "2": 2}
5227 file.write("Antialias=on\n")
5228 file.write("Antialias_Depth=%d\n" % scene
.pov
.antialias_depth
)
5229 file.write("Antialias_Threshold=%.3g\n" % scene
.pov
.antialias_threshold
)
5230 if using_uberpov
and scene
.pov
.antialias_method
== '2':
5232 "Sampling_Method=%s\n" % method
[scene
.pov
.antialias_method
]
5235 "Antialias_Confidence=%.3g\n" % scene
.pov
.antialias_confidence
5239 "Sampling_Method=%s\n" % method
[scene
.pov
.antialias_method
]
5241 file.write("Antialias_Gamma=%.3g\n" % scene
.pov
.antialias_gamma
)
5242 if scene
.pov
.jitter_enable
:
5243 file.write("Jitter=on\n")
5244 file.write("Jitter_Amount=%3g\n" % scene
.pov
.jitter_amount
)
5246 file.write("Jitter=off\n") # prevent animation flicker
5249 file.write("Antialias=off\n")
5250 # print("ini file closed %s" % file.closed)
5252 # print("ini file closed %s" % file.closed)
5255 class PovrayRender(bpy
.types
.RenderEngine
):
5256 """Define the external renderer"""
5258 bl_idname
= 'POVRAY_RENDER'
5259 bl_label
= "Persitence Of Vision"
5260 bl_use_shading_nodes_custom
= False
5264 def _locate_binary():
5265 """Identify POV engine"""
5266 addon_prefs
= bpy
.context
.preferences
.addons
[__package__
].preferences
5268 # Use the system preference if its set.
5269 pov_binary
= addon_prefs
.filepath_povray
5271 if os
.path
.exists(pov_binary
):
5275 "User Preferences path to povray %r NOT FOUND, checking $PATH"
5280 # assume if there is a 64bit binary that the user has a 64bit capable OS
5281 if sys
.platform
[:3] == "win":
5284 win_reg_key
= winreg
.OpenKey(
5285 winreg
.HKEY_CURRENT_USER
, "Software\\POV-Ray\\v3.7\\Windows"
5287 win_home
= winreg
.QueryValueEx(win_reg_key
, "Home")[0]
5289 # First try 64bits UberPOV
5290 pov_binary
= os
.path
.join(win_home
, "bin", "uberpov64.exe")
5291 if os
.path
.exists(pov_binary
):
5294 # Then try 64bits POV
5295 pov_binary
= os
.path
.join(win_home
, "bin", "pvengine64.exe")
5296 if os
.path
.exists(pov_binary
):
5299 # Then try 32bits UberPOV
5300 pov_binary
= os
.path
.join(win_home
, "bin", "uberpov32.exe")
5301 if os
.path
.exists(pov_binary
):
5304 # Then try 32bits POV
5305 pov_binary
= os
.path
.join(win_home
, "bin", "pvengine.exe")
5306 if os
.path
.exists(pov_binary
):
5309 # search the path all os's
5310 pov_binary_default
= "povray"
5312 os_path_ls
= os
.getenv("PATH").split(':') + [""]
5314 for dir_name
in os_path_ls
:
5315 pov_binary
= os
.path
.join(dir_name
, pov_binary_default
)
5316 if os
.path
.exists(pov_binary
):
5320 def _export(self
, depsgraph
, povPath
, renderImagePath
):
5321 """gather all necessary output files paths user defined and auto generated and export there"""
5324 scene
= bpy
.context
.scene
5325 if scene
.pov
.tempfiles_enable
:
5326 self
._temp
_file
_in
= tempfile
.NamedTemporaryFile(
5327 suffix
=".pov", delete
=False
5329 # PNG with POV 3.7, can show the background color with alpha. In the long run using the
5330 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
5331 self
._temp
_file
_out
= tempfile
.NamedTemporaryFile(
5332 suffix
=".png", delete
=False
5334 # self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
5335 self
._temp
_file
_ini
= tempfile
.NamedTemporaryFile(
5336 suffix
=".ini", delete
=False
5338 self
._temp
_file
_log
= os
.path
.join(
5339 tempfile
.gettempdir(), "alltext.out"
5342 self
._temp
_file
_in
= povPath
+ ".pov"
5343 # PNG with POV 3.7, can show the background color with alpha. In the long run using the
5344 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
5345 self
._temp
_file
_out
= renderImagePath
+ ".png"
5346 # self._temp_file_out = renderImagePath + ".tga"
5347 self
._temp
_file
_ini
= povPath
+ ".ini"
5348 logPath
= bpy
.path
.abspath(scene
.pov
.scene_path
).replace('\\', '/')
5349 self
._temp
_file
_log
= os
.path
.join(logPath
, "alltext.out")
5351 self._temp_file_in = "/test.pov"
5352 # PNG with POV 3.7, can show the background color with alpha. In the long run using the
5353 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
5354 self._temp_file_out = "/test.png"
5355 #self._temp_file_out = "/test.tga"
5356 self._temp_file_ini = "/test.ini"
5358 if scene
.pov
.text_block
== "":
5360 def info_callback(txt
):
5361 self
.update_stats("", "POV-Ray 3.7: " + txt
)
5363 # os.makedirs(user_dir, exist_ok=True) # handled with previews
5364 os
.makedirs(preview_dir
, exist_ok
=True)
5366 write_pov(self
._temp
_file
_in
, scene
, info_callback
)
5370 def _render(self
, depsgraph
):
5371 """Export necessary files and render image."""
5372 scene
= bpy
.context
.scene
5374 os
.remove(self
._temp
_file
_out
) # so as not to load the old file
5378 pov_binary
= PovrayRender
._locate
_binary
()
5381 "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
5387 self
._temp
_file
_ini
,
5388 self
._temp
_file
_log
,
5390 self
._temp
_file
_out
,
5393 print("***-STARTING-***")
5397 if scene
.pov
.command_line_switches
!= "":
5398 for newArg
in scene
.pov
.command_line_switches
.split(" "):
5399 extra_args
.append(newArg
)
5401 self
._is
_windows
= False
5402 if sys
.platform
[:3] == "win":
5403 self
._is
_windows
= True
5404 if "/EXIT" not in extra_args
and not scene
.pov
.pov_editor
:
5405 extra_args
.append("/EXIT")
5407 # added -d option to prevent render window popup which leads to segfault on linux
5408 extra_args
.append("-d")
5412 self
._process
= subprocess
.Popen(
5413 [pov_binary
, self
._temp
_file
_ini
] + extra_args
,
5414 stdout
=subprocess
.PIPE
,
5415 stderr
=subprocess
.STDOUT
,
5419 print("POV-Ray 3.7: could not execute '%s'" % pov_binary
)
5422 traceback
.print_exc()
5423 print("***-DONE-***")
5427 print("Engine ready!...")
5428 print("Command line arguments passed: " + str(extra_args
))
5431 # Now that we have a valid process
5434 """Delete temp files and unpacked ones"""
5435 for f
in (self
._temp
_file
_in
, self
._temp
_file
_ini
, self
._temp
_file
_out
):
5441 # Wait a bit before retrying file might be still in use by Blender,
5442 # and Windows does not know how to delete a file in use!
5443 time
.sleep(self
.DELAY
)
5444 for i
in unpacked_images
:
5450 # Wait a bit before retrying file might be still in use by Blender,
5451 # and Windows does not know how to delete a file in use!
5452 time
.sleep(self
.DELAY
)
5454 def render(self
, depsgraph
):
5455 """Export necessary files from text editor and render image."""
5458 scene
= bpy
.context
.scene
5460 x
= int(r
.resolution_x
* r
.resolution_percentage
* 0.01)
5461 y
= int(r
.resolution_y
* r
.resolution_percentage
* 0.01)
5462 print("***INITIALIZING***")
5464 # This makes some tests on the render, returning True if all goes good, and False if
5465 # it was finished one way or the other.
5466 # It also pauses the script (time.sleep())
5468 time
.sleep(self
.DELAY
)
5470 # User interrupts the rendering
5471 if self
.test_break():
5473 self
._process
.terminate()
5474 print("***POV INTERRUPTED***")
5479 poll_result
= self
._process
.poll()
5480 # POV process is finisehd, one way or the other
5481 if poll_result
is not None:
5483 print("***POV PROCESS FAILED : %s ***" % poll_result
)
5484 self
.update_stats("", "POV-Ray 3.7: Failed")
5489 if bpy
.context
.scene
.pov
.text_block
!= "":
5490 if scene
.pov
.tempfiles_enable
:
5491 self
._temp
_file
_in
= tempfile
.NamedTemporaryFile(
5492 suffix
=".pov", delete
=False
5494 self
._temp
_file
_out
= tempfile
.NamedTemporaryFile(
5495 suffix
=".png", delete
=False
5497 # self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
5498 self
._temp
_file
_ini
= tempfile
.NamedTemporaryFile(
5499 suffix
=".ini", delete
=False
5501 self
._temp
_file
_log
= os
.path
.join(
5502 tempfile
.gettempdir(), "alltext.out"
5505 povPath
= scene
.pov
.text_block
5506 renderImagePath
= os
.path
.splitext(povPath
)[0]
5507 self
._temp
_file
_out
= os
.path
.join(preview_dir
, renderImagePath
)
5508 self
._temp
_file
_in
= os
.path
.join(preview_dir
, povPath
)
5509 self
._temp
_file
_ini
= os
.path
.join(
5511 (os
.path
.splitext(self
._temp
_file
_in
)[0] + ".INI"),
5513 self
._temp
_file
_log
= os
.path
.join(preview_dir
, "alltext.out")
5517 os.remove(self._temp_file_in) # so as not to load the old file
5521 print(scene
.pov
.text_block
)
5522 text
= bpy
.data
.texts
[scene
.pov
.text_block
]
5523 file = open("%s" % self
._temp
_file
_in
, "w")
5524 # Why are the newlines needed?
5526 file.write(text
.as_string())
5530 # has to be called to update the frame on exporting animations
5531 scene
.frame_set(scene
.frame_current
)
5533 pov_binary
= PovrayRender
._locate
_binary
()
5537 "POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed"
5541 # start ini UI options export
5543 "", "POV-Ray 3.7: Exporting ini options from Blender"
5548 self
._temp
_file
_ini
,
5549 self
._temp
_file
_log
,
5551 self
._temp
_file
_out
,
5554 print("***-STARTING-***")
5558 if scene
.pov
.command_line_switches
!= "":
5559 for newArg
in scene
.pov
.command_line_switches
.split(" "):
5560 extra_args
.append(newArg
)
5562 if sys
.platform
[:3] == "win":
5563 if "/EXIT" not in extra_args
and not scene
.pov
.pov_editor
:
5564 extra_args
.append("/EXIT")
5566 # added -d option to prevent render window popup which leads to segfault on linux
5567 extra_args
.append("-d")
5572 sys
.platform
[:3] != "win" and scene
.pov
.sdl_window_enable
5573 ): # segfault on linux == False !!!
5574 env
= {'POV_DISPLAY_SCALED': 'off'}
5575 env
.update(os
.environ
)
5576 self
._process
= subprocess
.Popen(
5577 [pov_binary
, self
._temp
_file
_ini
],
5578 stdout
=subprocess
.PIPE
,
5579 stderr
=subprocess
.STDOUT
,
5583 self
._process
= subprocess
.Popen(
5584 [pov_binary
, self
._temp
_file
_ini
] + extra_args
,
5585 stdout
=subprocess
.PIPE
,
5586 stderr
=subprocess
.STDOUT
,
5590 print("POV-Ray 3.7: could not execute '%s'" % pov_binary
)
5593 traceback
.print_exc()
5594 print("***-DONE-***")
5598 print("Engine ready!...")
5599 print("Command line arguments passed: " + str(extra_args
))
5601 self
.update_stats("", "POV-Ray 3.7: Parsing File")
5603 # Indented in main function now so repeated here but still not working
5604 # to bring back render result to its buffer
5606 if os
.path
.exists(self
._temp
_file
_out
):
5607 xmin
= int(r
.border_min_x
* x
)
5608 ymin
= int(r
.border_min_y
* y
)
5609 xmax
= int(r
.border_max_x
* x
)
5610 ymax
= int(r
.border_max_y
* y
)
5611 result
= self
.begin_result(0, 0, x
, y
)
5612 lay
= result
.layers
[0]
5614 time
.sleep(self
.DELAY
)
5616 lay
.load_from_file(self
._temp
_file
_out
)
5617 except RuntimeError:
5618 print("***POV ERROR WHILE READING OUTPUT FILE***")
5619 self
.end_result(result
)
5620 # print(self._temp_file_log) #bring the pov log to blender console with proper path?
5623 ) as f
: # The with keyword automatically closes the file when you are done
5626 self
.update_stats("", "")
5628 if scene
.pov
.tempfiles_enable
or scene
.pov
.deletefiles_enable
:
5633 ## if r.image_settings.file_format == 'OPENEXR':
5635 ## render.image_settings.color_mode = 'RGBA'
5638 ## r.image_settings.file_format = 'TARGA'
5639 ## r.image_settings.color_mode = 'RGBA'
5641 blendSceneName
= bpy
.data
.filepath
.split(os
.path
.sep
)[-1].split(
5646 renderImagePath
= ""
5648 # has to be called to update the frame on exporting animations
5649 scene
.frame_set(scene
.frame_current
)
5651 if not scene
.pov
.tempfiles_enable
:
5654 povPath
= bpy
.path
.abspath(scene
.pov
.scene_path
).replace(
5658 if bpy
.data
.is_saved
:
5659 povPath
= bpy
.path
.abspath("//")
5661 povPath
= tempfile
.gettempdir()
5662 elif povPath
.endswith("/"):
5664 povPath
= bpy
.path
.abspath("//")
5666 povPath
= bpy
.path
.abspath(scene
.pov
.scene_path
)
5668 if not os
.path
.exists(povPath
):
5670 os
.makedirs(povPath
)
5674 traceback
.print_exc()
5677 "POV-Ray 3.7: Cannot create scenes directory: %r"
5682 "POV-Ray 3.7: Cannot create scenes directory %r"
5689 # Bug in POV-Ray RC3
5690 renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
5691 if renderImagePath == "":
5692 if bpy.data.is_saved:
5693 renderImagePath = bpy.path.abspath("//")
5695 renderImagePath = tempfile.gettempdir()
5696 #print("Path: " + renderImagePath)
5697 elif path.endswith("/"):
5698 if renderImagePath == "/":
5699 renderImagePath = bpy.path.abspath("//")
5701 renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
5702 if not os.path.exists(path):
5703 print("POV-Ray 3.7: Cannot find render image directory")
5704 self.update_stats("", "POV-Ray 3.7: Cannot find render image directory")
5710 if scene
.pov
.scene_name
== "":
5711 if blendSceneName
!= "":
5712 povSceneName
= blendSceneName
5714 povSceneName
= "untitled"
5716 povSceneName
= scene
.pov
.scene_name
5717 if os
.path
.isfile(povSceneName
):
5718 povSceneName
= os
.path
.basename(povSceneName
)
5719 povSceneName
= povSceneName
.split('/')[-1].split('\\')[-1]
5720 if not povSceneName
:
5721 print("POV-Ray 3.7: Invalid scene name")
5722 self
.update_stats("", "POV-Ray 3.7: Invalid scene name")
5725 povSceneName
= os
.path
.splitext(povSceneName
)[0]
5727 print("Scene name: " + povSceneName
)
5728 print("Export path: " + povPath
)
5729 povPath
= os
.path
.join(povPath
, povSceneName
)
5730 povPath
= os
.path
.realpath(povPath
)
5732 # for now this has to be the same like the pov output. Bug in POV-Ray RC3.
5733 # renderImagePath = renderImagePath + "\\" + povSceneName
5734 renderImagePath
= povPath
# Bugfix for POV-Ray RC3 bug
5735 # renderImagePath = os.path.realpath(renderImagePath) # Bugfix for POV-Ray RC3 bug
5737 # print("Export path: %s" % povPath)
5738 # print("Render Image path: %s" % renderImagePath)
5741 self
.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
5742 self
._export
(depsgraph
, povPath
, renderImagePath
)
5743 self
.update_stats("", "POV-Ray 3.7: Parsing File")
5745 if not self
._render
(depsgraph
):
5746 self
.update_stats("", "POV-Ray 3.7: Not found")
5750 # compute resolution
5751 # x = int(r.resolution_x * r.resolution_percentage * 0.01)
5752 # y = int(r.resolution_y * r.resolution_percentage * 0.01)
5754 # Wait for the file to be created
5755 # XXX This is no more valid, as 3.7 always creates output file once render is finished!
5756 parsing
= re
.compile(br
"= \[Parsing\.\.\.\] =")
5757 rendering
= re
.compile(br
"= \[Rendering\.\.\.\] =")
5758 percent
= re
.compile(r
"\(([0-9]{1,3})%\)")
5759 # print("***POV WAITING FOR FILE***")
5764 # POV in Windows did not output its stdout/stderr, it displayed them in its GUI
5765 # But now writes file
5766 if self
._is
_windows
:
5767 self
.update_stats("", "POV-Ray 3.7: Rendering File")
5769 t_data
= self
._process
.stdout
.read(10000)
5774 # XXX This is working for UNIX, not sure whether it might need adjustments for
5776 # First replace is for windows
5779 .replace('\\r\\n', '\\n')
5780 .replace('\\r', '\r')
5782 lines
= t_data
.split('\\n')
5783 last_line
+= lines
[0]
5784 lines
[0] = last_line
5785 print('\n'.join(lines
), end
="")
5786 last_line
= lines
[-1]
5788 if rendering
.search(data
):
5789 _pov_rendering
= True
5790 match
= percent
.findall(str(data
))
5794 "POV-Ray 3.7: Rendering File (%s%%)"
5798 self
.update_stats("", "POV-Ray 3.7: Rendering File")
5800 elif parsing
.search(data
):
5801 self
.update_stats("", "POV-Ray 3.7: Parsing File")
5803 if os
.path
.exists(self
._temp
_file
_out
):
5804 # print("***POV FILE OK***")
5805 # self.update_stats("", "POV-Ray 3.7: Rendering")
5809 xmin
= int(r
.border_min_x
* x
)
5810 ymin
= int(r
.border_min_y
* y
)
5811 xmax
= int(r
.border_max_x
* x
)
5812 ymax
= int(r
.border_max_y
* y
)
5814 # print("***POV UPDATING IMAGE***")
5815 result
= self
.begin_result(0, 0, x
, y
)
5816 # XXX, tests for border render.
5817 # result = self.begin_result(xmin, ymin, xmax - xmin, ymax - ymin)
5818 # result = self.begin_result(0, 0, xmax - xmin, ymax - ymin)
5819 lay
= result
.layers
[0]
5821 # This assumes the file has been fully written We wait a bit, just in case!
5822 time
.sleep(self
.DELAY
)
5824 lay
.load_from_file(self
._temp
_file
_out
)
5825 # XXX, tests for border render.
5826 # lay.load_from_file(self._temp_file_out, xmin, ymin)
5827 except RuntimeError:
5828 print("***POV ERROR WHILE READING OUTPUT FILE***")
5830 # Not needed right now, might only be useful if we find a way to use temp raw output of
5831 # pov 3.7 (in which case it might go under _test_wait()).
5834 # possible the image wont load early on.
5836 lay.load_from_file(self._temp_file_out)
5837 # XXX, tests for border render.
5838 #lay.load_from_file(self._temp_file_out, xmin, ymin)
5839 #lay.load_from_file(self._temp_file_out, xmin, ymin)
5840 except RuntimeError:
5843 # Update while POV-Ray renders
5845 # print("***POV RENDER LOOP***")
5847 # test if POV-Ray exists
5848 if self._process.poll() is not None:
5849 print("***POV PROCESS FINISHED***")
5854 if self.test_break():
5856 self._process.terminate()
5857 print("***POV PROCESS INTERRUPTED***")
5863 # Would be nice to redirect the output
5864 # stdout_value, stderr_value = self._process.communicate() # locks
5866 # check if the file updated
5867 new_size = os.path.getsize(self._temp_file_out)
5869 if new_size != prev_size:
5871 prev_size = new_size
5873 time.sleep(self.DELAY)
5876 self
.end_result(result
)
5879 print("***POV FILE NOT FOUND***")
5881 print("***POV FILE FINISHED***")
5883 # print(filename_log) #bring the pov log to blender console with proper path?
5885 self
._temp
_file
_log
,
5887 ) as f
: # The with keyword automatically closes the file when you are done
5889 #if isinstance(msg, str):
5893 #if type(msg) == bytes:
5894 #stdmsg = msg.split('\n')
5895 #stdmsg = msg.encode('utf-8', "replace")
5896 #stdmsg = msg.encode("utf-8", "replace")
5898 #stdmsg = msg.decode(encoding)
5900 #msg.encode('utf-8').decode('utf-8')
5902 # Also print to the interactive console used in POV centric workspace
5903 # To do: get a grip on new line encoding
5904 # and make this a function to be used elsewhere
5905 for win
in bpy
.context
.window_manager
.windows
:
5906 if win
.screen
!= None:
5908 for area
in scr
.areas
:
5909 if area
.type == 'CONSOLE':
5911 #ctx = {'window': win, 'screen': scr, 'area':area}#bpy.context.copy()
5914 ctx
['region'] = area
.regions
[-1]
5915 ctx
['space_data'] = area
.spaces
.active
5916 ctx
['screen'] = scr
#C.screen
5919 #bpy.ops.console.banner(ctx, text = "Hello world")
5920 bpy
.ops
.console
.clear_line(ctx
)
5921 stdmsg
= msg
.split('\n') #XXX todo , test and see
5923 bpy
.ops
.console
.insert(ctx
, text
= i
)
5925 self
.update_stats("", "")
5927 if scene
.pov
.tempfiles_enable
or scene
.pov
.deletefiles_enable
:
5930 sound_on
= bpy
.context
.preferences
.addons
[
5932 ].preferences
.use_sounds
5934 if sys
.platform
[:3] == "win" and sound_on
:
5935 # Could not find tts Windows command so playing beeps instead :-)
5936 # "Korobeiniki"(Коробе́йники)
5937 # aka "A-Type" Tetris theme
5939 winsound
.Beep(494,250) #B
5940 winsound
.Beep(370,125) #F
5941 winsound
.Beep(392,125) #G
5942 winsound
.Beep(440,250) #A
5943 winsound
.Beep(392,125) #G
5944 winsound
.Beep(370,125) #F#
5945 winsound
.Beep(330,275) #E
5946 winsound
.Beep(330,125) #E
5947 winsound
.Beep(392,125) #G
5948 winsound
.Beep(494,275) #B
5949 winsound
.Beep(440,125) #A
5950 winsound
.Beep(392,125) #G
5951 winsound
.Beep(370,275) #F
5952 winsound
.Beep(370,125) #F
5953 winsound
.Beep(392,125) #G
5954 winsound
.Beep(440,250) #A
5955 winsound
.Beep(494,250) #B
5956 winsound
.Beep(392,250) #G
5957 winsound
.Beep(330,350) #E
5959 winsound
.Beep(440,250) #A
5960 winsound
.Beep(440,150) #A
5961 winsound
.Beep(523,125) #D8
5962 winsound
.Beep(659,250) #E8
5963 winsound
.Beep(587,125) #D8
5964 winsound
.Beep(523,125) #C8
5965 winsound
.Beep(494,250) #B
5966 winsound
.Beep(494,125) #B
5967 winsound
.Beep(392,125) #G
5968 winsound
.Beep(494,250) #B
5969 winsound
.Beep(440,150) #A
5970 winsound
.Beep(392,125) #G
5971 winsound
.Beep(370,250) #F#
5972 winsound
.Beep(370,125) #F#
5973 winsound
.Beep(392,125) #G
5974 winsound
.Beep(440,250) #A
5975 winsound
.Beep(494,250) #B
5976 winsound
.Beep(392,250) #G
5977 winsound
.Beep(330,300) #E
5979 #Does Linux support say command?
5980 elif sys
.platform
[:3] != "win" :
5981 finished_render_message
= "\'Render completed\'"
5982 # We don't want the say command to block Python,
5983 # so we add an ampersand after the message
5984 os
.system("say %s &" % (finished_render_message
))
5986 ##################################################################################
5987 #################################Operators########################################
5988 ##################################################################################
5989 class RenderPovTexturePreview(Operator
):
5990 """Export only files necessary to texture preview and render image"""
5992 bl_idname
= "tex.preview_update"
5993 bl_label
= "Update preview"
5995 def execute(self
, context
):
5997 bpy
.context
.object.active_material
.active_texture
6000 string_strip_hyphen(bpy
.path
.clean_name(tex
.name
)) + "_prev"
6003 ## Make sure Preview directory exists and is empty
6004 if not os
.path
.isdir(preview_dir
):
6005 os
.mkdir(preview_dir
)
6007 iniPrevFile
= os
.path
.join(preview_dir
, "Preview.ini")
6008 inputPrevFile
= os
.path
.join(preview_dir
, "Preview.pov")
6009 outputPrevFile
= os
.path
.join(preview_dir
, texPrevName
)
6010 ##################### ini ##########################################
6011 fileIni
= open("%s" % iniPrevFile
, "w")
6012 fileIni
.write('Version=3.8\n')
6013 fileIni
.write('Input_File_Name="%s"\n' % inputPrevFile
)
6014 fileIni
.write('Output_File_Name="%s.png"\n' % outputPrevFile
)
6015 fileIni
.write('Library_Path="%s"\n' % preview_dir
)
6016 fileIni
.write('Width=256\n')
6017 fileIni
.write('Height=256\n')
6018 fileIni
.write('Pause_When_Done=0\n')
6019 fileIni
.write('Output_File_Type=N\n')
6020 fileIni
.write('Output_Alpha=1\n')
6021 fileIni
.write('Antialias=on\n')
6022 fileIni
.write('Sampling_Method=2\n')
6023 fileIni
.write('Antialias_Depth=3\n')
6024 fileIni
.write('-d\n')
6026 ##################### pov ##########################################
6027 filePov
= open("%s" % inputPrevFile
, "w")
6028 PATname
= "PAT_" + string_strip_hyphen(bpy
.path
.clean_name(tex
.name
))
6029 filePov
.write("#declare %s = \n" % PATname
)
6030 filePov
.write(shading
.exportPattern(tex
, string_strip_hyphen
))
6032 filePov
.write("#declare Plane =\n")
6033 filePov
.write("mesh {\n")
6035 " triangle {<-2.021,-1.744,2.021>,<-2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
6038 " triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n"
6040 filePov
.write(" texture{%s}\n" % PATname
)
6041 filePov
.write("}\n")
6042 filePov
.write("object {Plane}\n")
6043 filePov
.write("light_source {\n")
6044 filePov
.write(" <0,4.38,-1.92e-07>\n")
6045 filePov
.write(" color rgb<4, 4, 4>\n")
6046 filePov
.write(" parallel\n")
6047 filePov
.write(" point_at <0, 0, -1>\n")
6048 filePov
.write("}\n")
6049 filePov
.write("camera {\n")
6050 filePov
.write(" location <0, 0, 0>\n")
6051 filePov
.write(" look_at <0, 0, -1>\n")
6052 filePov
.write(" right <-1.0, 0, 0>\n")
6053 filePov
.write(" up <0, 1, 0>\n")
6054 filePov
.write(" angle 96.805211\n")
6055 filePov
.write(" rotate <-90.000003, -0.000000, 0.000000>\n")
6056 filePov
.write(" translate <0.000000, 0.000000, 0.000000>\n")
6057 filePov
.write("}\n")
6059 ##################### end write ##########################################
6061 pov_binary
= PovrayRender
._locate
_binary
()
6063 if sys
.platform
[:3] == "win":
6064 p1
= subprocess
.Popen(
6065 ["%s" % pov_binary
, "/EXIT", "%s" % iniPrevFile
],
6066 stdout
=subprocess
.PIPE
,
6067 stderr
=subprocess
.STDOUT
,
6070 p1
= subprocess
.Popen(
6071 ["%s" % pov_binary
, "-d", "%s" % iniPrevFile
],
6072 stdout
=subprocess
.PIPE
,
6073 stderr
=subprocess
.STDOUT
,
6077 tex
.use_nodes
= True
6078 tree
= tex
.node_tree
6080 for n
in tree
.nodes
:
6081 tree
.nodes
.remove(n
)
6082 im
= tree
.nodes
.new("TextureNodeImage")
6083 pathPrev
= "%s.png" % outputPrevFile
6084 im
.image
= bpy
.data
.images
.load(pathPrev
)
6086 name
= name
.split("/")
6087 name
= name
[len(name
) - 1]
6089 im
.location
= 200, 200
6090 previewer
= tree
.nodes
.new('TextureNodeOutput')
6091 previewer
.label
= "Preview"
6092 previewer
.location
= 400, 400
6093 links
.new(im
.outputs
[0], previewer
.inputs
[0])
6094 # tex.type="IMAGE" # makes clip extend possible
6095 # tex.extension="CLIP"
6099 class RunPovTextRender(Operator
):
6100 """Export files depending on text editor options and render image."""
6102 bl_idname
= "text.run"
6105 bl_description
= "Run a render with this text only"
6107 def execute(self
, context
):
6108 scene
= context
.scene
6109 scene
.pov
.text_block
= context
.space_data
.text
.name
6111 bpy
.ops
.render
.render()
6113 # empty text name property engain
6114 scene
.pov
.text_block
= ""
6118 classes
= (PovrayRender
, RenderPovTexturePreview
, RunPovTextRender
)
6122 # from bpy.utils import register_class
6129 from bpy
.utils
import unregister_class
6131 for cls
in reversed(classes
):
6132 unregister_class(cls
)