Use Python3.5's unpacking generalizations
[blender-addons.git] / render_povray / render.py
blobf115a9317ceeca7eb98034550b7fc40a829c8b9f
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 #****
19 # <pep8 compliant>
21 import bpy
22 import subprocess
23 import os
24 import sys
25 import time
26 from math import atan, pi, degrees, sqrt, cos, sin
27 import re
28 import random
29 import platform#
30 import subprocess#
31 from bpy.types import(Operator)
32 from bpy_extras.io_utils import ImportHelper
33 from bpy_extras import object_utils
35 from . import df3 # for smoke rendering
36 ##############################SF###########################
37 ##############find image texture
38 def imageFormat(imgF):
39 ext = {
40 'JPG': "jpeg",
41 'JPEG': "jpeg",
42 'GIF': "gif",
43 'TGA': "tga",
44 'IFF': "iff",
45 'PPM': "ppm",
46 'PNG': "png",
47 'SYS': "sys",
48 'TIFF': "tiff",
49 'TIF': "tiff",
50 'EXR': "exr",
51 'HDR': "hdr",
52 }.get(os.path.splitext(imgF)[-1].upper(), "")
54 if not ext:
55 print(" WARNING: texture image format not supported ")
57 return ext
60 def imgMap(ts):
61 image_map = ""
62 if ts.mapping == 'FLAT':
63 image_map = "map_type 0 "
64 elif ts.mapping == 'SPHERE':
65 image_map = "map_type 1 "
66 elif ts.mapping == 'TUBE':
67 image_map = "map_type 2 "
69 ## map_type 3 and 4 in development (?)
70 ## for POV-Ray, currently they just seem to default back to Flat (type 0)
71 #elif ts.mapping=="?":
72 # image_map = " map_type 3 "
73 #elif ts.mapping=="?":
74 # image_map = " map_type 4 "
75 if ts.texture.use_interpolation:
76 image_map += " interpolate 2 "
77 if ts.texture.extension == 'CLIP':
78 image_map += " once "
79 #image_map += "}"
80 #if ts.mapping=='CUBE':
81 # image_map+= "warp { cubic } rotate <-90,0,180>"
82 # no direct cube type mapping. Though this should work in POV 3.7
83 # it doesn't give that good results(best suited to environment maps?)
84 #if image_map == "":
85 # print(" No texture image found ")
86 return image_map
89 def imgMapTransforms(ts):
90 # XXX TODO: unchecked textures give error of variable referenced before assignment XXX
91 # POV-Ray "scale" is not a number of repetitions factor, but ,its
92 # inverse, a standard scale factor.
93 # 0.5 Offset is needed relatively to scale because center of the
94 # scale is 0.5,0.5 in blender and 0,0 in POV
95 image_map_transforms = ""
96 image_map_transforms = ("scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
97 ( 1.0 / ts.scale.x,
98 1.0 / ts.scale.y,
99 1.0 / ts.scale.z,
100 0.5-(0.5/ts.scale.x) - (ts.offset.x),
101 0.5-(0.5/ts.scale.y) - (ts.offset.y),
102 ts.offset.z))
103 # image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
104 # ( 1.0 / ts.scale.x,
105 # 1.0 / ts.scale.y,
106 # 1.0 / ts.scale.z,
107 # (0.5 / ts.scale.x) + ts.offset.x,
108 # (0.5 / ts.scale.y) + ts.offset.y,
109 # ts.offset.z))
110 # 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>" % \
111 # (1.0 / ts.scale.x,
112 # 1.0 / ts.scale.y,
113 # 1.0 / ts.scale.z,
114 # ts.offset.x,
115 # ts.offset.y,
116 # ts.offset.z))
117 return image_map_transforms
119 def imgMapBG(wts):
120 image_mapBG = ""
121 # texture_coords refers to the mapping of world textures:
122 if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
123 image_mapBG = " map_type 0 "
124 elif wts.texture_coords == 'ANGMAP':
125 image_mapBG = " map_type 1 "
126 elif wts.texture_coords == 'TUBE':
127 image_mapBG = " map_type 2 "
129 if wts.texture.use_interpolation:
130 image_mapBG += " interpolate 2 "
131 if wts.texture.extension == 'CLIP':
132 image_mapBG += " once "
133 #image_mapBG += "}"
134 #if wts.mapping == 'CUBE':
135 # image_mapBG += "warp { cubic } rotate <-90,0,180>"
136 # no direct cube type mapping. Though this should work in POV 3.7
137 # it doesn't give that good results(best suited to environment maps?)
138 #if image_mapBG == "":
139 # print(" No background texture image found ")
140 return image_mapBG
143 def path_image(image):
144 return bpy.path.abspath(image.filepath, library=image.library)
146 # end find image texture
147 # -----------------------------------------------------------------------------
150 def string_strip_hyphen(name):
151 return name.replace("-", "")
154 def safety(name, Level):
155 # safety string name material
157 # Level=1 is for texture with No specular nor Mirror reflection
158 # Level=2 is for texture with translation of spec and mir levels
159 # for when no map influences them
160 # Level=3 is for texture with Maximum Spec and Mirror
162 try:
163 if int(name) > 0:
164 prefix = "shader"
165 except:
166 prefix = ""
167 prefix = "shader_"
168 name = string_strip_hyphen(name)
169 if Level == 2:
170 return prefix + name
171 elif Level == 1:
172 return prefix + name + "0" # used for 0 of specular map
173 elif Level == 3:
174 return prefix + name + "1" # used for 1 of specular map
177 ##############end safety string name material
178 ##############################EndSF###########################
180 def is_renderable(ob):
181 return (ob.hide_render==False)
184 def renderable_objects():
185 return [ob for ob in bpy.data.objects if is_renderable(ob)]
188 tabLevel = 0
189 unpacked_images=[]
191 user_dir = bpy.utils.resource_path('USER')
192 preview_dir = os.path.join(user_dir, "preview")
194 ## Make sure Preview directory exists and is empty
195 smokePath = os.path.join(preview_dir, "smoke.df3")
197 def write_global_setting(scene,file):
198 file.write("global_settings {\n")
199 file.write(" assumed_gamma %.6f\n"%scene.pov.assumed_gamma)
200 if scene.pov.global_settings_default == False:
201 if scene.pov.adc_bailout_enable and scene.pov.radio_enable == False:
202 file.write(" adc_bailout %.6f\n"%scene.pov.adc_bailout)
203 if scene.pov.ambient_light_enable:
204 file.write(" ambient_light <%.6f,%.6f,%.6f>\n"%scene.pov.ambient_light[:])
205 if scene.pov.irid_wavelength_enable:
206 file.write(" irid_wavelength <%.6f,%.6f,%.6f>\n"%scene.pov.irid_wavelength[:])
207 if scene.pov.charset_enable:
208 file.write(" charset %s\n"%scene.pov.charset)
209 if scene.pov.max_trace_level_enable:
210 file.write(" max_trace_level %s\n"%scene.pov.max_trace_level)
211 if scene.pov.max_intersections_enable:
212 file.write(" max_intersections %s\n"%scene.pov.max_intersections)
213 if scene.pov.number_of_waves_enable:
214 file.write(" number_of_waves %s\n"%scene.pov.number_of_waves)
215 if scene.pov.noise_generator_enable:
216 file.write(" noise_generator %s\n"%scene.pov.noise_generator)
217 if scene.pov.sslt_enable:
218 file.write(" mm_per_unit %s\n"%scene.pov.mm_per_unit)
219 file.write(" subsurface {\n")
220 file.write(" samples %s, %s\n"%(scene.pov.sslt_samples_max,scene.pov.sslt_samples_min))
221 if scene.pov.sslt_radiosity:
222 file.write(" radiosity on\n")
223 file.write("}\n")
225 if scene.pov.radio_enable:
226 file.write(" radiosity {\n")
227 file.write(" pretrace_start %.6f\n"%scene.pov.radio_pretrace_start)
228 file.write(" pretrace_end %.6f\n"%scene.pov.radio_pretrace_end)
229 file.write(" count %s\n"%scene.pov.radio_count)
230 file.write(" nearest_count %s\n"%scene.pov.radio_nearest_count)
231 file.write(" error_bound %.6f\n"%scene.pov.radio_error_bound)
232 file.write(" recursion_limit %s\n"%scene.pov.radio_recursion_limit)
233 file.write(" low_error_factor %.6f\n"%scene.pov.radio_low_error_factor)
234 file.write(" gray_threshold %.6f\n"%scene.pov.radio_gray_threshold)
235 file.write(" maximum_reuse %.6f\n"%scene.pov.radio_maximum_reuse)
236 file.write(" minimum_reuse %.6f\n"%scene.pov.radio_minimum_reuse)
237 file.write(" brightness %.6f\n"%scene.pov.radio_brightness)
238 file.write(" adc_bailout %.6f\n"%scene.pov.radio_adc_bailout)
239 if scene.pov.radio_normal:
240 file.write(" normal on\n")
241 if scene.pov.radio_always_sample:
242 file.write(" always_sample on\n")
243 if scene.pov.radio_media:
244 file.write(" media on\n")
245 if scene.pov.radio_subsurface:
246 file.write(" subsurface on\n")
247 file.write(" }\n")
249 if scene.pov.photon_enable:
250 file.write(" photons {\n")
251 if scene.pov.photon_enable_count:
252 file.write(" count %s\n"%scene.pov.photon_count)
253 else:
254 file.write(" spacing %.6g\n"%scene.pov.photon_spacing)
255 if scene.pov.photon_gather:
256 file.write(" gather %s, %s\n"%(scene.pov.photon_gather_min,scene.pov.photon_gather_max))
257 if scene.pov.photon_autostop:
258 file.write(" autostop %.4g\n"%scene.pov.photon_autostop_value)
259 if scene.pov.photon_jitter_enable:
260 file.write(" jitter %.4g\n"%scene.pov.photon_jitter)
261 file.write(" max_trace_level %s\n"%scene.pov.photon_max_trace_level)
262 if scene.pov.photon_adc:
263 file.write(" adc_bailout %.6f\n"%scene.pov.photon_adc_bailout)
264 if scene.pov.photon_media_enable:
265 file.write(" media %s, %s\n"%(scene.pov.photon_media_steps,scene.pov.photon_media_factor))
266 if scene.pov.photon_savefile or scene.pov.photon_loadfile:
267 filePh = bpy.path.abspath(scene.pov.photon_map_file)
268 if scene.pov.photon_savefile:
269 file.write('save_file "%s"\n'%filePh)
270 if scene.pov.photon_loadfile and os.path.exists(filePh):
271 file.write('load_file "%s"\n'%filePh)
272 file.write("}\n")
273 file.write("}\n")
275 def write_object_modifiers(scene,ob,File):
276 if ob.pov.hollow:
277 File.write("hollow\n")
278 if ob.pov.double_illuminate:
279 File.write("double_illuminate\n")
280 if ob.pov.sturm:
281 File.write("sturm\n")
282 if ob.pov.no_shadow:
283 File.write("no_shadow\n")
284 if ob.pov.no_image:
285 File.write("no_image\n")
286 if ob.pov.no_reflection:
287 File.write("no_reflection\n")
288 if ob.pov.no_radiosity:
289 File.write("no_radiosity\n")
290 if ob.pov.inverse:
291 File.write("inverse\n")
292 if ob.pov.hierarchy:
293 File.write("hierarchy\n")
294 if scene.pov.photon_enable:
295 File.write("photons {\n")
296 if ob.pov.target:
297 File.write("target %.4g\n"%ob.pov.target_value)
298 if ob.pov.refraction:
299 File.write("refraction on\n")
300 if ob.pov.reflection:
301 File.write("reflection on\n")
302 if ob.pov.pass_through:
303 File.write("pass_through\n")
304 File.write("}\n")
305 # if ob.pov.object_ior > 1:
306 # File.write("interior {\n")
307 # File.write("ior %.4g\n"%ob.pov.object_ior)
308 # if scene.pov.photon_enable and ob.pov.target and ob.pov.refraction and ob.pov.dispersion:
309 # File.write("ior %.4g\n"%ob.pov.dispersion_value)
310 # File.write("ior %s\n"%ob.pov.dispersion_samples)
311 # if scene.pov.photon_enable == False:
312 # File.write("caustics %.4g\n"%ob.pov.fake_caustics_power)
314 def exportPattern(texture):
315 tex=texture
316 pat = tex.pov
317 PATname = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(tex.name))
318 mappingDif = ("translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
319 (pat.tex_mov_x, pat.tex_mov_y, pat.tex_mov_z,
320 1.0 / pat.tex_scale_x, 1.0 / pat.tex_scale_y, 1.0 / pat.tex_scale_z))
321 texStrg=""
322 def exportColorRamp(texture):
323 tex=texture
324 pat = tex.pov
325 colRampStrg="color_map {\n"
326 numColor=0
327 for el in tex.color_ramp.elements:
328 numColor+=1
329 pos = el.position
330 col=el.color
331 colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
332 if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
333 colRampStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
334 if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
335 colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
336 if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
337 colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
338 if pat.tex_pattern_type == 'square' and numColor < 5 :
339 colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
340 if pat.tex_pattern_type == 'triangular' and numColor < 7 :
341 colRampStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
343 colRampStrg+="} \n"
344 #end color map
345 return colRampStrg
346 #much work to be done here only defaults translated for now:
347 #pov noise_generator 3 means perlin noise
348 if pat.tex_pattern_type == 'emulator':
349 texStrg+="pigment {\n"
350 ####################### EMULATE BLENDER VORONOI TEXTURE ####################
351 if tex.type == 'VORONOI':
352 texStrg+="crackle\n"
353 texStrg+=" offset %.4g\n"%tex.nabla
354 texStrg+=" form <%.4g,%.4g,%.4g>\n"%(tex.weight_1, tex.weight_2, tex.weight_3)
355 if tex.distance_metric == 'DISTANCE':
356 texStrg+=" metric 2.5\n"
357 if tex.distance_metric == 'DISTANCE_SQUARED':
358 texStrg+=" metric 2.5\n"
359 texStrg+=" poly_wave 2\n"
360 if tex.distance_metric == 'MINKOVSKY':
361 texStrg+=" metric %s\n"%tex.minkovsky_exponent
362 if tex.distance_metric == 'MINKOVSKY_FOUR':
363 texStrg+=" metric 4\n"
364 if tex.distance_metric == 'MINKOVSKY_HALF':
365 texStrg+=" metric 0.5\n"
366 if tex.distance_metric == 'CHEBYCHEV':
367 texStrg+=" metric 10\n"
368 if tex.distance_metric == 'MANHATTAN':
369 texStrg+=" metric 1\n"
371 if tex.color_mode == 'POSITION':
372 texStrg+="solid\n"
373 texStrg+="scale 0.25\n"
375 if tex.use_color_ramp == True:
376 texStrg+=exportColorRamp(tex)
377 else:
378 texStrg+="color_map {\n"
379 texStrg+="[0 color rgbt<0,0,0,1>]\n"
380 texStrg+="[1 color rgbt<1,1,1,0>]\n"
381 texStrg+="}\n"
382 ####################### EMULATE BLENDER CLOUDS TEXTURE ####################
383 if tex.type == 'CLOUDS':
384 if tex.noise_type == 'SOFT_NOISE':
385 texStrg+="wrinkles\n"
386 texStrg+="scale 0.25\n"
387 else:
388 texStrg+="granite\n"
389 if tex.use_color_ramp == True:
390 texStrg+=exportColorRamp(tex)
391 else:
392 texStrg+="color_map {\n"
393 texStrg+="[0 color rgbt<0,0,0,1>]\n"
394 texStrg+="[1 color rgbt<1,1,1,0>]\n"
395 texStrg+="}\n"
396 ####################### EMULATE BLENDER WOOD TEXTURE ####################
397 if tex.type == 'WOOD':
398 if tex.wood_type == 'RINGS':
399 texStrg+="wood\n"
400 texStrg+="scale 0.25\n"
401 if tex.wood_type == 'RINGNOISE':
402 texStrg+="wood\n"
403 texStrg+="scale 0.25\n"
404 texStrg+="turbulence %.4g\n"%(tex.turbulence/100)
405 if tex.wood_type == 'BANDS':
406 texStrg+="marble\n"
407 texStrg+="scale 0.25\n"
408 texStrg+="rotate <45,-45,45>\n"
409 if tex.wood_type == 'BANDNOISE':
410 texStrg+="marble\n"
411 texStrg+="scale 0.25\n"
412 texStrg+="rotate <45,-45,45>\n"
413 texStrg+="turbulence %.4g\n"%(tex.turbulence/10)
415 if tex.noise_basis_2 == 'SIN':
416 texStrg+="sine_wave\n"
417 if tex.noise_basis_2 == 'TRI':
418 texStrg+="triangle_wave\n"
419 if tex.noise_basis_2 == 'SAW':
420 texStrg+="ramp_wave\n"
421 if tex.use_color_ramp == True:
422 texStrg+=exportColorRamp(tex)
423 else:
424 texStrg+="color_map {\n"
425 texStrg+="[0 color rgbt<0,0,0,0>]\n"
426 texStrg+="[1 color rgbt<1,1,1,0>]\n"
427 texStrg+="}\n"
428 ####################### EMULATE BLENDER STUCCI TEXTURE ####################
429 if tex.type == 'STUCCI':
430 texStrg+="bozo\n"
431 texStrg+="scale 0.25\n"
432 if tex.noise_type == 'HARD_NOISE':
433 texStrg+="triangle_wave\n"
434 if tex.use_color_ramp == True:
435 texStrg+=exportColorRamp(tex)
436 else:
437 texStrg+="color_map {\n"
438 texStrg+="[0 color rgbf<1,1,1,0>]\n"
439 texStrg+="[1 color rgbt<0,0,0,1>]\n"
440 texStrg+="}\n"
441 else:
442 if tex.use_color_ramp == True:
443 texStrg+=exportColorRamp(tex)
444 else:
445 texStrg+="color_map {\n"
446 texStrg+="[0 color rgbf<0,0,0,1>]\n"
447 texStrg+="[1 color rgbt<1,1,1,0>]\n"
448 texStrg+="}\n"
449 ####################### EMULATE BLENDER MAGIC TEXTURE ####################
450 if tex.type == 'MAGIC':
451 texStrg+="leopard\n"
452 if tex.use_color_ramp == True:
453 texStrg+=exportColorRamp(tex)
454 else:
455 texStrg+="color_map {\n"
456 texStrg+="[0 color rgbt<1,1,1,0.5>]\n"
457 texStrg+="[0.25 color rgbf<0,1,0,0.75>]\n"
458 texStrg+="[0.5 color rgbf<0,0,1,0.75>]\n"
459 texStrg+="[0.75 color rgbf<1,0,1,0.75>]\n"
460 texStrg+="[1 color rgbf<0,1,0,0.75>]\n"
461 texStrg+="}\n"
462 texStrg+="scale 0.1\n"
463 ####################### EMULATE BLENDER MARBLE TEXTURE ####################
464 if tex.type == 'MARBLE':
465 texStrg+="marble\n"
466 texStrg+="turbulence 0.5\n"
467 texStrg+="noise_generator 3\n"
468 texStrg+="scale 0.75\n"
469 texStrg+="rotate <45,-45,45>\n"
470 if tex.use_color_ramp == True:
471 texStrg+=exportColorRamp(tex)
472 else:
473 if tex.marble_type == 'SOFT':
474 texStrg+="color_map {\n"
475 texStrg+="[0 color rgbt<0,0,0,0>]\n"
476 texStrg+="[0.05 color rgbt<0,0,0,0>]\n"
477 texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
478 texStrg+="}\n"
479 elif tex.marble_type == 'SHARP':
480 texStrg+="color_map {\n"
481 texStrg+="[0 color rgbt<0,0,0,0>]\n"
482 texStrg+="[0.025 color rgbt<0,0,0,0>]\n"
483 texStrg+="[1 color rgbt<0.9,0.9,0.9,0>]\n"
484 texStrg+="}\n"
485 else:
486 texStrg+="[0 color rgbt<0,0,0,0>]\n"
487 texStrg+="[1 color rgbt<1,1,1,0>]\n"
488 texStrg+="}\n"
489 if tex.noise_basis_2 == 'SIN':
490 texStrg+="sine_wave\n"
491 if tex.noise_basis_2 == 'TRI':
492 texStrg+="triangle_wave\n"
493 if tex.noise_basis_2 == 'SAW':
494 texStrg+="ramp_wave\n"
495 ####################### EMULATE BLENDER BLEND TEXTURE ####################
496 if tex.type == 'BLEND':
497 if tex.progression=='RADIAL':
498 texStrg+="radial\n"
499 if tex.use_flip_axis=='HORIZONTAL':
500 texStrg+="rotate x*90\n"
501 else:
502 texStrg+="rotate <-90,0,90>\n"
503 texStrg+="ramp_wave\n"
504 elif tex.progression=='SPHERICAL':
505 texStrg+="spherical\n"
506 texStrg+="scale 3\n"
507 texStrg+="poly_wave 1\n"
508 elif tex.progression=='QUADRATIC_SPHERE':
509 texStrg+="spherical\n"
510 texStrg+="scale 3\n"
511 texStrg+=" poly_wave 2\n"
512 elif tex.progression=='DIAGONAL':
513 texStrg+="gradient <1,1,0>\n"
514 texStrg+="scale 3\n"
515 elif tex.use_flip_axis=='HORIZONTAL':
516 texStrg+="gradient x\n"
517 texStrg+="scale 2.01\n"
518 elif tex.use_flip_axis=='VERTICAL':
519 texStrg+="gradient y\n"
520 texStrg+="scale 2.01\n"
521 #texStrg+="ramp_wave\n"
522 #texStrg+="frequency 0.5\n"
523 texStrg+="phase 0.5\n"
524 if tex.use_color_ramp == True:
525 texStrg+=exportColorRamp(tex)
526 else:
527 texStrg+="color_map {\n"
528 texStrg+="[0 color rgbt<1,1,1,0>]\n"
529 texStrg+="[1 color rgbf<0,0,0,1>]\n"
530 texStrg+="}\n"
531 if tex.progression == 'LINEAR':
532 texStrg+=" poly_wave 1\n"
533 if tex.progression == 'QUADRATIC':
534 texStrg+=" poly_wave 2\n"
535 if tex.progression == 'EASING':
536 texStrg+=" poly_wave 1.5\n"
537 ####################### EMULATE BLENDER MUSGRAVE TEXTURE ####################
538 # if tex.type == 'MUSGRAVE':
539 # texStrg+="function{ f_ridged_mf( x, y, 0, 1, 2, 9, -0.5, 3,3 )*0.5}\n"
540 # texStrg+="color_map {\n"
541 # texStrg+="[0 color rgbf<0,0,0,1>]\n"
542 # texStrg+="[1 color rgbf<1,1,1,0>]\n"
543 # texStrg+="}\n"
544 # simplified for now:
546 if tex.type == 'MUSGRAVE':
547 texStrg+="bozo scale 0.25 \n"
548 if tex.use_color_ramp == True:
549 texStrg+=exportColorRamp(tex)
550 else:
551 texStrg+="color_map {[0.5 color rgbf<0,0,0,1>][1 color rgbt<1,1,1,0>]}ramp_wave \n"
552 ####################### EMULATE BLENDER DISTORTED NOISE TEXTURE ####################
553 if tex.type == 'DISTORTED_NOISE':
554 texStrg+="average\n"
555 texStrg+=" pigment_map {\n"
556 texStrg+=" [1 bozo scale 0.25 turbulence %.4g\n" %tex.distortion
557 if tex.use_color_ramp == True:
558 texStrg+=exportColorRamp(tex)
559 else:
560 texStrg+="color_map {\n"
561 texStrg+="[0 color rgbt<1,1,1,0>]\n"
562 texStrg+="[1 color rgbf<0,0,0,1>]\n"
563 texStrg+="}\n"
564 texStrg+="]\n"
566 if tex.noise_distortion == 'CELL_NOISE':
567 texStrg+=" [1 cells scale 0.1\n"
568 if tex.use_color_ramp == True:
569 texStrg+=exportColorRamp(tex)
570 else:
571 texStrg+="color_map {\n"
572 texStrg+="[0 color rgbt<1,1,1,0>]\n"
573 texStrg+="[1 color rgbf<0,0,0,1>]\n"
574 texStrg+="}\n"
575 texStrg+="]\n"
576 if tex.noise_distortion=='VORONOI_CRACKLE':
577 texStrg+=" [1 crackle scale 0.25\n"
578 if tex.use_color_ramp == True:
579 texStrg+=exportColorRamp(tex)
580 else:
581 texStrg+="color_map {\n"
582 texStrg+="[0 color rgbt<1,1,1,0>]\n"
583 texStrg+="[1 color rgbf<0,0,0,1>]\n"
584 texStrg+="}\n"
585 texStrg+="]\n"
586 if tex.noise_distortion in ['VORONOI_F1','VORONOI_F2','VORONOI_F3','VORONOI_F4','VORONOI_F2_F1']:
587 texStrg+=" [1 crackle metric 2.5 scale 0.25 turbulence %.4g\n" %(tex.distortion/2)
588 if tex.use_color_ramp == True:
589 texStrg+=exportColorRamp(tex)
590 else:
591 texStrg+="color_map {\n"
592 texStrg+="[0 color rgbt<1,1,1,0>]\n"
593 texStrg+="[1 color rgbf<0,0,0,1>]\n"
594 texStrg+="}\n"
595 texStrg+="]\n"
596 else:
597 texStrg+=" [1 wrinkles scale 0.25\n"
598 if tex.use_color_ramp == True:
599 texStrg+=exportColorRamp(tex)
600 else:
601 texStrg+="color_map {\n"
602 texStrg+="[0 color rgbt<1,1,1,0>]\n"
603 texStrg+="[1 color rgbf<0,0,0,1>]\n"
604 texStrg+="}\n"
605 texStrg+="]\n"
606 texStrg+=" }\n"
607 ####################### EMULATE BLENDER NOISE TEXTURE ####################
608 if tex.type == 'NOISE':
609 texStrg+="cells\n"
610 texStrg+="turbulence 3\n"
611 texStrg+="omega 3\n"
612 if tex.use_color_ramp == True:
613 texStrg+=exportColorRamp(tex)
614 else:
615 texStrg+="color_map {\n"
616 texStrg+="[0.75 color rgb<0,0,0,>]\n"
617 texStrg+="[1 color rgb<1,1,1,>]\n"
618 texStrg+="}\n"
620 ####################### IGNORE OTHER BLENDER TEXTURE ####################
621 else: #non translated textures
622 pass
623 texStrg+="}\n\n"
625 texStrg+="#declare f%s=\n"%PATname
626 texStrg+="function{pigment{%s}}\n"%PATname
627 texStrg+="\n"
629 else:
630 texStrg+="pigment {\n"
631 texStrg+="%s\n"%pat.tex_pattern_type
632 if pat.tex_pattern_type == 'agate':
633 texStrg+="agate_turb %.4g\n"%pat.modifier_turbulence
634 if pat.tex_pattern_type in {'spiral1', 'spiral2', 'tiling'}:
635 texStrg+="%s\n"%pat.modifier_numbers
636 if pat.tex_pattern_type == 'quilted':
637 texStrg+="control0 %s control1 %s\n"%(pat.modifier_control0, pat.modifier_control1)
638 if pat.tex_pattern_type == 'mandel':
639 texStrg+="%s exponent %s \n"%(pat.f_iter, pat.f_exponent)
640 if pat.tex_pattern_type == 'julia':
641 texStrg+="<%.4g, %.4g> %s exponent %s \n"%(pat.julia_complex_1, pat.julia_complex_2, pat.f_iter, pat.f_exponent)
642 if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'mandel':
643 texStrg+="%s mandel %s \n"%(pat.magnet_type, pat.f_iter)
644 if pat.tex_pattern_type == 'magnet' and pat.magnet_style == 'julia':
645 texStrg+="%s julia <%.4g, %.4g> %s\n"%(pat.magnet_type, pat.julia_complex_1, pat.julia_complex_2, pat.f_iter)
646 if pat.tex_pattern_type in {'mandel', 'julia', 'magnet'}:
647 texStrg+="interior %s, %.4g\n"%(pat.f_ior, pat.f_ior_fac)
648 texStrg+="exterior %s, %.4g\n"%(pat.f_eor, pat.f_eor_fac)
649 if pat.tex_pattern_type == 'gradient':
650 texStrg+="<%s, %s, %s> \n"%(pat.grad_orient_x, pat.grad_orient_y, pat.grad_orient_z)
651 if pat.tex_pattern_type == 'pavement':
652 numTiles=pat.pave_tiles
653 numPattern=1
654 if pat.pave_sides == '4' and pat.pave_tiles == 3:
655 numPattern = pat.pave_pat_2
656 if pat.pave_sides == '6' and pat.pave_tiles == 3:
657 numPattern = pat.pave_pat_3
658 if pat.pave_sides == '3' and pat.pave_tiles == 4:
659 numPattern = pat.pave_pat_3
660 if pat.pave_sides == '3' and pat.pave_tiles == 5:
661 numPattern = pat.pave_pat_4
662 if pat.pave_sides == '4' and pat.pave_tiles == 4:
663 numPattern = pat.pave_pat_5
664 if pat.pave_sides == '6' and pat.pave_tiles == 4:
665 numPattern = pat.pave_pat_7
666 if pat.pave_sides == '4' and pat.pave_tiles == 5:
667 numPattern = pat.pave_pat_12
668 if pat.pave_sides == '3' and pat.pave_tiles == 6:
669 numPattern = pat.pave_pat_12
670 if pat.pave_sides == '6' and pat.pave_tiles == 5:
671 numPattern = pat.pave_pat_22
672 if pat.pave_sides == '4' and pat.pave_tiles == 6:
673 numPattern = pat.pave_pat_35
674 if pat.pave_sides == '6' and pat.pave_tiles == 6:
675 numTiles = 5
676 texStrg+="number_of_sides %s number_of_tiles %s pattern %s form %s \n"%(pat.pave_sides, numTiles, numPattern, pat.pave_form)
677 ################ functions #####################################################################################################
678 if pat.tex_pattern_type == 'function':
679 texStrg+="{ %s"%pat.func_list
680 texStrg+="(x"
681 if pat.func_plus_x != "NONE":
682 if pat.func_plus_x =='increase':
683 texStrg+="*"
684 if pat.func_plus_x =='plus':
685 texStrg+="+"
686 texStrg+="%.4g"%pat.func_x
687 texStrg+=",y"
688 if pat.func_plus_y != "NONE":
689 if pat.func_plus_y =='increase':
690 texStrg+="*"
691 if pat.func_plus_y =='plus':
692 texStrg+="+"
693 texStrg+="%.4g"%pat.func_y
694 texStrg+=",z"
695 if pat.func_plus_z != "NONE":
696 if pat.func_plus_z =='increase':
697 texStrg+="*"
698 if pat.func_plus_z =='plus':
699 texStrg+="+"
700 texStrg+="%.4g"%pat.func_z
701 sort = -1
702 if pat.func_list in {"f_comma","f_crossed_trough","f_cubic_saddle","f_cushion","f_devils_curve",
703 "f_enneper","f_glob","f_heart","f_hex_x","f_hex_y","f_hunt_surface",
704 "f_klein_bottle","f_kummer_surface_v1","f_lemniscate_of_gerono","f_mitre",
705 "f_nodal_cubic","f_noise_generator","f_odd","f_paraboloid","f_pillow",
706 "f_piriform","f_quantum","f_quartic_paraboloid","f_quartic_saddle",
707 "f_sphere","f_steiners_roman","f_torus_gumdrop","f_umbrella"}:
708 sort = 0
709 if pat.func_list in {"f_bicorn","f_bifolia","f_boy_surface","f_superellipsoid","f_torus"}:
710 sort = 1
711 if pat.func_list in {"f_ellipsoid","f_folium_surface","f_hyperbolic_torus",
712 "f_kampyle_of_eudoxus","f_parabolic_torus","f_quartic_cylinder","f_torus2"}:
713 sort = 2
714 if pat.func_list in {"f_blob2","f_cross_ellipsoids","f_flange_cover","f_isect_ellipsoids",
715 "f_kummer_surface_v2","f_ovals_of_cassini","f_rounded_box","f_spikes_2d","f_strophoid"}:
716 sort = 3
717 if pat.func_list in {"f_algbr_cyl1","f_algbr_cyl2","f_algbr_cyl3","f_algbr_cyl4","f_blob","f_mesh1","f_poly4","f_spikes"}:
718 sort = 4
719 if pat.func_list in {"f_devils_curve_2d","f_dupin_cyclid","f_folium_surface_2d","f_hetero_mf","f_kampyle_of_eudoxus_2d",
720 "f_lemniscate_of_gerono_2d","f_polytubes","f_ridge","f_ridged_mf","f_spiral","f_witch_of_agnesi"}:
721 sort = 5
722 if pat.func_list in {"f_helix1","f_helix2","f_piriform_2d","f_strophoid_2d"}:
723 sort = 6
724 if pat.func_list == "f_helical_torus":
725 sort = 7
726 if sort > -1:
727 texStrg+=",%.4g"%pat.func_P0
728 if sort > 0:
729 texStrg+=",%.4g"%pat.func_P1
730 if sort > 1:
731 texStrg+=",%.4g"%pat.func_P2
732 if sort > 2:
733 texStrg+=",%.4g"%pat.func_P3
734 if sort > 3:
735 texStrg+=",%.4g"%pat.func_P4
736 if sort > 4:
737 texStrg+=",%.4g"%pat.func_P5
738 if sort > 5:
739 texStrg+=",%.4g"%pat.func_P6
740 if sort > 6:
741 texStrg+=",%.4g"%pat.func_P7
742 texStrg+=",%.4g"%pat.func_P8
743 texStrg+=",%.4g"%pat.func_P9
744 texStrg+=")}\n"
745 ############## end functions ###############################################################
746 if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'}:
747 texStrg+="color_map {\n"
748 numColor=0
749 if tex.use_color_ramp == True:
750 for el in tex.color_ramp.elements:
751 numColor+=1
752 pos = el.position
753 col=el.color
754 colR,colG,colB,colA = col[0],col[1],col[2],1-col[3]
755 if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
756 texStrg+="[%.4g color rgbf<%.4g,%.4g,%.4g,%.4g>] \n"%(pos,colR,colG,colB,colA)
757 if pat.tex_pattern_type in {'brick','checker'} and numColor < 3:
758 texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
759 if pat.tex_pattern_type == 'hexagon' and numColor < 4 :
760 texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
761 if pat.tex_pattern_type == 'square' and numColor < 5 :
762 texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
763 if pat.tex_pattern_type == 'triangular' and numColor < 7 :
764 texStrg+="color rgbf<%.4g,%.4g,%.4g,%.4g> \n"%(colR,colG,colB,colA)
765 else:
766 texStrg+="[0 color rgbf<0,0,0,1>]\n"
767 texStrg+="[1 color rgbf<1,1,1,0>]\n"
768 if pat.tex_pattern_type not in {'checker', 'hexagon', 'square', 'triangular', 'brick'} :
769 texStrg+="} \n"
770 if pat.tex_pattern_type == 'brick':
771 texStrg+="brick_size <%.4g, %.4g, %.4g> mortar %.4g \n"%(pat.brick_size_x, pat.brick_size_y, pat.brick_size_z, pat.brick_mortar)
772 texStrg+="%s \n"%mappingDif
773 texStrg+="rotate <%.4g,%.4g,%.4g> \n"%(pat.tex_rot_x, pat.tex_rot_y, pat.tex_rot_z)
774 texStrg+="turbulence <%.4g,%.4g,%.4g> \n"%(pat.warp_turbulence_x, pat.warp_turbulence_y, pat.warp_turbulence_z)
775 texStrg+="octaves %s \n"%pat.modifier_octaves
776 texStrg+="lambda %.4g \n"%pat.modifier_lambda
777 texStrg+="omega %.4g \n"%pat.modifier_omega
778 texStrg+="frequency %.4g \n"%pat.modifier_frequency
779 texStrg+="phase %.4g \n"%pat.modifier_phase
780 texStrg+="}\n\n"
781 texStrg+="#declare f%s=\n"%PATname
782 texStrg+="function{pigment{%s}}\n"%PATname
783 texStrg+="\n"
784 return(texStrg)
786 def write_pov(filename, scene=None, info_callback=None):
787 import mathutils
788 #file = filename
789 file = open(filename, "w")
791 # Only for testing
792 if not scene:
793 scene = bpy.data.scenes[0]
795 render = scene.render
796 world = scene.world
797 global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
798 comments = scene.pov.comments_enable and not scene.pov.tempfiles_enable
799 linebreaksinlists = scene.pov.list_lf_enable and not scene.pov.tempfiles_enable
800 feature_set = bpy.context.user_preferences.addons[__package__].preferences.branch_feature_set_povray
801 using_uberpov = (feature_set=='uberpov')
802 pov_binary = PovrayRender._locate_binary()
804 if using_uberpov:
805 print("Unofficial UberPOV feature set chosen in preferences")
806 else:
807 print("Official POV-Ray 3.7 feature set chosen in preferences")
808 if 'uber' in pov_binary:
809 print("The name of the binary suggests you are probably rendering with Uber POV engine")
810 else:
811 print("The name of the binary suggests you are probably rendering with standard POV engine")
812 def setTab(tabtype, spaces):
813 TabStr = ""
814 if tabtype == 'NONE':
815 TabStr = ""
816 elif tabtype == 'TAB':
817 TabStr = "\t"
818 elif tabtype == 'SPACE':
819 TabStr = spaces * " "
820 return TabStr
822 tab = setTab(scene.pov.indentation_character, scene.pov.indentation_spaces)
823 if not scene.pov.tempfiles_enable:
824 def tabWrite(str_o):
825 global tabLevel
826 brackets = str_o.count("{") - str_o.count("}") + str_o.count("[") - str_o.count("]")
827 if brackets < 0:
828 tabLevel = tabLevel + brackets
829 if tabLevel < 0:
830 print("Indentation Warning: tabLevel = %s" % tabLevel)
831 tabLevel = 0
832 if tabLevel >= 1:
833 file.write("%s" % tab * tabLevel)
834 file.write(str_o)
835 if brackets > 0:
836 tabLevel = tabLevel + brackets
837 else:
838 def tabWrite(str_o):
839 file.write(str_o)
841 def uniqueName(name, nameSeq):
843 if name not in nameSeq:
844 name = string_strip_hyphen(name)
845 return name
847 name_orig = name
848 i = 1
849 while name in nameSeq:
850 name = "%s_%.3d" % (name_orig, i)
851 i += 1
852 name = string_strip_hyphen(name)
853 return name
855 def writeMatrix(matrix):
856 tabWrite("matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n" %
857 (matrix[0][0], matrix[1][0], matrix[2][0],
858 matrix[0][1], matrix[1][1], matrix[2][1],
859 matrix[0][2], matrix[1][2], matrix[2][2],
860 matrix[0][3], matrix[1][3], matrix[2][3]))
862 def MatrixAsPovString(matrix):
863 sMatrix = ("matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n" %
864 (matrix[0][0], matrix[1][0], matrix[2][0],
865 matrix[0][1], matrix[1][1], matrix[2][1],
866 matrix[0][2], matrix[1][2], matrix[2][2],
867 matrix[0][3], matrix[1][3], matrix[2][3]))
868 return sMatrix
870 def writeObjectMaterial(material, ob):
872 # DH - modified some variables to be function local, avoiding RNA write
873 # this should be checked to see if it is functionally correct
875 # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
876 #if material and material.transparency_method == 'RAYTRACE':
877 if material:
878 # But there can be only one!
879 if material.subsurface_scattering.use: # SSS IOR get highest priority
880 tabWrite("interior {\n")
881 tabWrite("ior %.6f\n" % material.subsurface_scattering.ior)
882 # Then the raytrace IOR taken from raytrace transparency properties and used for
883 # reflections if IOR Mirror option is checked.
884 elif material.pov.mirror_use_IOR:
885 tabWrite("interior {\n")
886 tabWrite("ior %.6f\n" % material.raytrace_transparency.ior)
887 else:
888 tabWrite("interior {\n")
889 tabWrite("ior %.6f\n" % material.raytrace_transparency.ior)
891 pov_fake_caustics = False
892 pov_photons_refraction = False
893 pov_photons_reflection = False
895 if material.pov.photons_reflection:
896 pov_photons_reflection = True
897 if material.pov.refraction_type == "0":
898 pov_fake_caustics = False
899 pov_photons_refraction = False
900 elif material.pov.refraction_type == "1":
901 pov_fake_caustics = True
902 pov_photons_refraction = False
903 elif material.pov.refraction_type == "2":
904 pov_fake_caustics = False
905 pov_photons_refraction = True
907 # If only Raytrace transparency is set, its IOR will be used for refraction, but user
908 # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
909 # Last, if none of the above is specified, user can set up 'un-physical' fresnel
910 # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
911 if material.pov.caustics_enable:
912 if pov_fake_caustics:
913 tabWrite("caustics %.3g\n" % material.pov.fake_caustics_power)
914 if pov_photons_refraction:
915 # Default of 1 means no dispersion
916 tabWrite("dispersion %.6f\n" % material.pov.photons_dispersion)
917 tabWrite("dispersion_samples %.d\n" % material.pov.photons_dispersion_samples)
918 #TODO
919 # Other interior args
920 if material.use_transparency and material.transparency_method == 'RAYTRACE':
921 # fade_distance
922 # In Blender this value has always been reversed compared to what tooltip says.
923 # 100.001 rather than 100 so that it does not get to 0
924 # which deactivates the feature in POV
925 tabWrite("fade_distance %.3g\n" % \
926 (100.001 - material.raytrace_transparency.depth_max))
927 # fade_power
928 tabWrite("fade_power %.3g\n" % material.raytrace_transparency.falloff)
929 # fade_color
930 tabWrite("fade_color <%.3g, %.3g, %.3g>\n" % material.pov.interior_fade_color[:])
932 # (variable) dispersion_samples (constant count for now)
933 tabWrite("}\n")
934 if material.pov.photons_reflection or material.pov.refraction_type=="2":
935 tabWrite("photons{")
936 tabWrite("target %.3g\n" % ob.pov.spacing_multiplier)
937 if not ob.pov.collect_photons:
938 tabWrite("collect off\n")
939 if pov_photons_refraction:
940 tabWrite("refraction on\n")
941 if pov_photons_reflection:
942 tabWrite("reflection on\n")
943 tabWrite("}\n")
945 materialNames = {}
946 DEF_MAT_NAME = "" #or "Default"?
948 def writeMaterial(material):
949 # Assumes only called once on each material
950 if material:
951 name_orig = material.name
952 name = materialNames[name_orig] = uniqueName(bpy.path.clean_name(name_orig), materialNames)
953 else:
954 name = name_orig = DEF_MAT_NAME
957 if material:
958 # If saturation(.s) is not zero, then color is not grey, and has a tint
959 colored_specular_found = (material.specular_color.s > 0.0)
961 ##################
962 # Several versions of the finish: Level conditions are variations for specular/Mirror
963 # texture channel map with alternative finish of 0 specular and no mirror reflection.
964 # Level=1 Means No specular nor Mirror reflection
965 # Level=2 Means translation of spec and mir levels for when no map influences them
966 # Level=3 Means Maximum Spec and Mirror
968 def povHasnoSpecularMaps(Level):
969 if Level == 1:
970 tabWrite("#declare %s = finish {" % safety(name, Level=1))
971 if comments:
972 file.write(" //No specular nor Mirror reflection\n")
973 else:
974 tabWrite("\n")
975 elif Level == 2:
976 tabWrite("#declare %s = finish {" % safety(name, Level=2))
977 if comments:
978 file.write(" //translation of spec and mir levels for when no map " \
979 "influences them\n")
980 else:
981 tabWrite("\n")
982 elif Level == 3:
983 tabWrite("#declare %s = finish {" % safety(name, Level=3))
984 if comments:
985 file.write(" //Maximum Spec and Mirror\n")
986 else:
987 tabWrite("\n")
989 if material:
990 # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
991 # (the back diffuse is like blender translucency)
992 frontDiffuse = material.diffuse_intensity
993 backDiffuse = material.translucency
995 if material.pov.conserve_energy:
997 #Total should not go above one
998 if (frontDiffuse + backDiffuse) <= 1.0:
999 pass
1000 elif frontDiffuse == backDiffuse:
1001 # Try to respect the user's 'intention' by comparing the two values but
1002 # bringing the total back to one.
1003 frontDiffuse = backDiffuse = 0.5
1004 # Let the highest value stay the highest value.
1005 elif frontDiffuse > backDiffuse:
1006 # clamps the sum below 1
1007 backDiffuse = min(backDiffuse, (1.0 - frontDiffuse))
1008 else:
1009 frontDiffuse = min(frontDiffuse, (1.0 - backDiffuse))
1011 # map hardness between 0.0 and 1.0
1012 roughness = ((1.0 - ((material.specular_hardness - 1.0) / 510.0)))
1013 ## scale from 0.0 to 0.1
1014 roughness *= 0.1
1015 # add a small value because 0.0 is invalid.
1016 roughness += (1.0 / 511.0)
1018 ################################Diffuse Shader######################################
1019 # Not used for Full spec (Level=3) of the shader.
1020 if material.diffuse_shader == 'OREN_NAYAR' and Level != 3:
1021 # Blender roughness is what is generally called oren nayar Sigma,
1022 # and brilliance in POV-Ray.
1023 tabWrite("brilliance %.3g\n" % (0.9 + material.roughness))
1025 if material.diffuse_shader == 'TOON' and Level != 3:
1026 tabWrite("brilliance %.3g\n" % (0.01 + material.diffuse_toon_smooth * 0.25))
1027 # Lower diffuse and increase specular for toon effect seems to look better
1028 # in POV-Ray.
1029 frontDiffuse *= 0.5
1031 if material.diffuse_shader == 'MINNAERT' and Level != 3:
1032 #tabWrite("aoi %.3g\n" % material.darkness)
1033 pass # let's keep things simple for now
1034 if material.diffuse_shader == 'FRESNEL' and Level != 3:
1035 #tabWrite("aoi %.3g\n" % material.diffuse_fresnel_factor)
1036 pass # let's keep things simple for now
1037 if material.diffuse_shader == 'LAMBERT' and Level != 3:
1038 # trying to best match lambert attenuation by that constant brilliance value
1039 tabWrite("brilliance 1.8\n")
1041 if Level == 2:
1042 ###########################Specular Shader######################################
1043 # No difference between phong and cook torrence in blender HaHa!
1044 if (material.specular_shader == 'COOKTORR' or
1045 material.specular_shader == 'PHONG'):
1046 tabWrite("phong %.3g\n" % (material.specular_intensity))
1047 tabWrite("phong_size %.3g\n" % (material.specular_hardness / 2 + 0.25))
1049 # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
1050 elif material.specular_shader == 'BLINN':
1051 # Use blender Blinn's IOR just as some factor for spec intensity
1052 tabWrite("specular %.3g\n" % (material.specular_intensity *
1053 (material.specular_ior / 4.0)))
1054 tabWrite("roughness %.3g\n" % roughness)
1055 #Could use brilliance 2(or varying around 2 depending on ior or factor) too.
1057 elif material.specular_shader == 'TOON':
1058 tabWrite("phong %.3g\n" % (material.specular_intensity * 2.0))
1059 # use extreme phong_size
1060 tabWrite("phong_size %.3g\n" % (0.1 + material.specular_toon_smooth / 2.0))
1062 elif material.specular_shader == 'WARDISO':
1063 # find best suited default constant for brilliance Use both phong and
1064 # specular for some values.
1065 tabWrite("specular %.3g\n" % (material.specular_intensity /
1066 (material.specular_slope + 0.0005)))
1067 # find best suited default constant for brilliance Use both phong and
1068 # specular for some values.
1069 tabWrite("roughness %.4g\n" % (0.0005 + material.specular_slope / 10.0))
1070 # find best suited default constant for brilliance Use both phong and
1071 # specular for some values.
1072 tabWrite("brilliance %.4g\n" % (1.8 - material.specular_slope * 1.8))
1074 ####################################################################################
1075 elif Level == 1:
1076 tabWrite("specular 0\n")
1077 elif Level == 3:
1078 tabWrite("specular 1\n")
1079 tabWrite("diffuse %.3g %.3g\n" % (frontDiffuse, backDiffuse))
1081 tabWrite("ambient %.3g\n" % material.ambient)
1082 # POV-Ray blends the global value
1083 #tabWrite("ambient rgb <%.3g, %.3g, %.3g>\n" % \
1084 # tuple([c*material.ambient for c in world.ambient_color]))
1085 tabWrite("emission %.3g\n" % material.emit) # New in POV-Ray 3.7
1087 #POV-Ray just ignores roughness if there's no specular keyword
1088 #tabWrite("roughness %.3g\n" % roughness)
1090 if material.pov.conserve_energy:
1091 # added for more realistic shading. Needs some checking to see if it
1092 # really works. --Maurice.
1093 tabWrite("conserve_energy\n")
1095 if colored_specular_found == True:
1096 tabWrite("metallic\n")
1098 # 'phong 70.0 '
1099 if Level != 1:
1100 if material.raytrace_mirror.use:
1101 raytrace_mirror = material.raytrace_mirror
1102 if raytrace_mirror.reflect_factor:
1103 tabWrite("reflection {\n")
1104 tabWrite("rgb <%.3g, %.3g, %.3g>\n" % material.mirror_color[:])
1105 if material.pov.mirror_metallic:
1106 tabWrite("metallic %.3g\n" % (raytrace_mirror.reflect_factor))
1107 # Blurry reflections for UberPOV
1108 if using_uberpov and raytrace_mirror.gloss_factor < 1.0:
1109 #tabWrite("#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
1110 tabWrite("roughness %.6f\n" % \
1111 (0.000001/raytrace_mirror.gloss_factor))
1112 #tabWrite("#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
1113 if material.pov.mirror_use_IOR: # WORKING ?
1114 # Removed from the line below: gives a more physically correct
1115 # material but needs proper IOR. --Maurice
1116 tabWrite("fresnel 1 ")
1117 tabWrite("falloff %.3g exponent %.3g} " % \
1118 (raytrace_mirror.fresnel, raytrace_mirror.fresnel_factor))
1120 if material.subsurface_scattering.use:
1121 subsurface_scattering = material.subsurface_scattering
1122 tabWrite("subsurface { translucency <%.3g, %.3g, %.3g> }\n" % (
1123 (subsurface_scattering.radius[0]),
1124 (subsurface_scattering.radius[1]),
1125 (subsurface_scattering.radius[2]),
1129 if material.pov.irid_enable:
1130 tabWrite("irid { %.4g thickness %.4g turbulence %.4g }" % \
1131 (material.pov.irid_amount, material.pov.irid_thickness,
1132 material.pov.irid_turbulence))
1134 else:
1135 tabWrite("diffuse 0.8\n")
1136 tabWrite("phong 70.0\n")
1138 #tabWrite("specular 0.2\n")
1140 # This is written into the object
1142 if material and material.transparency_method=='RAYTRACE':
1143 'interior { ior %.3g} ' % material.raytrace_transparency.ior
1146 #tabWrite("crand 1.0\n") # Sand granyness
1147 #tabWrite("metallic %.6f\n" % material.spec)
1148 #tabWrite("phong %.6f\n" % material.spec)
1149 #tabWrite("phong_size %.6f\n" % material.spec)
1150 #tabWrite("brilliance %.6f " % (material.specular_hardness/256.0) # Like hardness
1152 tabWrite("}\n\n")
1154 # Level=2 Means translation of spec and mir levels for when no map influences them
1155 povHasnoSpecularMaps(Level=2)
1157 if material:
1158 special_texture_found = False
1159 for t in material.texture_slots:
1160 if t and t.use:
1161 if (t.texture.type == 'IMAGE' and t.texture.image) or t.texture.type != 'IMAGE':
1162 validPath=True
1163 else:
1164 validPath=False
1165 if(t and t.use and validPath and
1166 (t.use_map_specular or t.use_map_raymir or t.use_map_normal or t.use_map_alpha)):
1167 special_texture_found = True
1168 continue # Some texture found
1170 if special_texture_found or colored_specular_found:
1171 # Level=1 Means No specular nor Mirror reflection
1172 povHasnoSpecularMaps(Level=1)
1174 # Level=3 Means Maximum Spec and Mirror
1175 povHasnoSpecularMaps(Level=3)
1177 def exportCamera():
1178 camera = scene.camera
1180 # DH disabled for now, this isn't the correct context
1181 active_object = None # bpy.context.active_object # does not always work MR
1182 matrix = global_matrix * camera.matrix_world
1183 focal_point = camera.data.dof_distance
1185 # compute resolution
1186 Qsize = render.resolution_x / render.resolution_y
1187 tabWrite("#declare camLocation = <%.6f, %.6f, %.6f>;\n" %
1188 matrix.translation[:])
1189 tabWrite("#declare camLookAt = <%.6f, %.6f, %.6f>;\n" %
1190 tuple([degrees(e) for e in matrix.to_3x3().to_euler()]))
1192 tabWrite("camera {\n")
1193 if scene.pov.baking_enable and active_object and active_object.type == 'MESH':
1194 tabWrite("mesh_camera{ 1 3\n") # distribution 3 is what we want here
1195 tabWrite("mesh{%s}\n" % active_object.name)
1196 tabWrite("}\n")
1197 tabWrite("location <0,0,.01>")
1198 tabWrite("direction <0,0,-1>")
1199 # Using standard camera otherwise
1200 else:
1201 tabWrite("location <0, 0, 0>\n")
1202 tabWrite("look_at <0, 0, -1>\n")
1203 tabWrite("right <%s, 0, 0>\n" % - Qsize)
1204 tabWrite("up <0, 1, 0>\n")
1205 tabWrite("angle %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi))
1207 tabWrite("rotate <%.6f, %.6f, %.6f>\n" % \
1208 tuple([degrees(e) for e in matrix.to_3x3().to_euler()]))
1209 tabWrite("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
1210 if camera.data.pov.dof_enable and focal_point != 0:
1211 tabWrite("aperture %.3g\n" % camera.data.pov.dof_aperture)
1212 tabWrite("blur_samples %d %d\n" % \
1213 (camera.data.pov.dof_samples_min, camera.data.pov.dof_samples_max))
1214 tabWrite("variance 1/%d\n" % camera.data.pov.dof_variance)
1215 tabWrite("confidence %.3g\n" % camera.data.pov.dof_confidence)
1216 tabWrite("focal_point <0, 0, %f>\n" % focal_point)
1217 tabWrite("}\n")
1221 def exportLamps(lamps):
1222 # Incremented after each lamp export to declare its target
1223 # currently used for Fresnel diffuse shader as their slope vector:
1224 global lampCount
1225 lampCount = 0
1226 # Get all lamps
1227 for ob in lamps:
1228 lamp = ob.data
1230 matrix = global_matrix * ob.matrix_world
1232 # Color is modified by energy #muiltiplie by 2 for a better match --Maurice
1233 color = tuple([c * lamp.energy * 2.0 for c in lamp.color])
1235 tabWrite("light_source {\n")
1236 tabWrite("< 0,0,0 >\n")
1237 tabWrite("color rgb<%.3g, %.3g, %.3g>\n" % color)
1239 if lamp.type == 'POINT':
1240 pass
1241 elif lamp.type == 'SPOT':
1242 tabWrite("spotlight\n")
1244 # Falloff is the main radius from the centre line
1245 tabWrite("falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0)) # 1 TO 179 FOR BOTH
1246 tabWrite("radius %.6f\n" % \
1247 ((degrees(lamp.spot_size) / 2.0) * (1.0 - lamp.spot_blend)))
1249 # Blender does not have a tightness equivilent, 0 is most like blender default.
1250 tabWrite("tightness 0\n") # 0:10f
1252 tabWrite("point_at <0, 0, -1>\n")
1253 elif lamp.type == 'SUN':
1254 tabWrite("parallel\n")
1255 tabWrite("point_at <0, 0, -1>\n") # *must* be after 'parallel'
1257 elif lamp.type == 'AREA':
1258 tabWrite("area_illumination\n")
1259 tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
1260 # Area lights have no falloff type, so always use blenders lamp quad equivalent
1261 # for those?
1262 tabWrite("fade_power %d\n" % 2)
1263 size_x = lamp.size
1264 samples_x = lamp.shadow_ray_samples_x
1265 if lamp.shape == 'SQUARE':
1266 size_y = size_x
1267 samples_y = samples_x
1268 else:
1269 size_y = lamp.size_y
1270 samples_y = lamp.shadow_ray_samples_y
1272 tabWrite("area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n" % \
1273 (size_x, size_y, samples_x, samples_y))
1274 if lamp.shadow_ray_sample_method == 'CONSTANT_JITTERED':
1275 if lamp.use_jitter:
1276 tabWrite("jitter\n")
1277 else:
1278 tabWrite("adaptive 1\n")
1279 tabWrite("jitter\n")
1281 # HEMI never has any shadow_method attribute
1282 if(not scene.render.use_shadows or lamp.type == 'HEMI' or
1283 (lamp.type != 'HEMI' and lamp.shadow_method == 'NOSHADOW')):
1284 tabWrite("shadowless\n")
1286 # Sun shouldn't be attenuated. Hemi and area lights have no falloff attribute so they
1287 # are put to type 2 attenuation a little higher above.
1288 if lamp.type not in {'SUN', 'AREA', 'HEMI'}:
1289 tabWrite("fade_distance %.6f\n" % (lamp.distance / 2.0))
1290 if lamp.falloff_type == 'INVERSE_SQUARE':
1291 tabWrite("fade_power %d\n" % 2) # Use blenders lamp quad equivalent
1292 elif lamp.falloff_type == 'INVERSE_LINEAR':
1293 tabWrite("fade_power %d\n" % 1) # Use blenders lamp linear
1294 # supposing using no fade power keyword would default to constant, no attenuation.
1295 elif lamp.falloff_type == 'CONSTANT':
1296 pass
1297 # Using Custom curve for fade power 3 for now.
1298 elif lamp.falloff_type == 'CUSTOM_CURVE':
1299 tabWrite("fade_power %d\n" % 4)
1301 writeMatrix(matrix)
1303 tabWrite("}\n")
1305 lampCount += 1
1307 # v(A,B) rotates vector A about origin by vector B.
1308 file.write("#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n" % \
1309 (lampCount, -(ob.location.x), -(ob.location.y), -(ob.location.z),
1310 ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
1312 ####################################################################################################
1313 def exportRainbows(rainbows):
1314 for ob in rainbows:
1315 povdataname = ob.data.name #enough?
1316 angle = degrees(ob.data.spot_size/2.5) #radians in blender (2
1317 width = ob.data.spot_blend *10
1318 distance = ob.data.shadow_buffer_clip_start
1319 #eps=0.0000001
1320 #angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
1321 #width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
1322 # formerly:
1323 #cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
1325 # v(A,B) rotates vector A about origin by vector B.
1326 # and avoid a 0 length vector by adding 1
1328 # file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
1329 # (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
1330 # ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
1332 direction = (ob.location.x,ob.location.y,ob.location.z) # not taking matrix into account
1333 rmatrix = global_matrix * ob.matrix_world
1335 #ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
1336 # XXX Is result of the below offset by 90 degrees?
1337 up =ob.matrix_world.to_3x3()[1].xyz #* global_matrix
1340 # XXX TO CHANGE:
1341 #formerly:
1342 #tabWrite("#declare %s = rainbow {\n"%povdataname)
1344 # clumsy for now but remove the rainbow from instancing
1345 # system because not an object. use lamps later instead of meshes
1347 #del data_ref[dataname]
1348 tabWrite("rainbow {\n")
1350 tabWrite("angle %.4f\n"%angle)
1351 tabWrite("width %.4f\n"%width)
1352 tabWrite("distance %.4f\n"%distance)
1353 tabWrite("arc_angle %.4f\n"%ob.pov.arc_angle)
1354 tabWrite("falloff_angle %.4f\n"%ob.pov.falloff_angle)
1355 tabWrite("direction <%.4f,%.4f,%.4f>\n"%rmatrix.translation[:])
1356 tabWrite("up <%.4f,%.4f,%.4f>\n"%(up[0],up[1],up[2]))
1357 tabWrite("color_map {\n")
1358 tabWrite("[0.000 color rgbt<1.0, 0.5, 1.0, 1.0>]\n")
1359 tabWrite("[0.130 color rgbt<0.5, 0.5, 1.0, 0.9>]\n")
1360 tabWrite("[0.298 color rgbt<0.2, 0.2, 1.0, 0.7>]\n")
1361 tabWrite("[0.412 color rgbt<0.2, 1.0, 1.0, 0.4>]\n")
1362 tabWrite("[0.526 color rgbt<0.2, 1.0, 0.2, 0.4>]\n")
1363 tabWrite("[0.640 color rgbt<1.0, 1.0, 0.2, 0.4>]\n")
1364 tabWrite("[0.754 color rgbt<1.0, 0.5, 0.2, 0.6>]\n")
1365 tabWrite("[0.900 color rgbt<1.0, 0.2, 0.2, 0.7>]\n")
1366 tabWrite("[1.000 color rgbt<1.0, 0.2, 0.2, 1.0>]\n")
1367 tabWrite("}\n")
1370 povMatName = "Default_texture"
1371 #tabWrite("texture {%s}\n"%povMatName)
1372 write_object_modifiers(scene,ob,file)
1373 #tabWrite("rotate x*90\n")
1374 #matrix = global_matrix * ob.matrix_world
1375 #writeMatrix(matrix)
1376 tabWrite("}\n")
1377 #continue #Don't render proxy mesh, skip to next object
1379 ################################XXX LOFT, ETC.
1380 def exportCurves(scene, ob):
1381 name_orig = "OB" + ob.name
1382 dataname_orig = "DATA" + ob.data.name
1384 name = string_strip_hyphen(bpy.path.clean_name(name_orig))
1385 dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
1387 global_matrix = mathutils.Matrix.Rotation(-pi / 2.0, 4, 'X')
1388 matrix=global_matrix*ob.matrix_world
1389 bezier_sweep = False
1390 if ob.pov.curveshape == 'sphere_sweep':
1391 for spl in ob.data.splines:
1392 if spl.type == "BEZIER":
1393 bezier_sweep = True
1394 if ob.pov.curveshape in {'loft','birail'}:
1396 for spline in ob.data.splines:
1397 n+=1
1398 tabWrite('#declare %s%s=spline {\n'%(dataname,n))
1399 tabWrite('cubic_spline\n')
1400 lp = len(spline.points)
1401 delta = 1/(lp)
1402 d=-delta
1403 point = spline.points[lp-1]
1404 x,y,z,w = point.co[:]
1405 tabWrite('%.6f, <%.6f,%.6f,%.6f>\n'%(d,x,y,z))
1406 d+=delta
1407 for point in spline.points:
1408 x,y,z,w = point.co[:]
1409 tabWrite('%.6f, <%.6f,%.6f,%.6f>\n'%(d,x,y,z))
1410 d+=delta
1411 for i in range(2):
1412 point = spline.points[i]
1413 x,y,z,w = point.co[:]
1414 tabWrite('%.6f, <%.6f,%.6f,%.6f>\n'%(d,x,y,z))
1415 d+=delta
1416 tabWrite('}\n')
1417 if ob.pov.curveshape in {'loft'}:
1418 n = len(ob.data.splines)
1419 tabWrite('#declare %s = array[%s]{\n'%(dataname,(n+3)))
1420 tabWrite('spline{%s%s},\n'%(dataname,n))
1421 for i in range(n):
1422 tabWrite('spline{%s%s},\n'%(dataname,(i+1)))
1423 tabWrite('spline{%s1},\n'%(dataname))
1424 tabWrite('spline{%s2}\n'%(dataname))
1425 tabWrite('}\n')
1426 # Use some of the Meshmaker.inc macro, here inlined
1427 file.write('#macro CheckFileName(FileName)\n')
1428 file.write(' #local Len=strlen(FileName);\n')
1429 file.write(' #if(Len>0)\n')
1430 file.write(' #if(file_exists(FileName))\n')
1431 file.write(' #if(Len>=4)\n')
1432 file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
1433 file.write(' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n')
1434 file.write(' #local Return=99;\n')
1435 file.write(' #else\n')
1436 file.write(' #local Return=0;\n')
1437 file.write(' #end\n')
1438 file.write(' #else\n')
1439 file.write(' #local Return=0;\n')
1440 file.write(' #end\n')
1441 file.write(' #else\n')
1442 file.write(' #if(Len>=4)\n')
1443 file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
1444 file.write(' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n')
1445 file.write(' #if (strcmp(Ext,".obj")=0)\n')
1446 file.write(' #local Return=2;\n')
1447 file.write(' #end\n')
1448 file.write(' #if (strcmp(Ext,".pcm")=0)\n')
1449 file.write(' #local Return=3;\n')
1450 file.write(' #end\n')
1451 file.write(' #if (strcmp(Ext,".arr")=0)\n')
1452 file.write(' #local Return=4;\n')
1453 file.write(' #end\n')
1454 file.write(' #else\n')
1455 file.write(' #local Return=1;\n')
1456 file.write(' #end\n')
1457 file.write(' #else\n')
1458 file.write(' #local Return=1;\n')
1459 file.write(' #end\n')
1460 file.write(' #end\n')
1461 file.write(' #else\n')
1462 file.write(' #local Return=1;\n')
1463 file.write(' #end\n')
1464 file.write(' (Return)\n')
1465 file.write('#end\n')
1467 file.write('#macro BuildSpline(Arr, SplType)\n')
1468 file.write(' #local Ds=dimension_size(Arr,1);\n')
1469 file.write(' #local Asc=asc(strupr(SplType));\n')
1470 file.write(' #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
1471 file.write(' #local Asc=76;\n')
1472 file.write(' #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n')
1473 file.write(' #end\n')
1474 file.write(' spline {\n')
1475 file.write(' #switch (Asc)\n')
1476 file.write(' #case (67) //C cubic_spline\n')
1477 file.write(' cubic_spline\n')
1478 file.write(' #break\n')
1479 file.write(' #case (76) //L linear_spline\n')
1480 file.write(' linear_spline\n')
1481 file.write(' #break\n')
1482 file.write(' #case (78) //N linear_spline\n')
1483 file.write(' natural_spline\n')
1484 file.write(' #break\n')
1485 file.write(' #case (81) //Q Quadratic_spline\n')
1486 file.write(' quadratic_spline\n')
1487 file.write(' #break\n')
1488 file.write(' #end\n')
1489 file.write(' #local Add=1/((Ds-2)-1);\n')
1490 file.write(' #local J=0-Add;\n')
1491 file.write(' #local I=0;\n')
1492 file.write(' #while (I<Ds)\n')
1493 file.write(' J\n')
1494 file.write(' Arr[I]\n')
1495 file.write(' #local I=I+1;\n')
1496 file.write(' #local J=J+Add;\n')
1497 file.write(' #end\n')
1498 file.write(' }\n')
1499 file.write('#end\n')
1502 file.write('#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n')
1503 #suppressed some file checking from original macro because no more separate files
1504 file.write(' #local Write=0;\n')
1505 file.write(' #debug concat("\\n\\n Building mesh2: \\n - vertex_vectors\\n")\n')
1506 file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
1507 file.write(' #switch (Write)\n')
1508 file.write(' #case(1)\n')
1509 file.write(' #write(\n')
1510 file.write(' MeshFile,\n')
1511 file.write(' " vertex_vectors {\\n",\n')
1512 file.write(' " ", str(NumVertices,0,0),"\\n "\n')
1513 file.write(' )\n')
1514 file.write(' #break\n')
1515 file.write(' #case(2)\n')
1516 file.write(' #write(\n')
1517 file.write(' MeshFile,\n')
1518 file.write(' "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
1519 file.write(' )\n')
1520 file.write(' #break\n')
1521 file.write(' #case(3)\n')
1522 file.write(' #write(\n')
1523 file.write(' MeshFile,\n')
1524 file.write(' str(2*NumVertices,0,0),",\\n"\n')
1525 file.write(' )\n')
1526 file.write(' #break\n')
1527 file.write(' #case(4)\n')
1528 file.write(' #write(\n')
1529 file.write(' MeshFile,\n')
1530 file.write(' "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
1531 file.write(' )\n')
1532 file.write(' #break\n')
1533 file.write(' #end\n')
1534 file.write(' mesh2 {\n')
1535 file.write(' vertex_vectors {\n')
1536 file.write(' NumVertices\n')
1537 file.write(' #local I=0;\n')
1538 file.write(' #while (I<NumVertices)\n')
1539 file.write(' VecArr[I]\n')
1540 file.write(' #switch(Write)\n')
1541 file.write(' #case(1)\n')
1542 file.write(' #write(MeshFile, VecArr[I])\n')
1543 file.write(' #break\n')
1544 file.write(' #case(2)\n')
1545 file.write(' #write(\n')
1546 file.write(' MeshFile,\n')
1547 file.write(' "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n')
1548 file.write(' )\n')
1549 file.write(' #break\n')
1550 file.write(' #case(3)\n')
1551 file.write(' #write(\n')
1552 file.write(' MeshFile,\n')
1553 file.write(' VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n')
1554 file.write(' )\n')
1555 file.write(' #break\n')
1556 file.write(' #case(4)\n')
1557 file.write(' #write(MeshFile, VecArr[I])\n')
1558 file.write(' #break\n')
1559 file.write(' #end\n')
1560 file.write(' #local I=I+1;\n')
1561 file.write(' #if(Write=1 | Write=4)\n')
1562 file.write(' #if(mod(I,3)=0)\n')
1563 file.write(' #write(MeshFile,"\\n ")\n')
1564 file.write(' #end\n')
1565 file.write(' #end \n')
1566 file.write(' #end\n')
1567 file.write(' #switch(Write)\n')
1568 file.write(' #case(1)\n')
1569 file.write(' #write(MeshFile,"\\n }\\n")\n')
1570 file.write(' #break\n')
1571 file.write(' #case(2)\n')
1572 file.write(' #write(MeshFile,"\\n")\n')
1573 file.write(' #break\n')
1574 file.write(' #case(3)\n')
1575 file.write(' // do nothing\n')
1576 file.write(' #break\n')
1577 file.write(' #case(4) \n')
1578 file.write(' #write(MeshFile,"\\n}\\n")\n')
1579 file.write(' #break\n')
1580 file.write(' #end\n')
1581 file.write(' }\n')
1583 file.write(' #debug concat(" - normal_vectors\\n") \n')
1584 file.write(' #local NumVertices=dimension_size(NormArr,1);\n')
1585 file.write(' #switch(Write)\n')
1586 file.write(' #case(1)\n')
1587 file.write(' #write(\n')
1588 file.write(' MeshFile,\n')
1589 file.write(' " normal_vectors {\\n",\n')
1590 file.write(' " ", str(NumVertices,0,0),"\\n "\n')
1591 file.write(' )\n')
1592 file.write(' #break\n')
1593 file.write(' #case(2)\n')
1594 file.write(' #write(\n')
1595 file.write(' MeshFile,\n')
1596 file.write(' "# Normals: ",str(NumVertices,0,0),"\\n"\n')
1597 file.write(' )\n')
1598 file.write(' #break\n')
1599 file.write(' #case(3)\n')
1600 file.write(' // do nothing\n')
1601 file.write(' #break\n')
1602 file.write(' #case(4)\n')
1603 file.write(' #write(\n')
1604 file.write(' MeshFile,\n')
1605 file.write(' "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
1606 file.write(' )\n')
1607 file.write(' #break\n')
1608 file.write(' #end\n')
1609 file.write(' normal_vectors {\n')
1610 file.write(' NumVertices\n')
1611 file.write(' #local I=0;\n')
1612 file.write(' #while (I<NumVertices)\n')
1613 file.write(' NormArr[I]\n')
1614 file.write(' #switch(Write)\n')
1615 file.write(' #case(1)\n')
1616 file.write(' #write(MeshFile NormArr[I])\n')
1617 file.write(' #break\n')
1618 file.write(' #case(2)\n')
1619 file.write(' #write(\n')
1620 file.write(' MeshFile,\n')
1621 file.write(' "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n')
1622 file.write(' )\n')
1623 file.write(' #break\n')
1624 file.write(' #case(3)\n')
1625 file.write(' #write(\n')
1626 file.write(' MeshFile,\n')
1627 file.write(' NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n')
1628 file.write(' )\n')
1629 file.write(' #break\n')
1630 file.write(' #case(4)\n')
1631 file.write(' #write(MeshFile NormArr[I])\n')
1632 file.write(' #break\n')
1633 file.write(' #end\n')
1634 file.write(' #local I=I+1;\n')
1635 file.write(' #if(Write=1 | Write=4) \n')
1636 file.write(' #if(mod(I,3)=0)\n')
1637 file.write(' #write(MeshFile,"\\n ")\n')
1638 file.write(' #end\n')
1639 file.write(' #end\n')
1640 file.write(' #end\n')
1641 file.write(' #switch(Write)\n')
1642 file.write(' #case(1)\n')
1643 file.write(' #write(MeshFile,"\\n }\\n")\n')
1644 file.write(' #break\n')
1645 file.write(' #case(2)\n')
1646 file.write(' #write(MeshFile,"\\n")\n')
1647 file.write(' #break\n')
1648 file.write(' #case(3)\n')
1649 file.write(' //do nothing\n')
1650 file.write(' #break\n')
1651 file.write(' #case(4)\n')
1652 file.write(' #write(MeshFile,"\\n}\\n")\n')
1653 file.write(' #break\n')
1654 file.write(' #end\n')
1655 file.write(' }\n')
1657 file.write(' #debug concat(" - uv_vectors\\n") \n')
1658 file.write(' #local NumVertices=dimension_size(UVArr,1);\n')
1659 file.write(' #switch(Write)\n')
1660 file.write(' #case(1)\n')
1661 file.write(' #write(\n')
1662 file.write(' MeshFile, \n')
1663 file.write(' " uv_vectors {\\n",\n')
1664 file.write(' " ", str(NumVertices,0,0),"\\n "\n')
1665 file.write(' )\n')
1666 file.write(' #break\n')
1667 file.write(' #case(2)\n')
1668 file.write(' #write(\n')
1669 file.write(' MeshFile,\n')
1670 file.write(' "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n')
1671 file.write(' )\n')
1672 file.write(' #break\n')
1673 file.write(' #case(3)\n')
1674 file.write(' // do nothing, *.pcm does not support uv-vectors\n')
1675 file.write(' #break\n')
1676 file.write(' #case(4)\n')
1677 file.write(' #write(\n')
1678 file.write(' MeshFile,\n')
1679 file.write(' "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
1680 file.write(' )\n')
1681 file.write(' #break\n')
1682 file.write(' #end\n')
1683 file.write(' uv_vectors {\n')
1684 file.write(' NumVertices\n')
1685 file.write(' #local I=0;\n')
1686 file.write(' #while (I<NumVertices)\n')
1687 file.write(' UVArr[I]\n')
1688 file.write(' #switch(Write)\n')
1689 file.write(' #case(1)\n')
1690 file.write(' #write(MeshFile UVArr[I])\n')
1691 file.write(' #break\n')
1692 file.write(' #case(2)\n')
1693 file.write(' #write(\n')
1694 file.write(' MeshFile,\n')
1695 file.write(' "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n')
1696 file.write(' )\n')
1697 file.write(' #break\n')
1698 file.write(' #case(3)\n')
1699 file.write(' //do nothing\n')
1700 file.write(' #break\n')
1701 file.write(' #case(4)\n')
1702 file.write(' #write(MeshFile UVArr[I])\n')
1703 file.write(' #break\n')
1704 file.write(' #end\n')
1705 file.write(' #local I=I+1; \n')
1706 file.write(' #if(Write=1 | Write=4)\n')
1707 file.write(' #if(mod(I,3)=0)\n')
1708 file.write(' #write(MeshFile,"\\n ")\n')
1709 file.write(' #end \n')
1710 file.write(' #end\n')
1711 file.write(' #end \n')
1712 file.write(' #switch(Write)\n')
1713 file.write(' #case(1)\n')
1714 file.write(' #write(MeshFile,"\\n }\\n")\n')
1715 file.write(' #break\n')
1716 file.write(' #case(2)\n')
1717 file.write(' #write(MeshFile,"\\n")\n')
1718 file.write(' #break\n')
1719 file.write(' #case(3)\n')
1720 file.write(' //do nothing\n')
1721 file.write(' #break\n')
1722 file.write(' #case(4)\n')
1723 file.write(' #write(MeshFile,"\\n}\\n")\n')
1724 file.write(' #break\n')
1725 file.write(' #end\n')
1726 file.write(' }\n')
1727 file.write('\n')
1728 file.write(' #debug concat(" - face_indices\\n") \n')
1729 file.write(' #declare NumFaces=U*V*2;\n')
1730 file.write(' #switch(Write)\n')
1731 file.write(' #case(1)\n')
1732 file.write(' #write(\n')
1733 file.write(' MeshFile,\n')
1734 file.write(' " face_indices {\\n"\n')
1735 file.write(' " ", str(NumFaces,0,0),"\\n "\n')
1736 file.write(' )\n')
1737 file.write(' #break\n')
1738 file.write(' #case(2)\n')
1739 file.write(' #write (\n')
1740 file.write(' MeshFile,\n')
1741 file.write(' "# faces: ",str(NumFaces,0,0),"\\n"\n')
1742 file.write(' )\n')
1743 file.write(' #break\n')
1744 file.write(' #case(3)\n')
1745 file.write(' #write (\n')
1746 file.write(' MeshFile,\n')
1747 file.write(' "0,",str(NumFaces,0,0),",\\n"\n')
1748 file.write(' )\n')
1749 file.write(' #break\n')
1750 file.write(' #case(4)\n')
1751 file.write(' #write(\n')
1752 file.write(' MeshFile,\n')
1753 file.write(' "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n "\n')
1754 file.write(' )\n')
1755 file.write(' #break\n')
1756 file.write(' #end\n')
1757 file.write(' face_indices {\n')
1758 file.write(' NumFaces\n')
1759 file.write(' #local I=0;\n')
1760 file.write(' #local H=0;\n')
1761 file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
1762 file.write(' #while (I<V)\n')
1763 file.write(' #local J=0;\n')
1764 file.write(' #while (J<U)\n')
1765 file.write(' #local Ind=(I*U)+I+J;\n')
1766 file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
1767 file.write(' #switch(Write)\n')
1768 file.write(' #case(1)\n')
1769 file.write(' #write(\n')
1770 file.write(' MeshFile,\n')
1771 file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
1772 file.write(' )\n')
1773 file.write(' #break\n')
1774 file.write(' #case(2)\n')
1775 file.write(' #write(\n')
1776 file.write(' MeshFile,\n')
1777 file.write(' "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n')
1778 file.write(' "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n')
1779 file.write(' )\n')
1780 file.write(' #break\n')
1781 file.write(' #case(3)\n')
1782 file.write(' #write(\n')
1783 file.write(' MeshFile,\n')
1784 file.write(' Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n')
1785 file.write(' Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n')
1786 file.write(' )\n')
1787 file.write(' #break\n')
1788 file.write(' #case(4)\n')
1789 file.write(' #write(\n')
1790 file.write(' MeshFile,\n')
1791 file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
1792 file.write(' )\n')
1793 file.write(' #break\n')
1794 file.write(' #end\n')
1795 file.write(' #local J=J+1;\n')
1796 file.write(' #local H=H+1;\n')
1797 file.write(' #if(Write=1 | Write=4)\n')
1798 file.write(' #if(mod(H,3)=0)\n')
1799 file.write(' #write(MeshFile,"\\n ")\n')
1800 file.write(' #end \n')
1801 file.write(' #end\n')
1802 file.write(' #end\n')
1803 file.write(' #local I=I+1;\n')
1804 file.write(' #end\n')
1805 file.write(' }\n')
1806 file.write(' #switch(Write)\n')
1807 file.write(' #case(1)\n')
1808 file.write(' #write(MeshFile, "\\n }\\n}")\n')
1809 file.write(' #fclose MeshFile\n')
1810 file.write(' #debug concat(" Done writing\\n")\n')
1811 file.write(' #break\n')
1812 file.write(' #case(2)\n')
1813 file.write(' #fclose MeshFile\n')
1814 file.write(' #debug concat(" Done writing\\n")\n')
1815 file.write(' #break\n')
1816 file.write(' #case(3)\n')
1817 file.write(' #fclose MeshFile\n')
1818 file.write(' #debug concat(" Done writing\\n")\n')
1819 file.write(' #break\n')
1820 file.write(' #case(4)\n')
1821 file.write(' #write(MeshFile, "\\n}\\n}")\n')
1822 file.write(' #fclose MeshFile\n')
1823 file.write(' #debug concat(" Done writing\\n")\n')
1824 file.write(' #break\n')
1825 file.write(' #end\n')
1826 file.write(' }\n')
1827 file.write('#end\n')
1829 file.write('#macro MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)\n')
1830 file.write(' #declare Build=CheckFileName(FileName);\n')
1831 file.write(' #if(Build=0)\n')
1832 file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
1833 file.write(' #include FileName\n')
1834 file.write(' object{Surface}\n')
1835 file.write(' #else\n')
1836 file.write(' #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
1837 file.write(' #local NumFaces=SplRes*InterpRes*2;\n')
1838 file.write(' #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n')
1839 file.write(' #local VecArr=array[NumVertices]\n')
1840 file.write(' #local NormArr=array[NumVertices]\n')
1841 file.write(' #local UVArr=array[NumVertices]\n')
1842 file.write(' #local N=dimension_size(SplineArray,1);\n')
1843 file.write(' #local TempSplArr0=array[N];\n')
1844 file.write(' #local TempSplArr1=array[N];\n')
1845 file.write(' #local TempSplArr2=array[N];\n')
1846 file.write(' #local PosStep=1/SplRes;\n')
1847 file.write(' #local InterpStep=1/InterpRes;\n')
1848 file.write(' #local Count=0;\n')
1849 file.write(' #local Pos=0;\n')
1850 file.write(' #while(Pos<=1)\n')
1851 file.write(' #local I=0;\n')
1852 file.write(' #if (Pos=0)\n')
1853 file.write(' #while (I<N)\n')
1854 file.write(' #local Spl=spline{SplineArray[I]}\n')
1855 file.write(' #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n')
1856 file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
1857 file.write(' #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n')
1858 file.write(' #local I=I+1;\n')
1859 file.write(' #end\n')
1860 file.write(' #local S0=BuildSpline(TempSplArr0, Interp_type)\n')
1861 file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
1862 file.write(' #local S2=BuildSpline(TempSplArr2, Interp_type)\n')
1863 file.write(' #else\n')
1864 file.write(' #while (I<N)\n')
1865 file.write(' #local Spl=spline{SplineArray[I]}\n')
1866 file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
1867 file.write(' #local I=I+1;\n')
1868 file.write(' #end\n')
1869 file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
1870 file.write(' #end\n')
1871 file.write(' #local J=0;\n')
1872 file.write(' #while (J<=1)\n')
1873 file.write(' #local P0=<0,0,0>+S0(J);\n')
1874 file.write(' #local P1=<0,0,0>+S1(J);\n')
1875 file.write(' #local P2=<0,0,0>+S2(J);\n')
1876 file.write(' #local P3=<0,0,0>+S0(J+InterpStep);\n')
1877 file.write(' #local P4=<0,0,0>+S0(J-InterpStep);\n')
1878 file.write(' #local B1=P4-P0;\n')
1879 file.write(' #local B2=P2-P0;\n')
1880 file.write(' #local B3=P3-P0;\n')
1881 file.write(' #local B4=P1-P0;\n')
1882 file.write(' #local N1=vcross(B1,B2);\n')
1883 file.write(' #local N2=vcross(B2,B3);\n')
1884 file.write(' #local N3=vcross(B3,B4);\n')
1885 file.write(' #local N4=vcross(B4,B1);\n')
1886 file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
1887 file.write(' #local VecArr[Count]=P0;\n')
1888 file.write(' #local NormArr[Count]=Norm;\n')
1889 file.write(' #local UVArr[Count]=<J,Pos>;\n')
1890 file.write(' #local J=J+InterpStep;\n')
1891 file.write(' #local Count=Count+1;\n')
1892 file.write(' #end\n')
1893 file.write(' #local S2=spline{S0}\n')
1894 file.write(' #local S0=spline{S1}\n')
1895 file.write(' #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n')
1896 file.write(' #local Pos=Pos+PosStep;\n')
1897 file.write(' #end\n')
1898 file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n')
1899 file.write(' #end\n')
1900 file.write('#end\n\n')
1902 file.write('#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n')
1903 file.write(' #declare Build=CheckFileName(FileName);\n')
1904 file.write(' #if(Build=0)\n')
1905 file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
1906 file.write(' #include FileName\n')
1907 file.write(' object{Surface}\n')
1908 file.write(' #else\n')
1909 file.write(' #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
1910 file.write(' #local NumFaces=Iter_U*Iter_V*2;\n')
1911 file.write(' #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n')
1912 file.write(' #declare VecArr=array[NumVertices] \n')
1913 file.write(' #declare NormArr=array[NumVertices] \n')
1914 file.write(' #local UVArr=array[NumVertices] \n')
1915 file.write(' #local Spl1_0=Spl1(0);\n')
1916 file.write(' #local Spl2_0=Spl2(0);\n')
1917 file.write(' #local Spl3_0=Spl3(0);\n')
1918 file.write(' #local Spl4_0=Spl4(0);\n')
1919 file.write(' #local UStep=1/Iter_U;\n')
1920 file.write(' #local VStep=1/Iter_V;\n')
1921 file.write(' #local Count=0;\n')
1922 file.write(' #local I=0;\n')
1923 file.write(' #while (I<=1)\n')
1924 file.write(' #local Im=1-I;\n')
1925 file.write(' #local J=0;\n')
1926 file.write(' #while (J<=1)\n')
1927 file.write(' #local Jm=1-J;\n')
1928 file.write(' #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n')
1929 file.write(' #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n')
1930 file.write(' LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n')
1931 file.write(' #declare VecArr[Count]=P0;\n')
1932 file.write(' #local UVArr[Count]=<J,I>;\n')
1933 file.write(' #local J=J+UStep;\n')
1934 file.write(' #local Count=Count+1;\n')
1935 file.write(' #end\n')
1936 file.write(' #debug concat(\n')
1937 file.write(' "\r Done ", str(Count,0,0)," vertices : ",\n')
1938 file.write(' str(100*Count/NumVertices,0,2)," %"\n')
1939 file.write(' )\n')
1940 file.write(' #local I=I+VStep;\n')
1941 file.write(' #end\n')
1942 file.write(' #debug "\r Normals "\n')
1943 file.write(' #local Count=0;\n')
1944 file.write(' #local I=0;\n')
1945 file.write(' #while (I<=Iter_V)\n')
1946 file.write(' #local J=0;\n')
1947 file.write(' #while (J<=Iter_U)\n')
1948 file.write(' #local Ind=(I*Iter_U)+I+J;\n')
1949 file.write(' #local P0=VecArr[Ind];\n')
1950 file.write(' #if(J=0)\n')
1951 file.write(' #local P1=P0+(P0-VecArr[Ind+1]);\n')
1952 file.write(' #else\n')
1953 file.write(' #local P1=VecArr[Ind-1];\n')
1954 file.write(' #end\n')
1955 file.write(' #if (J=Iter_U)\n')
1956 file.write(' #local P2=P0+(P0-VecArr[Ind-1]);\n')
1957 file.write(' #else\n')
1958 file.write(' #local P2=VecArr[Ind+1];\n')
1959 file.write(' #end\n')
1960 file.write(' #if (I=0)\n')
1961 file.write(' #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n')
1962 file.write(' #else\n')
1963 file.write(' #local P3=VecArr[Ind-Iter_U-1];\n')
1964 file.write(' #end\n')
1965 file.write(' #if (I=Iter_V)\n')
1966 file.write(' #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n')
1967 file.write(' #else\n')
1968 file.write(' #local P4=VecArr[Ind+Iter_U+1];\n')
1969 file.write(' #end\n')
1970 file.write(' #local B1=P4-P0;\n')
1971 file.write(' #local B2=P2-P0;\n')
1972 file.write(' #local B3=P3-P0;\n')
1973 file.write(' #local B4=P1-P0;\n')
1974 file.write(' #local N1=vcross(B1,B2);\n')
1975 file.write(' #local N2=vcross(B2,B3);\n')
1976 file.write(' #local N3=vcross(B3,B4);\n')
1977 file.write(' #local N4=vcross(B4,B1);\n')
1978 file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
1979 file.write(' #declare NormArr[Count]=Norm;\n')
1980 file.write(' #local J=J+1;\n')
1981 file.write(' #local Count=Count+1;\n')
1982 file.write(' #end\n')
1983 file.write(' #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n')
1984 file.write(' #local I=I+1;\n')
1985 file.write(' #end\n')
1986 file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n')
1987 file.write(' #end\n')
1988 file.write('#end\n\n')
1990 if bezier_sweep == False:
1991 tabWrite("#declare %s =\n"%dataname)
1992 if ob.pov.curveshape == 'sphere_sweep' and bezier_sweep == False:
1993 tabWrite("union {\n")
1994 for spl in ob.data.splines:
1995 if spl.type != "BEZIER":
1996 spl_type = "linear"
1997 if spl.type == "NURBS":
1998 spl_type = "cubic"
1999 points=spl.points
2000 numPoints=len(points)
2001 if spl.use_cyclic_u:
2002 numPoints+=3
2004 tabWrite("sphere_sweep { %s_spline %s,\n"%(spl_type,numPoints))
2005 if spl.use_cyclic_u:
2006 pt1 = points[len(points)-1]
2007 wpt1 = pt1.co
2008 tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt1[0], wpt1[1], wpt1[2], pt1.radius*ob.data.bevel_depth))
2009 for pt in points:
2010 wpt = pt.co
2011 tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt[0], wpt[1], wpt[2], pt.radius*ob.data.bevel_depth))
2012 if spl.use_cyclic_u:
2013 for i in range (0,2):
2014 endPt=points[i]
2015 wpt = endPt.co
2016 tabWrite("<%.4g,%.4g,%.4g>,%.4g\n" %(wpt[0], wpt[1], wpt[2], endPt.radius*ob.data.bevel_depth))
2019 tabWrite("}\n")
2021 if ob.pov.curveshape == 'sor':
2022 for spl in ob.data.splines:
2023 if spl.type in {'POLY','NURBS'}:
2024 points=spl.points
2025 numPoints=len(points)
2026 tabWrite("sor { %s,\n"%numPoints)
2027 for pt in points:
2028 wpt = pt.co
2029 tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
2030 else:
2031 tabWrite("box { 0,0\n")
2032 if ob.pov.curveshape in {'lathe','prism'}:
2033 spl = ob.data.splines[0]
2034 if spl.type == "BEZIER":
2035 points=spl.bezier_points
2036 lenCur=len(points)-1
2037 lenPts=lenCur*4
2038 ifprism = ''
2039 if ob.pov.curveshape in {'prism'}:
2040 height = ob.data.extrude
2041 ifprism = '-%s, %s,'%(height, height)
2042 lenCur+=1
2043 lenPts+=4
2044 tabWrite("%s { bezier_spline %s %s,\n"%(ob.pov.curveshape,ifprism,lenPts))
2045 for i in range(0,lenCur):
2046 p1=points[i].co
2047 pR=points[i].handle_right
2048 end = i+1
2049 if i == lenCur-1 and ob.pov.curveshape in {'prism'}:
2050 end = 0
2051 pL=points[end].handle_left
2052 p2=points[end].co
2053 line="<%.4g,%.4g>"%(p1[0],p1[1])
2054 line+="<%.4g,%.4g>"%(pR[0],pR[1])
2055 line+="<%.4g,%.4g>"%(pL[0],pL[1])
2056 line+="<%.4g,%.4g>"%(p2[0],p2[1])
2057 tabWrite("%s\n" %line)
2058 else:
2059 points=spl.points
2060 lenCur=len(points)
2061 lenPts=lenCur
2062 ifprism = ''
2063 if ob.pov.curveshape in {'prism'}:
2064 height = ob.data.extrude
2065 ifprism = '-%s, %s,'%(height, height)
2066 lenPts+=3
2067 spl_type = 'quadratic'
2068 if spl.type == 'POLY':
2069 spl_type = 'linear'
2070 tabWrite("%s { %s_spline %s %s,\n"%(ob.pov.curveshape,spl_type,ifprism,lenPts))
2071 if ob.pov.curveshape in {'prism'}:
2072 pt = points[len(points)-1]
2073 wpt = pt.co
2074 tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
2075 for pt in points:
2076 wpt = pt.co
2077 tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
2078 if ob.pov.curveshape in {'prism'}:
2079 for i in range(2):
2080 pt = points[i]
2081 wpt = pt.co
2082 tabWrite("<%.4g,%.4g>\n" %(wpt[0], wpt[1]))
2083 if bezier_sweep:
2084 spl = ob.data.splines[0]
2085 points=spl.bezier_points
2086 lenCur = len(points)-1
2087 numPoints = lenCur*4
2088 if spl.use_cyclic_u:
2089 lenCur += 1
2090 numPoints += 4
2091 tabWrite("#declare %s_bezier_points = array[%s]{\n"%(dataname,numPoints))
2092 for i in range(lenCur):
2093 p1=points[i].co
2094 pR=points[i].handle_right
2095 end = i+1
2096 if spl.use_cyclic_u and i == (lenCur - 1):
2097 end = 0
2098 pL=points[end].handle_left
2099 p2=points[end].co
2100 line="<%.4g,%.4g,%.4f>"%(p1[0],p1[1],p1[2])
2101 line+="<%.4g,%.4g,%.4f>"%(pR[0],pR[1],pR[2])
2102 line+="<%.4g,%.4g,%.4f>"%(pL[0],pL[1],pL[2])
2103 line+="<%.4g,%.4g,%.4f>"%(p2[0],p2[1],p2[2])
2104 tabWrite("%s\n" %line)
2105 tabWrite("}\n")
2106 #tabWrite('#include "bezier_spheresweep.inc"\n') #now inlined
2107 tabWrite('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
2108 if ob.pov.curveshape in {'loft'}:
2109 tabWrite('object {MSM(%s,%s,"c",%s,"")\n'%(dataname,ob.pov.res_u,ob.pov.res_v))
2110 if ob.pov.curveshape in {'birail'}:
2111 splines = '%s1,%s2,%s3,%s4'%(dataname,dataname,dataname,dataname)
2112 tabWrite('object {Coons(%s, %s, %s, "")\n'%(splines,ob.pov.res_u,ob.pov.res_v))
2113 povMatName = "Default_texture"
2114 if ob.active_material:
2115 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2116 try:
2117 material = ob.active_material
2118 writeObjectMaterial(material, ob)
2119 except IndexError:
2120 print(me)
2121 #tabWrite("texture {%s}\n"%povMatName)
2122 if ob.pov.curveshape in {'prism'}:
2123 tabWrite("rotate <90,0,0>\n")
2124 tabWrite("scale y*-1\n" )
2125 tabWrite("}\n")
2127 #################################################################
2130 def exportMeta(metas):
2132 # TODO - blenders 'motherball' naming is not supported.
2134 if comments and len(metas) >= 1:
2135 file.write("//--Blob objects--\n\n")
2137 for ob in metas:
2138 meta = ob.data
2140 # important because no elements will break parsing.
2141 elements = [elem for elem in meta.elements if elem.type in {'BALL', 'ELLIPSOID'}]
2143 if elements:
2144 tabWrite("blob {\n")
2145 tabWrite("threshold %.4g\n" % meta.threshold)
2146 importance = ob.pov.importance_value
2148 try:
2149 material = meta.materials[0] # lame! - blender cant do enything else.
2150 except:
2151 material = None
2153 for elem in elements:
2154 loc = elem.co
2156 stiffness = elem.stiffness
2157 if elem.use_negative:
2158 stiffness = - stiffness
2160 if elem.type == 'BALL':
2162 tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" % \
2163 (loc.x, loc.y, loc.z, elem.radius, stiffness))
2165 # After this wecould do something simple like...
2166 # "pigment {Blue} }"
2167 # except we'll write the color
2169 elif elem.type == 'ELLIPSOID':
2170 # location is modified by scale
2171 tabWrite("sphere { <%.6g, %.6g, %.6g>, %.4g, %.4g }\n" % \
2172 (loc.x / elem.size_x, loc.y / elem.size_y, loc.z / elem.size_z,
2173 elem.radius, stiffness))
2174 tabWrite("scale <%.6g, %.6g, %.6g> \n" % \
2175 (elem.size_x, elem.size_y, elem.size_z))
2177 if material:
2178 diffuse_color = material.diffuse_color
2179 trans = 1.0 - material.alpha
2180 if material.use_transparency and material.transparency_method == 'RAYTRACE':
2181 povFilter = material.raytrace_transparency.filter * (1.0 - material.alpha)
2182 trans = (1.0 - material.alpha) - povFilter
2183 else:
2184 povFilter = 0.0
2186 material_finish = materialNames[material.name]
2188 tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>} \n" % \
2189 (diffuse_color[0], diffuse_color[1], diffuse_color[2],
2190 povFilter, trans))
2191 tabWrite("finish {%s}\n" % safety(material_finish, Level=2))
2193 else:
2194 tabWrite("pigment {rgb<1 1 1>} \n")
2195 # Write the finish last.
2196 tabWrite("finish {%s}\n" % (safety(DEF_MAT_NAME, Level=2)))
2198 writeObjectMaterial(material, ob)
2200 writeMatrix(global_matrix * ob.matrix_world)
2201 # Importance for radiosity sampling added here
2202 tabWrite("radiosity { \n")
2203 tabWrite("importance %3g \n" % importance)
2204 tabWrite("}\n")
2206 tabWrite("}\n") # End of Metaball block
2208 if comments and len(metas) >= 1:
2209 file.write("\n")
2211 # objectNames = {}
2212 DEF_OBJ_NAME = "Default"
2214 def exportMeshes(scene, sel):
2215 # obmatslist = []
2216 # def hasUniqueMaterial():
2217 # # Grab materials attached to object instances ...
2218 # if hasattr(ob, 'material_slots'):
2219 # for ms in ob.material_slots:
2220 # if ms.material is not None and ms.link == 'OBJECT':
2221 # if ms.material in obmatslist:
2222 # return False
2223 # else:
2224 # obmatslist.append(ms.material)
2225 # return True
2226 # def hasObjectMaterial(ob):
2227 # # Grab materials attached to object instances ...
2228 # if hasattr(ob, 'material_slots'):
2229 # for ms in ob.material_slots:
2230 # if ms.material is not None and ms.link == 'OBJECT':
2231 # # If there is at least one material slot linked to the object
2232 # # and not the data (mesh), always create a new, "private" data instance.
2233 # return True
2234 # return False
2235 # For objects using local material(s) only!
2236 # This is a mapping between a tuple (dataname, materialnames, ...), and the POV dataname.
2237 # As only objects using:
2238 # * The same data.
2239 # * EXACTLY the same materials, in EXACTLY the same sockets.
2240 # ... can share a same instance in POV export.
2241 obmats2data = {}
2243 def checkObjectMaterials(ob, name, dataname):
2244 if hasattr(ob, 'material_slots'):
2245 has_local_mats = False
2246 key = [dataname]
2247 for ms in ob.material_slots:
2248 if ms.material is not None:
2249 key.append(ms.material.name)
2250 if ms.link == 'OBJECT' and not has_local_mats:
2251 has_local_mats = True
2252 else:
2253 # Even if the slot is empty, it is important to grab it...
2254 key.append("")
2255 if has_local_mats:
2256 # If this object uses local material(s), lets find if another object
2257 # using the same data and exactly the same list of materials
2258 # (in the same slots) has already been processed...
2259 # Note that here also, we use object name as new, unique dataname for Pov.
2260 key = tuple(key) # Lists are not hashable...
2261 if key not in obmats2data:
2262 obmats2data[key] = name
2263 return obmats2data[key]
2264 return None
2266 data_ref = {}
2268 def store(scene, ob, name, dataname, matrix):
2269 # The Object needs to be written at least once but if its data is
2270 # already in data_ref this has already been done.
2271 # This func returns the "povray" name of the data, or None
2272 # if no writing is needed.
2273 if ob.is_modified(scene, 'RENDER'):
2274 # Data modified.
2275 # Create unique entry in data_ref by using object name
2276 # (always unique in Blender) as data name.
2277 data_ref[name] = [(name, MatrixAsPovString(matrix))]
2278 return name
2279 # Here, we replace dataname by the value returned by checkObjectMaterials, only if
2280 # it is not evaluated to False (i.e. only if the object uses some local material(s)).
2281 dataname = checkObjectMaterials(ob, name, dataname) or dataname
2282 if dataname in data_ref:
2283 # Data already known, just add the object instance.
2284 data_ref[dataname].append((name, MatrixAsPovString(matrix)))
2285 # No need to write data
2286 return None
2287 else:
2288 # Data not yet processed, create a new entry in data_ref.
2289 data_ref[dataname] = [(name, MatrixAsPovString(matrix))]
2290 return dataname
2293 def exportSmoke(smoke_obj_name):
2294 #if LuxManager.CurrentScene.name == 'preview':
2295 #return 1, 1, 1, 1.0
2296 #else:
2297 flowtype = -1
2298 smoke_obj = bpy.data.objects[smoke_obj_name]
2299 domain = None
2301 # Search smoke domain target for smoke modifiers
2302 for mod in smoke_obj.modifiers:
2303 if mod.name == 'Smoke':
2304 if mod.smoke_type == 'FLOW':
2305 if mod.flow_settings.smoke_flow_type == 'BOTH':
2306 flowtype = 2
2307 else:
2308 if mod.flow_settings.smoke_flow_type == 'SMOKE':
2309 flowtype = 0
2310 else:
2311 if mod.flow_settings.smoke_flow_type == 'FIRE':
2312 flowtype = 1
2314 if mod.smoke_type == 'DOMAIN':
2315 domain = smoke_obj
2316 smoke_modifier = mod
2318 eps = 0.000001
2319 if domain is not None:
2320 #if bpy.app.version[0] >= 2 and bpy.app.version[1] >= 71:
2321 # Blender version 2.71 supports direct access to smoke data structure
2322 set = mod.domain_settings
2323 channeldata = []
2324 for v in set.density_grid:
2325 channeldata.append(v.real)
2326 print(v.real)
2327 ## Usage en voxel texture:
2328 # channeldata = []
2329 # if channel == 'density':
2330 # for v in set.density_grid:
2331 # channeldata.append(v.real)
2333 # if channel == 'fire':
2334 # for v in set.flame_grid:
2335 # channeldata.append(v.real)
2337 resolution = set.resolution_max
2338 big_res = []
2339 big_res.append(set.domain_resolution[0])
2340 big_res.append(set.domain_resolution[1])
2341 big_res.append(set.domain_resolution[2])
2343 if set.use_high_resolution:
2344 big_res[0] = big_res[0] * (set.amplify + 1)
2345 big_res[1] = big_res[1] * (set.amplify + 1)
2346 big_res[2] = big_res[2] * (set.amplify + 1)
2347 # else:
2348 # p = []
2349 ##gather smoke domain settings
2350 # BBox = domain.bound_box
2351 # p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
2352 # p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
2353 # set = mod.domain_settings
2354 # resolution = set.resolution_max
2355 # smokecache = set.point_cache
2356 # ret = read_cache(smokecache, set.use_high_resolution, set.amplify + 1, flowtype)
2357 # res_x = ret[0]
2358 # res_y = ret[1]
2359 # res_z = ret[2]
2360 # density = ret[3]
2361 # fire = ret[4]
2363 # if res_x * res_y * res_z > 0:
2364 ##new cache format
2365 # big_res = []
2366 # big_res.append(res_x)
2367 # big_res.append(res_y)
2368 # big_res.append(res_z)
2369 # else:
2370 # max = domain.dimensions[0]
2371 # if (max - domain.dimensions[1]) < -eps:
2372 # max = domain.dimensions[1]
2374 # if (max - domain.dimensions[2]) < -eps:
2375 # max = domain.dimensions[2]
2377 # big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
2378 # int(round(resolution * domain.dimensions[1] / max, 0)),
2379 # int(round(resolution * domain.dimensions[2] / max, 0))]
2381 # if set.use_high_resolution:
2382 # big_res = [big_res[0] * (set.amplify + 1), big_res[1] * (set.amplify + 1),
2383 # big_res[2] * (set.amplify + 1)]
2385 # if channel == 'density':
2386 # channeldata = density
2388 # if channel == 'fire':
2389 # channeldata = fire
2391 # sc_fr = '%s/%s/%s/%05d' % (efutil.export_path, efutil.scene_filename(), bpy.context.scene.name, bpy.context.scene.frame_current)
2392 # if not os.path.exists( sc_fr ):
2393 # os.makedirs(sc_fr)
2395 # smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
2396 # smoke_path = '/'.join([sc_fr, smoke_filename])
2398 # with open(smoke_path, 'wb') as smoke_file:
2399 # # Binary densitygrid file format
2401 # # File header
2402 # smoke_file.write(b'SMOKE') #magic number
2403 # smoke_file.write(struct.pack('<I', big_res[0]))
2404 # smoke_file.write(struct.pack('<I', big_res[1]))
2405 # smoke_file.write(struct.pack('<I', big_res[2]))
2406 # Density data
2407 # smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
2409 # LuxLog('Binary SMOKE file written: %s' % (smoke_path))
2411 #return big_res[0], big_res[1], big_res[2], channeldata
2413 mydf3 = df3.df3(big_res[0],big_res[1],big_res[2])
2414 sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
2415 for x in range(sim_sizeX):
2416 for y in range(sim_sizeY):
2417 for z in range(sim_sizeZ):
2418 mydf3.set(x, y, z, channeldata[((z * sim_sizeY + y) * sim_sizeX + x)])
2420 mydf3.exportDF3(smokePath)
2421 print('Binary smoke.df3 file written in preview directory')
2422 if comments:
2423 file.write("\n//--Smoke--\n\n")
2425 # Note: We start with a default unit cube.
2426 # This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
2427 # coordinates from the start, and avoid scale/translate operations at the end...
2428 file.write("box{<0,0,0>, <1,1,1>\n")
2429 file.write(" pigment{ rgbt 1 }\n")
2430 file.write(" hollow\n")
2431 file.write(" interior{ //---------------------\n")
2432 file.write(" media{ method 3\n")
2433 file.write(" emission <1,1,1>*1\n")# 0>1 for dark smoke to white vapour
2434 file.write(" scattering{ 1, // Type\n")
2435 file.write(" <1,1,1>*0.1\n")
2436 file.write(" } // end scattering\n")
2437 file.write(" density{density_file df3 \"%s\"\n" % (smokePath))
2438 file.write(" color_map {\n")
2439 file.write(" [0.00 rgb 0]\n")
2440 file.write(" [0.05 rgb 0]\n")
2441 file.write(" [0.20 rgb 0.2]\n")
2442 file.write(" [0.30 rgb 0.6]\n")
2443 file.write(" [0.40 rgb 1]\n")
2444 file.write(" [1.00 rgb 1]\n")
2445 file.write(" } // end color_map\n")
2446 file.write(" } // end of density\n")
2447 file.write(" samples %i // higher = more precise\n" % resolution)
2448 file.write(" } // end of media --------------------------\n")
2449 file.write(" } // end of interior\n")
2451 # START OF TRANSFORMATIONS
2453 # Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
2454 # loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
2455 bbox = smoke_obj.bound_box
2456 dim = [abs(bbox[6][0] - bbox[0][0]), abs(bbox[6][1] - bbox[0][1]), abs(bbox[6][2] - bbox[0][2])]
2458 # We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
2459 file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
2461 # We offset our cube such that (0,0,0) coordinate matches Blender's object center.
2462 file.write("translate<%.6g,%.6g,%.6g>\n" % (bbox[0][0], bbox[0][1], bbox[0][2]))
2464 # We apply object's transformations to get final loc/rot/size in world space!
2465 # Note: we could combine the two previous transformations with this matrix directly...
2466 writeMatrix(global_matrix * smoke_obj.matrix_world)
2468 # END OF TRANSFORMATIONS
2470 file.write("}\n")
2473 #file.write(" interpolate 1\n")
2474 #file.write(" frequency 0\n")
2475 #file.write(" }\n")
2476 #file.write("}\n")
2478 ob_num = 0
2479 for ob in sel:
2480 ob_num += 1
2482 # XXX I moved all those checks here, as there is no need to compute names
2483 # for object we won't export here!
2484 if (ob.type in {'LAMP', 'CAMERA', 'EMPTY',
2485 'META', 'ARMATURE', 'LATTICE'}):
2486 continue
2487 smokeFlag=False
2488 for mod in ob.modifiers:
2489 if mod and hasattr(mod, 'smoke_type'):
2490 smokeFlag=True
2491 if (mod.smoke_type == 'DOMAIN'):
2492 exportSmoke(ob.name)
2493 break # don't render domain mesh or flow emitter mesh, skip to next object.
2494 if not smokeFlag:
2495 # Export Hair
2496 renderEmitter = True
2497 if hasattr(ob, 'particle_systems'):
2498 renderEmitter = False
2499 for pSys in ob.particle_systems:
2500 if pSys.settings.use_render_emitter:
2501 renderEmitter = True
2502 for mod in [m for m in ob.modifiers if (m is not None) and (m.type == 'PARTICLE_SYSTEM')]:
2503 if (pSys.settings.render_type == 'PATH') and mod.show_render and (pSys.name == mod.particle_system.name):
2504 tstart = time.time()
2505 texturedHair=0
2506 if ob.active_material is not None:
2507 pmaterial = ob.material_slots[pSys.settings.material - 1].material
2508 for th in pmaterial.texture_slots:
2509 if th and th.use:
2510 if (th.texture.type == 'IMAGE' and th.texture.image) or th.texture.type != 'IMAGE':
2511 if th.use_map_color_diffuse:
2512 texturedHair=1
2513 if pmaterial.strand.use_blender_units:
2514 strandStart = pmaterial.strand.root_size
2515 strandEnd = pmaterial.strand.tip_size
2516 strandShape = pmaterial.strand.shape
2517 else: # Blender unit conversion
2518 strandStart = pmaterial.strand.root_size / 200.0
2519 strandEnd = pmaterial.strand.tip_size / 200.0
2520 strandShape = pmaterial.strand.shape
2521 else:
2522 pmaterial = "default" # No material assigned in blender, use default one
2523 strandStart = 0.01
2524 strandEnd = 0.01
2525 strandShape = 0.0
2526 # Set the number of particles to render count rather than 3d view display
2527 pSys.set_resolution(scene, ob, 'RENDER')
2528 steps = pSys.settings.draw_step
2529 steps = 3 ** steps # or (power of 2 rather than 3) + 1 # Formerly : len(particle.hair_keys)
2531 totalNumberOfHairs = ( len(pSys.particles) + len(pSys.child_particles) )
2532 #hairCounter = 0
2533 file.write('#declare HairArray = array[%i] {\n' % totalNumberOfHairs)
2534 for pindex in range(0, totalNumberOfHairs):
2536 #if particle.is_exist and particle.is_visible:
2537 #hairCounter += 1
2538 #controlPointCounter = 0
2539 # Each hair is represented as a separate sphere_sweep in POV-Ray.
2541 file.write('sphere_sweep{')
2542 if pSys.settings.use_hair_bspline:
2543 file.write('b_spline ')
2544 file.write('%i,\n' % (steps + 2)) # +2 because the first point needs tripling to be more than a handle in POV
2545 else:
2546 file.write('linear_spline ')
2547 file.write('%i,\n' % (steps))
2548 #changing world coordinates to object local coordinates by multiplying with inverted matrix
2549 initCo = ob.matrix_world.inverted()*(pSys.co_hair(ob, pindex, 0))
2550 if ob.active_material is not None:
2551 pmaterial = ob.material_slots[pSys.settings.material-1].material
2552 for th in pmaterial.texture_slots:
2553 if th and th.use and th.use_map_color_diffuse:
2554 #treat POV textures as bitmaps
2555 if (th.texture.type == 'IMAGE' and th.texture.image and th.texture_coords == 'UV' and ob.data.uv_textures != None): # or (th.texture.pov.tex_pattern_type != 'emulator' and th.texture_coords == 'UV' and ob.data.uv_textures != None):
2556 image=th.texture.image
2557 image_width = image.size[0]
2558 image_height = image.size[1]
2559 image_pixels = image.pixels[:]
2560 uv_co = pSys.uv_on_emitter(mod, pSys.particles[pindex], pindex, 0)
2561 x_co = round(uv_co[0] * (image_width - 1))
2562 y_co = round(uv_co[1] * (image_height - 1))
2563 pixelnumber = (image_width * y_co) + x_co
2564 r = image_pixels[pixelnumber*4]
2565 g = image_pixels[pixelnumber*4+1]
2566 b = image_pixels[pixelnumber*4+2]
2567 a = image_pixels[pixelnumber*4+3]
2568 initColor=(r,g,b,a)
2569 else:
2570 #only overwrite variable for each competing texture for now
2571 initColor=th.texture.evaluate((initCo[0],initCo[1],initCo[2]))
2572 for step in range(0, steps):
2573 co = pSys.co_hair(ob, pindex, step)
2574 #for controlPoint in particle.hair_keys:
2575 if pSys.settings.clump_factor != 0:
2576 hDiameter = pSys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
2577 elif step == 0:
2578 hDiameter = strandStart
2579 else:
2580 hDiameter += (strandEnd-strandStart)/(pSys.settings.draw_step+1) #XXX +1 or not?
2581 if step == 0 and pSys.settings.use_hair_bspline:
2582 # Write three times the first point to compensate pov Bezier handling
2583 file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (co[0], co[1], co[2], abs(hDiameter)))
2584 file.write('<%.6g,%.6g,%.6g>,%.7g,\n' % (co[0], co[1], co[2], abs(hDiameter)))
2585 #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.
2586 #file.write(',\n')
2587 #controlPointCounter += 1
2588 #totalNumberOfHairs += len(pSys.particles)# len(particle.hair_keys)
2590 # Each control point is written out, along with the radius of the
2591 # hair at that point.
2592 file.write('<%.6g,%.6g,%.6g>,%.7g' % (co[0], co[1], co[2], abs(hDiameter)))
2594 # All coordinates except the last need a following comma.
2596 if step != steps - 1:
2597 file.write(',\n')
2598 else:
2599 if texturedHair:
2600 # Write pigment and alpha (between Pov and Blender alpha 0 and 1 are reversed)
2601 file.write('\npigment{ color rgbf < %.3g, %.3g, %.3g, %.3g> }\n' %(initColor[0], initColor[1], initColor[2], 1.0-initColor[3]))
2602 # End the sphere_sweep declaration for this hair
2603 file.write('}\n')
2605 # All but the final sphere_sweep (each array element) needs a terminating comma.
2607 if pindex != totalNumberOfHairs:
2608 file.write(',\n')
2609 else:
2610 file.write('\n')
2612 # End the array declaration.
2614 file.write('}\n')
2615 file.write('\n')
2617 if not texturedHair:
2618 # Pick up the hair material diffuse color and create a default POV-Ray hair texture.
2620 file.write('#ifndef (HairTexture)\n')
2621 file.write(' #declare HairTexture = texture {\n')
2622 file.write(' pigment {rgbt <%s,%s,%s,%s>}\n' % (pmaterial.diffuse_color[0], pmaterial.diffuse_color[1], pmaterial.diffuse_color[2], (pmaterial.strand.width_fade + 0.05)))
2623 file.write(' }\n')
2624 file.write('#end\n')
2625 file.write('\n')
2627 # Dynamically create a union of the hairstrands (or a subset of them).
2628 # By default use every hairstrand, commented line is for hand tweaking test renders.
2629 file.write('//Increasing HairStep divides the amount of hair for test renders.\n')
2630 file.write('#ifndef(HairStep) #declare HairStep = 1; #end\n')
2631 file.write('union{\n')
2632 file.write(' #local I = 0;\n')
2633 file.write(' #while (I < %i)\n' % totalNumberOfHairs)
2634 file.write(' object {HairArray[I]')
2635 if not texturedHair:
2636 file.write(' texture{HairTexture}\n')
2637 else:
2638 file.write('\n')
2639 # Translucency of the hair:
2640 file.write(' hollow\n')
2641 file.write(' double_illuminate\n')
2642 file.write(' interior {\n')
2643 file.write(' ior 1.45\n')
2644 file.write(' media {\n')
2645 file.write(' scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n')
2646 file.write(' absorption 10/<0.83, 0.75, 0.15>\n')
2647 file.write(' samples 1\n')
2648 file.write(' method 2\n')
2649 file.write(' density {\n')
2650 file.write(' color_map {\n')
2651 file.write(' [0.0 rgb <0.83, 0.45, 0.35>]\n')
2652 file.write(' [0.5 rgb <0.8, 0.8, 0.4>]\n')
2653 file.write(' [1.0 rgb <1,1,1>]\n')
2654 file.write(' }\n')
2655 file.write(' }\n')
2656 file.write(' }\n')
2657 file.write(' }\n')
2658 file.write(' }\n')
2660 file.write(' #local I = I + HairStep;\n')
2661 file.write(' #end\n')
2663 writeMatrix(global_matrix * ob.matrix_world)
2666 file.write('}')
2667 print('Totals hairstrands written: %i' % totalNumberOfHairs)
2668 print('Number of tufts (particle systems)', len(ob.particle_systems))
2670 # Set back the displayed number of particles to preview count
2671 pSys.set_resolution(scene, ob, 'PREVIEW')
2673 if renderEmitter == False:
2674 continue #don't render mesh, skip to next object.
2676 #############################################
2677 # Generating a name for object just like materials to be able to use it
2678 # (baking for now or anything else).
2679 # XXX I don't understand that:&nbsp;if we are here, sel if a non-empty iterable,
2680 # so this condition is always True, IMO -- mont29
2681 if sel:
2682 name_orig = "OB" + ob.name
2683 dataname_orig = "DATA" + ob.data.name
2684 else:
2685 name_orig = DEF_OBJ_NAME
2686 dataname_orig = DEF_OBJ_NAME
2687 name = string_strip_hyphen(bpy.path.clean_name(name_orig))
2688 dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
2689 ## for slot in ob.material_slots:
2690 ## if slot.material is not None and slot.link == 'OBJECT':
2691 ## obmaterial = slot.material
2693 #############################################
2695 if info_callback:
2696 info_callback("Object %2.d of %2.d (%s)" % (ob_num, len(sel), ob.name))
2698 #if ob.type != 'MESH':
2699 # continue
2700 # me = ob.data
2702 matrix = global_matrix * ob.matrix_world
2703 povdataname = store(scene, ob, name, dataname, matrix)
2704 if povdataname is None:
2705 print("This is an instance")
2706 continue
2708 print("Writing Down First Occurence")
2710 ############################################Povray Primitives
2711 # special exportCurves() function takes care of writing
2712 # lathe, sphere_sweep, birail, and loft
2713 if ob.type == 'CURVE' and (ob.pov.curveshape in
2714 {'lathe', 'sphere_sweep', 'loft'}):
2715 continue #Don't render proxy mesh, skip to next object
2717 if ob.pov.object_as == 'ISOSURFACE':
2718 tabWrite("#declare %s = isosurface{ \n"% povdataname)
2719 tabWrite("function{ \n")
2720 textName = ob.pov.iso_function_text
2721 if textName:
2722 node_tree = bpy.context.scene.node_tree
2723 for node in node_tree.nodes:
2724 if node.bl_idname == "IsoPropsNode" and node.label == ob.name:
2725 for inp in node.inputs:
2726 if inp:
2727 tabWrite("#declare %s = %.6g;\n"%(inp.name,inp.default_value))
2729 text = bpy.data.texts[textName]
2730 for line in text.lines:
2731 split = line.body.split()
2732 if split[0] != "#declare":
2733 tabWrite("%s\n"%line.body)
2734 else:
2735 tabWrite("abs(x) - 2 + y")
2736 tabWrite("}\n")
2737 tabWrite("threshold %.6g\n"%ob.pov.threshold)
2738 tabWrite("max_gradient %.6g\n"%ob.pov.max_gradient)
2739 tabWrite("accuracy %.6g\n"%ob.pov.accuracy)
2740 tabWrite("contained_by { ")
2741 if ob.pov.contained_by == "sphere":
2742 tabWrite("sphere {0,%.6g}}\n"%ob.pov.container_scale)
2743 else:
2744 tabWrite("box {-%.6g,%.6g}}\n"%(ob.pov.container_scale,ob.pov.container_scale))
2745 if ob.pov.all_intersections:
2746 tabWrite("all_intersections\n")
2747 else:
2748 if ob.pov.max_trace > 1:
2749 tabWrite("max_trace %.6g\n"%ob.pov.max_trace)
2750 povMatName = "Default_texture"
2751 if ob.active_material:
2752 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2753 try:
2754 material = ob.active_material
2755 writeObjectMaterial(material, ob)
2756 except IndexError:
2757 print(me)
2758 #tabWrite("texture {%s}\n"%povMatName)
2759 tabWrite("scale %.6g\n"%(1/ob.pov.container_scale))
2760 tabWrite("}\n")
2761 continue #Don't render proxy mesh, skip to next object
2763 if ob.pov.object_as == 'SUPERELLIPSOID':
2764 tabWrite("#declare %s = superellipsoid{ <%.4f,%.4f>\n"%(povdataname,ob.pov.se_n2,ob.pov.se_n1))
2765 povMatName = "Default_texture"
2766 if ob.active_material:
2767 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2768 try:
2769 material = ob.active_material
2770 writeObjectMaterial(material, ob)
2771 except IndexError:
2772 print(me)
2773 #tabWrite("texture {%s}\n"%povMatName)
2774 write_object_modifiers(scene,ob,file)
2775 tabWrite("}\n")
2776 continue #Don't render proxy mesh, skip to next object
2779 if ob.pov.object_as == 'SUPERTORUS':
2780 rMajor = ob.pov.st_major_radius
2781 rMinor = ob.pov.st_minor_radius
2782 ring = ob.pov.st_ring
2783 cross = ob.pov.st_cross
2784 accuracy=ob.pov.st_accuracy
2785 gradient=ob.pov.st_max_gradient
2786 ############Inline Supertorus macro
2787 file.write("#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n")
2788 file.write(" #local CP = 2/MinorControl;\n")
2789 file.write(" #local RP = 2/MajorControl;\n")
2790 file.write(" isosurface {\n")
2791 file.write(" function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n")
2792 file.write(" threshold 0\n")
2793 file.write(" contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n")
2794 file.write(" #if(MaxGradient >= 1)\n")
2795 file.write(" max_gradient MaxGradient\n")
2796 file.write(" #else\n")
2797 file.write(" evaluate 1, 10, 0.1\n")
2798 file.write(" #end\n")
2799 file.write(" accuracy Accuracy\n")
2800 file.write(" }\n")
2801 file.write("#end\n")
2802 ############
2803 tabWrite("#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n"%(povdataname,rMajor,rMinor,ring,cross,accuracy,gradient))
2804 povMatName = "Default_texture"
2805 if ob.active_material:
2806 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2807 try:
2808 material = ob.active_material
2809 writeObjectMaterial(material, ob)
2810 except IndexError:
2811 print(me)
2812 #tabWrite("texture {%s}\n"%povMatName)
2813 write_object_modifiers(scene,ob,file)
2814 tabWrite("rotate x*90\n")
2815 tabWrite("}\n")
2816 continue #Don't render proxy mesh, skip to next object
2819 if ob.pov.object_as == 'PLANE':
2820 tabWrite("#declare %s = plane{ <0,0,1>,1\n"%povdataname)
2821 povMatName = "Default_texture"
2822 if ob.active_material:
2823 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2824 try:
2825 material = ob.active_material
2826 writeObjectMaterial(material, ob)
2827 except IndexError:
2828 print(me)
2829 #tabWrite("texture {%s}\n"%povMatName)
2830 write_object_modifiers(scene,ob,file)
2831 #tabWrite("rotate x*90\n")
2832 tabWrite("}\n")
2833 continue #Don't render proxy mesh, skip to next object
2836 if ob.pov.object_as == 'BOX':
2837 tabWrite("#declare %s = box { -1,1\n"%povdataname)
2838 povMatName = "Default_texture"
2839 if ob.active_material:
2840 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2841 try:
2842 material = ob.active_material
2843 writeObjectMaterial(material, ob)
2844 except IndexError:
2845 print(me)
2846 #tabWrite("texture {%s}\n"%povMatName)
2847 write_object_modifiers(scene,ob,file)
2848 #tabWrite("rotate x*90\n")
2849 tabWrite("}\n")
2850 continue #Don't render proxy mesh, skip to next object
2853 if ob.pov.object_as == 'CONE':
2854 br = ob.pov.cone_base_radius
2855 cr = ob.pov.cone_cap_radius
2856 bz = ob.pov.cone_base_z
2857 cz = ob.pov.cone_cap_z
2858 tabWrite("#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n"%(povdataname,bz,br,cz,cr))
2859 povMatName = "Default_texture"
2860 if ob.active_material:
2861 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2862 try:
2863 material = ob.active_material
2864 writeObjectMaterial(material, ob)
2865 except IndexError:
2866 print(me)
2867 #tabWrite("texture {%s}\n"%povMatName)
2868 write_object_modifiers(scene,ob,file)
2869 #tabWrite("rotate x*90\n")
2870 tabWrite("}\n")
2871 continue #Don't render proxy mesh, skip to next object
2873 if ob.pov.object_as == 'CYLINDER':
2874 tabWrite("#declare %s = cylinder { <0,0,1>,<0,0,-1>,1\n"%povdataname)
2875 povMatName = "Default_texture"
2876 if ob.active_material:
2877 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2878 try:
2879 material = ob.active_material
2880 writeObjectMaterial(material, ob)
2881 except IndexError:
2882 print(me)
2883 #tabWrite("texture {%s}\n"%povMatName)
2884 write_object_modifiers(scene,ob,file)
2885 #tabWrite("rotate x*90\n")
2886 tabWrite("}\n")
2887 continue #Don't render proxy mesh, skip to next object
2890 if ob.pov.object_as == 'HEIGHT_FIELD':
2891 data = ""
2892 filename = ob.pov.hf_filename
2893 data += '"%s"'%filename
2894 gamma = ' gamma %.4f'%ob.pov.hf_gamma
2895 data += gamma
2896 if ob.pov.hf_premultiplied:
2897 data += ' premultiplied on'
2898 if ob.pov.hf_smooth:
2899 data += ' smooth'
2900 if ob.pov.hf_water > 0:
2901 data += ' water_level %.4f'%ob.pov.hf_water
2902 #hierarchy = ob.pov.hf_hierarchy
2903 tabWrite('#declare %s = height_field { %s\n'%(povdataname,data))
2904 povMatName = "Default_texture"
2905 if ob.active_material:
2906 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2907 try:
2908 material = ob.active_material
2909 writeObjectMaterial(material, ob)
2910 except IndexError:
2911 print(me)
2912 #tabWrite("texture {%s}\n"%povMatName)
2913 write_object_modifiers(scene,ob,file)
2914 tabWrite("rotate x*90\n")
2915 tabWrite("translate <-0.5,0.5,0>\n")
2916 tabWrite("scale <0,-1,0>\n")
2917 tabWrite("}\n")
2918 continue #Don't render proxy mesh, skip to next object
2921 if ob.pov.object_as == 'SPHERE':
2923 tabWrite("#declare %s = sphere { 0,%6f\n"%(povdataname,ob.pov.sphere_radius))
2924 povMatName = "Default_texture"
2925 if ob.active_material:
2926 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2927 try:
2928 material = ob.active_material
2929 writeObjectMaterial(material, ob)
2930 except IndexError:
2931 print(me)
2932 #tabWrite("texture {%s}\n"%povMatName)
2933 write_object_modifiers(scene,ob,file)
2934 #tabWrite("rotate x*90\n")
2935 tabWrite("}\n")
2936 continue #Don't render proxy mesh, skip to next object
2938 if ob.pov.object_as == 'TORUS':
2939 tabWrite("#declare %s = torus { %.4f,%.4f\n"%(povdataname,ob.pov.torus_major_radius,ob.pov.torus_minor_radius))
2940 povMatName = "Default_texture"
2941 if ob.active_material:
2942 #povMatName = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
2943 try:
2944 material = ob.active_material
2945 writeObjectMaterial(material, ob)
2946 except IndexError:
2947 print(me)
2948 #tabWrite("texture {%s}\n"%povMatName)
2949 write_object_modifiers(scene,ob,file)
2950 tabWrite("rotate x*90\n")
2951 tabWrite("}\n")
2952 continue #Don't render proxy mesh, skip to next object
2955 if ob.pov.object_as == 'PARAMETRIC':
2956 tabWrite("#declare %s = parametric {\n"%povdataname)
2957 tabWrite("function { %s }\n"%ob.pov.x_eq)
2958 tabWrite("function { %s }\n"%ob.pov.y_eq)
2959 tabWrite("function { %s }\n"%ob.pov.z_eq)
2960 tabWrite("<%.4f,%.4f>, <%.4f,%.4f>\n"%(ob.pov.u_min,ob.pov.v_min,ob.pov.u_max,ob.pov.v_max))
2961 if ob.pov.contained_by == "sphere":
2962 tabWrite("contained_by { sphere{0, 2} }\n")
2963 else:
2964 tabWrite("contained_by { box{-2, 2} }\n")
2965 tabWrite("max_gradient %.6f\n"%ob.pov.max_gradient)
2966 tabWrite("accuracy %.6f\n"%ob.pov.accuracy)
2967 tabWrite("precompute 10 x,y,z\n")
2968 tabWrite("}\n")
2969 continue #Don't render proxy mesh, skip to next object
2971 if ob.pov.object_as == 'POLYCIRCLE':
2972 #TODO write below macro Once:
2973 #if write_polytocircle_macro_once == 0:
2974 file.write("/****************************\n")
2975 file.write("This macro was written by 'And'.\n")
2976 file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n")
2977 file.write("****************************/\n")
2978 file.write("//from math.inc:\n")
2979 file.write("#macro VPerp_Adjust(V, Axis)\n")
2980 file.write(" vnormalize(vcross(vcross(Axis, V), Axis))\n")
2981 file.write("#end\n")
2982 file.write("//Then for the actual macro\n")
2983 file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n")
2984 file.write("#local p1 = point1 + <0,0,0>;\n")
2985 file.write("#local p2 = point2 + <0,0,0>;\n")
2986 file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n")
2987 file.write("#local direct_v1 = vnormalize(p2 - p1);\n")
2988 file.write("#if(vdot(direct_v1, clip_v) = 1)\n")
2989 file.write(' #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n')
2990 file.write("#end\n\n")
2991 file.write("#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n")
2992 file.write("#local d = vdot(norm, p1);\n")
2993 file.write("plane{\n")
2994 file.write("norm, d\n")
2995 file.write("}\n")
2996 file.write("#end\n\n")
2997 file.write("//polygon to circle\n")
2998 file.write("#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n")
2999 file.write("#local n = int(_polygon_n);\n")
3000 file.write("#if(n < 3)\n")
3001 file.write(" #error ""\n")
3002 file.write("#end\n\n")
3003 file.write("#local front_v = VPerp_Adjust(_side_face, z);\n")
3004 file.write("#if(vdot(front_v, x) >= 0)\n")
3005 file.write(" #local face_ang = acos(vdot(-y, front_v));\n")
3006 file.write("#else\n")
3007 file.write(" #local face_ang = -acos(vdot(-y, front_v));\n")
3008 file.write("#end\n")
3009 file.write("#local polyg_ext_ang = 2*pi/n;\n")
3010 file.write("#local polyg_outer_r = _polygon_circumscribed_radius;\n")
3011 file.write("#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n")
3012 file.write("#local cycle_r = _circle_radius;\n")
3013 file.write("#local h = _height;\n")
3014 file.write("#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n")
3015 file.write(' #error "error: each side length must be positive"\n')
3016 file.write("#end\n\n")
3017 file.write("#local multi = 1000;\n")
3018 file.write("#local poly_obj =\n")
3019 file.write("polynomial{\n")
3020 file.write("4,\n")
3021 file.write("xyz(0,2,2): multi*1,\n")
3022 file.write("xyz(2,0,1): multi*2*h,\n")
3023 file.write("xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n")
3024 file.write("xyz(2,0,0): multi*(-h*h),\n")
3025 file.write("xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n")
3026 file.write("xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n")
3027 file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n")
3028 file.write("xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n")
3029 file.write("xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n")
3030 file.write("sturm\n")
3031 file.write("}\n\n")
3032 file.write("#local mockup1 =\n")
3033 file.write("difference{\n")
3034 file.write(" cylinder{\n")
3035 file.write(" <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n")
3036 file.write(" }\n\n")
3037 file.write(" #for(i, 0, n-1)\n")
3038 file.write(" object{\n")
3039 file.write(" poly_obj\n")
3040 file.write(" inverse\n")
3041 file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
3042 file.write(" }\n")
3043 file.write(" object{\n")
3044 file.write(" Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n")
3045 file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n")
3046 file.write(" }\n")
3047 file.write(" #end\n")
3048 file.write("}\n\n")
3049 file.write("object{\n")
3050 file.write("mockup1\n")
3051 file.write("rotate <0, 0, degrees(face_ang)>\n")
3052 file.write("}\n")
3053 file.write("#end\n")
3054 #Use the macro
3055 ngon = ob.pov.polytocircle_ngon
3056 ngonR = ob.pov.polytocircle_ngonR
3057 circleR = ob.pov.polytocircle_circleR
3058 tabWrite("#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n"%(povdataname,ngon,ngonR,circleR))
3059 tabWrite("}\n")
3060 continue #Don't render proxy mesh, skip to next object
3063 ############################################else try to export mesh
3064 else:
3065 try:
3066 me = ob.to_mesh(scene, True, 'RENDER')
3067 except:
3068 # happens when curves cant be made into meshes because of no-data
3069 continue
3071 importance = ob.pov.importance_value
3072 me_materials = me.materials
3073 me_faces = me.tessfaces[:]
3075 if not me or not me_faces:
3076 continue
3078 uv_textures = me.tessface_uv_textures
3079 if len(uv_textures) > 0:
3080 if me.uv_textures.active and uv_textures.active.data:
3081 uv_layer = uv_textures.active.data
3082 else:
3083 uv_layer = None
3085 try:
3086 #vcol_layer = me.vertex_colors.active.data
3087 vcol_layer = me.tessface_vertex_colors.active.data
3088 except AttributeError:
3089 vcol_layer = None
3091 faces_verts = [f.vertices[:] for f in me_faces]
3092 faces_normals = [f.normal[:] for f in me_faces]
3093 verts_normals = [v.normal[:] for v in me.vertices]
3095 # quads incur an extra face
3096 quadCount = sum(1 for f in faces_verts if len(f) == 4)
3098 # Use named declaration to allow reference e.g. for baking. MR
3099 file.write("\n")
3100 tabWrite("#declare %s =\n" % povdataname)
3101 tabWrite("mesh2 {\n")
3102 tabWrite("vertex_vectors {\n")
3103 tabWrite("%d" % len(me.vertices)) # vert count
3105 tabStr = tab * tabLevel
3106 for v in me.vertices:
3107 if linebreaksinlists:
3108 file.write(",\n")
3109 file.write(tabStr + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
3110 else:
3111 file.write(", ")
3112 file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
3113 #tabWrite("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
3114 file.write("\n")
3115 tabWrite("}\n")
3117 # Build unique Normal list
3118 uniqueNormals = {}
3119 for fi, f in enumerate(me_faces):
3120 fv = faces_verts[fi]
3121 # [-1] is a dummy index, use a list so we can modify in place
3122 if f.use_smooth: # Use vertex normals
3123 for v in fv:
3124 key = verts_normals[v]
3125 uniqueNormals[key] = [-1]
3126 else: # Use face normal
3127 key = faces_normals[fi]
3128 uniqueNormals[key] = [-1]
3130 tabWrite("normal_vectors {\n")
3131 tabWrite("%d" % len(uniqueNormals)) # vert count
3132 idx = 0
3133 tabStr = tab * tabLevel
3134 for no, index in uniqueNormals.items():
3135 if linebreaksinlists:
3136 file.write(",\n")
3137 file.write(tabStr + "<%.6f, %.6f, %.6f>" % no) # vert count
3138 else:
3139 file.write(", ")
3140 file.write("<%.6f, %.6f, %.6f>" % no) # vert count
3141 index[0] = idx
3142 idx += 1
3143 file.write("\n")
3144 tabWrite("}\n")
3146 # Vertex colors
3147 vertCols = {} # Use for material colors also.
3149 if uv_layer:
3150 # Generate unique UV's
3151 uniqueUVs = {}
3152 #n = 0
3153 for fi, uv in enumerate(uv_layer):
3155 if len(faces_verts[fi]) == 4:
3156 uvs = uv_layer[fi].uv[0], uv_layer[fi].uv[1], uv_layer[fi].uv[2], uv_layer[fi].uv[3]
3157 else:
3158 uvs = uv_layer[fi].uv[0], uv_layer[fi].uv[1], uv_layer[fi].uv[2]
3160 for uv in uvs:
3161 uniqueUVs[uv[:]] = [-1]
3163 tabWrite("uv_vectors {\n")
3164 #print unique_uvs
3165 tabWrite("%d" % len(uniqueUVs)) # vert count
3166 idx = 0
3167 tabStr = tab * tabLevel
3168 for uv, index in uniqueUVs.items():
3169 if linebreaksinlists:
3170 file.write(",\n")
3171 file.write(tabStr + "<%.6f, %.6f>" % uv)
3172 else:
3173 file.write(", ")
3174 file.write("<%.6f, %.6f>" % uv)
3175 index[0] = idx
3176 idx += 1
3178 else:
3179 # Just add 1 dummy vector, no real UV's
3180 tabWrite('1') # vert count
3181 file.write(',\n\t\t<0.0, 0.0>')
3183 file.write("\n")
3184 tabWrite("}\n")
3186 if me.vertex_colors:
3187 #Write down vertex colors as a texture for each vertex
3188 tabWrite("texture_list {\n")
3189 tabWrite("%d\n" % (((len(me_faces)-quadCount) * 3 )+ quadCount * 4)) # works only with tris and quad mesh for now
3190 VcolIdx=0
3191 if comments:
3192 file.write("\n //Vertex colors: one simple pigment texture per vertex\n")
3193 for fi, f in enumerate(me_faces):
3194 # annoying, index may be invalid
3195 material_index = f.material_index
3196 try:
3197 material = me_materials[material_index]
3198 except:
3199 material = None
3200 if material: #and material.use_vertex_color_paint: #Always use vertex color when there is some for now
3202 col = vcol_layer[fi]
3204 if len(faces_verts[fi]) == 4:
3205 cols = col.color1, col.color2, col.color3, col.color4
3206 else:
3207 cols = col.color1, col.color2, col.color3
3209 for col in cols:
3210 key = col[0], col[1], col[2], material_index # Material index!
3211 VcolIdx+=1
3212 vertCols[key] = [VcolIdx]
3213 if linebreaksinlists:
3214 tabWrite("texture {pigment{ color rgb <%6f,%6f,%6f> }}\n" % (col[0], col[1], col[2]))
3215 else:
3216 tabWrite("texture {pigment{ color rgb <%6f,%6f,%6f> }}" % (col[0], col[1], col[2]))
3217 tabStr = tab * tabLevel
3218 else:
3219 if material:
3220 # Multiply diffuse with SSS Color
3221 if material.subsurface_scattering.use:
3222 diffuse_color = [i * j for i, j in zip(material.subsurface_scattering.color[:], material.diffuse_color[:])]
3223 key = diffuse_color[0], diffuse_color[1], diffuse_color[2], \
3224 material_index
3225 vertCols[key] = [-1]
3226 else:
3227 diffuse_color = material.diffuse_color[:]
3228 key = diffuse_color[0], diffuse_color[1], diffuse_color[2], \
3229 material_index
3230 vertCols[key] = [-1]
3232 tabWrite("\n}\n")
3233 # Face indices
3234 tabWrite("\nface_indices {\n")
3235 tabWrite("%d" % (len(me_faces) + quadCount)) # faces count
3236 tabStr = tab * tabLevel
3238 for fi, f in enumerate(me_faces):
3239 fv = faces_verts[fi]
3240 material_index = f.material_index
3241 if len(fv) == 4:
3242 indices = (0, 1, 2), (0, 2, 3)
3243 else:
3244 indices = ((0, 1, 2),)
3246 if vcol_layer:
3247 col = vcol_layer[fi]
3249 if len(fv) == 4:
3250 cols = col.color1, col.color2, col.color3, col.color4
3251 else:
3252 cols = col.color1, col.color2, col.color3
3254 if not me_materials or me_materials[material_index] is None: # No materials
3255 for i1, i2, i3 in indices:
3256 if linebreaksinlists:
3257 file.write(",\n")
3258 # vert count
3259 file.write(tabStr + "<%d,%d,%d>" % (fv[i1], fv[i2], fv[i3]))
3260 else:
3261 file.write(", ")
3262 file.write("<%d,%d,%d>" % (fv[i1], fv[i2], fv[i3])) # vert count
3263 else:
3264 material = me_materials[material_index]
3265 for i1, i2, i3 in indices:
3266 if me.vertex_colors: #and material.use_vertex_color_paint:
3267 # Color per vertex - vertex color
3269 col1 = cols[i1]
3270 col2 = cols[i2]
3271 col3 = cols[i3]
3273 ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
3274 ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
3275 ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
3276 else:
3277 # Color per material - flat material color
3278 if material.subsurface_scattering.use:
3279 diffuse_color = [i * j for i, j in zip(material.subsurface_scattering.color[:], material.diffuse_color[:])]
3280 else:
3281 diffuse_color = material.diffuse_color[:]
3282 ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], \
3283 diffuse_color[2], f.material_index][0]
3284 # ci are zero based index so we'll subtract 1 from them
3285 if linebreaksinlists:
3286 file.write(",\n")
3287 file.write(tabStr + "<%d,%d,%d>, %d,%d,%d" % \
3288 (fv[i1], fv[i2], fv[i3], ci1-1, ci2-1, ci3-1)) # vert count
3289 else:
3290 file.write(", ")
3291 file.write("<%d,%d,%d>, %d,%d,%d" % \
3292 (fv[i1], fv[i2], fv[i3], ci1-1, ci2-1, ci3-1)) # vert count
3294 file.write("\n")
3295 tabWrite("}\n")
3297 # normal_indices indices
3298 tabWrite("normal_indices {\n")
3299 tabWrite("%d" % (len(me_faces) + quadCount)) # faces count
3300 tabStr = tab * tabLevel
3301 for fi, fv in enumerate(faces_verts):
3303 if len(fv) == 4:
3304 indices = (0, 1, 2), (0, 2, 3)
3305 else:
3306 indices = ((0, 1, 2),)
3308 for i1, i2, i3 in indices:
3309 if me_faces[fi].use_smooth:
3310 if linebreaksinlists:
3311 file.write(",\n")
3312 file.write(tabStr + "<%d,%d,%d>" %\
3313 (uniqueNormals[verts_normals[fv[i1]]][0],\
3314 uniqueNormals[verts_normals[fv[i2]]][0],\
3315 uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
3316 else:
3317 file.write(", ")
3318 file.write("<%d,%d,%d>" %\
3319 (uniqueNormals[verts_normals[fv[i1]]][0],\
3320 uniqueNormals[verts_normals[fv[i2]]][0],\
3321 uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
3322 else:
3323 idx = uniqueNormals[faces_normals[fi]][0]
3324 if linebreaksinlists:
3325 file.write(",\n")
3326 file.write(tabStr + "<%d,%d,%d>" % (idx, idx, idx)) # vert count
3327 else:
3328 file.write(", ")
3329 file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
3331 file.write("\n")
3332 tabWrite("}\n")
3334 if uv_layer:
3335 tabWrite("uv_indices {\n")
3336 tabWrite("%d" % (len(me_faces) + quadCount)) # faces count
3337 tabStr = tab * tabLevel
3338 for fi, fv in enumerate(faces_verts):
3340 if len(fv) == 4:
3341 indices = (0, 1, 2), (0, 2, 3)
3342 else:
3343 indices = ((0, 1, 2),)
3345 uv = uv_layer[fi]
3346 if len(faces_verts[fi]) == 4:
3347 uvs = uv.uv[0][:], uv.uv[1][:], uv.uv[2][:], uv.uv[3][:]
3348 else:
3349 uvs = uv.uv[0][:], uv.uv[1][:], uv.uv[2][:]
3351 for i1, i2, i3 in indices:
3352 if linebreaksinlists:
3353 file.write(",\n")
3354 file.write(tabStr + "<%d,%d,%d>" % (
3355 uniqueUVs[uvs[i1]][0],\
3356 uniqueUVs[uvs[i2]][0],\
3357 uniqueUVs[uvs[i3]][0]))
3358 else:
3359 file.write(", ")
3360 file.write("<%d,%d,%d>" % (
3361 uniqueUVs[uvs[i1]][0],\
3362 uniqueUVs[uvs[i2]][0],\
3363 uniqueUVs[uvs[i3]][0]))
3365 file.write("\n")
3366 tabWrite("}\n")
3368 if me.materials:
3369 try:
3370 material = me.materials[0] # dodgy
3371 writeObjectMaterial(material, ob)
3372 except IndexError:
3373 print(me)
3375 #Importance for radiosity sampling added here:
3376 tabWrite("radiosity { \n")
3377 tabWrite("importance %3g \n" % importance)
3378 tabWrite("}\n")
3380 tabWrite("}\n") # End of mesh block
3381 else:
3382 # No vertex colors, so write material colors as vertex colors
3383 for i, material in enumerate(me_materials):
3385 if material:
3386 # Multiply diffuse with SSS Color
3387 if material.subsurface_scattering.use:
3388 diffuse_color = [i * j for i, j in zip(material.subsurface_scattering.color[:], material.diffuse_color[:])]
3389 key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat
3390 vertCols[key] = [-1]
3391 else:
3392 diffuse_color = material.diffuse_color[:]
3393 key = diffuse_color[0], diffuse_color[1], diffuse_color[2], i # i == f.mat
3394 vertCols[key] = [-1]
3396 idx = 0
3397 LocalMaterialNames = []
3398 for col, index in vertCols.items():
3399 #if me_materials:
3400 mater = me_materials[col[3]]
3401 if me_materials is None: #XXX working?
3402 material_finish = DEF_MAT_NAME # not working properly,
3403 trans = 0.0
3405 else:
3406 material_finish = materialNames[mater.name]
3407 if mater.use_transparency:
3408 trans = 1.0 - mater.alpha
3409 else:
3410 trans = 0.0
3411 if (mater.specular_color.s == 0.0):
3412 colored_specular_found = False
3413 else:
3414 colored_specular_found = True
3416 if mater.use_transparency and mater.transparency_method == 'RAYTRACE':
3417 povFilter = mater.raytrace_transparency.filter * (1.0 - mater.alpha)
3418 trans = (1.0 - mater.alpha) - povFilter
3419 else:
3420 povFilter = 0.0
3422 ##############SF
3423 texturesDif = ""
3424 texturesSpec = ""
3425 texturesNorm = ""
3426 texturesAlpha = ""
3427 #proceduralFlag=False
3428 for t in mater.texture_slots:
3429 if t and t.use and t.texture.type != 'IMAGE' and t.texture.type != 'NONE':
3430 proceduralFlag=True
3431 image_filename = "PAT_%s"%string_strip_hyphen(bpy.path.clean_name(t.texture.name))
3432 if image_filename:
3433 if t.use_map_color_diffuse:
3434 texturesDif = image_filename
3435 # colvalue = t.default_value # UNUSED
3436 t_dif = t
3437 if t_dif.texture.pov.tex_gamma_enable:
3438 imgGamma = (" gamma %.3g " % t_dif.texture.pov.tex_gamma_value)
3439 if t.use_map_specular or t.use_map_raymir:
3440 texturesSpec = image_filename
3441 # colvalue = t.default_value # UNUSED
3442 t_spec = t
3443 if t.use_map_normal:
3444 texturesNorm = image_filename
3445 # colvalue = t.normal_factor * 10.0 # UNUSED
3446 #textNormName=t.texture.image.name + ".normal"
3447 #was the above used? --MR
3448 t_nor = t
3449 if t.use_map_alpha:
3450 texturesAlpha = image_filename
3451 # colvalue = t.alpha_factor * 10.0 # UNUSED
3452 #textDispName=t.texture.image.name + ".displ"
3453 #was the above used? --MR
3454 t_alpha = t
3456 if t and t.texture.type == 'IMAGE' and t.use and t.texture.image and t.texture.pov.tex_pattern_type == 'emulator':
3457 proceduralFlag=False
3458 if t.texture.image.packed_file:
3459 orig_image_filename=t.texture.image.filepath_raw
3460 unpackedfilename= os.path.join(preview_dir,("unpacked_img_"+(string_strip_hyphen(bpy.path.clean_name(t.texture.name)))))
3461 if not os.path.exists(unpackedfilename):
3462 # record which images that were newly copied and can be safely
3463 # cleaned up
3464 unpacked_images.append(unpackedfilename)
3465 t.texture.image.filepath_raw=unpackedfilename
3466 t.texture.image.save()
3467 image_filename = unpackedfilename
3468 t.texture.image.filepath_raw=orig_image_filename
3469 else:
3470 image_filename = path_image(t.texture.image)
3471 # IMAGE SEQUENCE BEGINS
3472 if image_filename:
3473 if bpy.data.images[t.texture.image.name].source == 'SEQUENCE':
3474 korvaa = "." + str(bpy.data.textures[t.texture.name].image_user.frame_offset + 1).zfill(3) + "."
3475 image_filename = image_filename.replace(".001.", korvaa)
3476 print(" seq debug ")
3477 print(image_filename)
3478 # IMAGE SEQUENCE ENDS
3479 imgGamma = ""
3480 if image_filename:
3481 if t.use_map_color_diffuse:
3482 texturesDif = image_filename
3483 # colvalue = t.default_value # UNUSED
3484 t_dif = t
3485 if t_dif.texture.pov.tex_gamma_enable:
3486 imgGamma = (" gamma %.3g " % t_dif.texture.pov.tex_gamma_value)
3487 if t.use_map_specular or t.use_map_raymir:
3488 texturesSpec = image_filename
3489 # colvalue = t.default_value # UNUSED
3490 t_spec = t
3491 if t.use_map_normal:
3492 texturesNorm = image_filename
3493 # colvalue = t.normal_factor * 10.0 # UNUSED
3494 #textNormName=t.texture.image.name + ".normal"
3495 #was the above used? --MR
3496 t_nor = t
3497 if t.use_map_alpha:
3498 texturesAlpha = image_filename
3499 # colvalue = t.alpha_factor * 10.0 # UNUSED
3500 #textDispName=t.texture.image.name + ".displ"
3501 #was the above used? --MR
3502 t_alpha = t
3504 ####################################################################################
3507 file.write("\n")
3508 # THIS AREA NEEDS TO LEAVE THE TEXTURE OPEN UNTIL ALL MAPS ARE WRITTEN DOWN.
3509 # --MR
3510 currentMatName = string_strip_hyphen(materialNames[mater.name])
3511 LocalMaterialNames.append(currentMatName)
3512 file.write("\n #declare MAT_%s = \ntexture{\n" % currentMatName)
3514 ################################################################################
3516 if mater.pov.replacement_text != "":
3517 file.write("%s\n" % mater.pov.replacement_text)
3518 #################################################################################
3519 if mater.diffuse_shader == 'MINNAERT':
3520 tabWrite("\n")
3521 tabWrite("aoi\n")
3522 tabWrite("texture_map {\n")
3523 tabWrite("[%.3g finish {diffuse %.3g}]\n" % \
3524 (mater.darkness / 2.0, 2.0 - mater.darkness))
3525 tabWrite("[%.3g\n" % (1.0 - (mater.darkness / 2.0)))
3527 if mater.diffuse_shader == 'FRESNEL':
3528 # For FRESNEL diffuse in POV, we'll layer slope patterned textures
3529 # with lamp vector as the slope vector and nest one slope per lamp
3530 # into each texture map's entry.
3532 c = 1
3533 while (c <= lampCount):
3534 tabWrite("slope { lampTarget%s }\n" % (c))
3535 tabWrite("texture_map {\n")
3536 # Diffuse Fresnel value and factor go up to five,
3537 # other kind of values needed: used the number 5 below to remap
3538 tabWrite("[%.3g finish {diffuse %.3g}]\n" % \
3539 ((5.0 - mater.diffuse_fresnel) / 5,
3540 (mater.diffuse_intensity *
3541 ((5.0 - mater.diffuse_fresnel_factor) / 5))))
3542 tabWrite("[%.3g\n" % ((mater.diffuse_fresnel_factor / 5) *
3543 (mater.diffuse_fresnel / 5.0)))
3544 c += 1
3546 # if shader is a 'FRESNEL' or 'MINNAERT': slope pigment pattern or aoi
3547 # and texture map above, the rest below as one of its entry
3549 if texturesSpec != "" or texturesAlpha != "":
3550 if texturesSpec != "":
3551 # tabWrite("\n")
3552 tabWrite("pigment_pattern {\n")
3553 if texturesSpec and texturesSpec.startswith("PAT_"):
3554 tabWrite("function{f%s(x,y,z).grey}" %texturesSpec)
3555 else:
3556 # POV-Ray "scale" is not a number of repetitions factor, but its
3557 # inverse, a standard scale factor.
3558 # Offset seems needed relatively to scale so probably center of the
3559 # scale is not the same in blender and POV
3560 mappingSpec =imgMapTransforms(t_spec)
3561 # mappingSpec = "translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>\n" % \
3562 # (-t_spec.offset.x, t_spec.offset.y, t_spec.offset.z,
3563 # 1.0 / t_spec.scale.x, 1.0 / t_spec.scale.y,
3564 # 1.0 / t_spec.scale.z)
3565 tabWrite("uv_mapping image_map{%s \"%s\" %s}\n" % \
3566 (imageFormat(texturesSpec), texturesSpec, imgMap(t_spec)))
3567 tabWrite("%s\n" % mappingSpec)
3568 tabWrite("}\n")
3569 tabWrite("texture_map {\n")
3570 tabWrite("[0 \n")
3572 if texturesDif == "":
3573 if texturesAlpha != "":
3574 tabWrite("\n")
3575 if texturesAlpha and texturesAlpha.startswith("PAT_"):
3576 tabWrite("function{f%s(x,y,z).transmit}\n" %texturesAlpha)
3577 else:
3578 # POV-Ray "scale" is not a number of repetitions factor, but its
3579 # inverse, a standard scale factor.
3580 # Offset seems needed relatively to scale so probably center of the
3581 # scale is not the same in blender and POV
3582 mappingAlpha = imgMapTransforms(t_alpha)
3583 # mappingAlpha = " translate <%.4g, %.4g, %.4g> " \
3584 # "scale <%.4g, %.4g, %.4g>\n" % \
3585 # (-t_alpha.offset.x, -t_alpha.offset.y,
3586 # t_alpha.offset.z, 1.0 / t_alpha.scale.x,
3587 # 1.0 / t_alpha.scale.y, 1.0 / t_alpha.scale.z)
3588 tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
3589 "{%s \"%s\" %s}%s" % \
3590 (imageFormat(texturesAlpha), texturesAlpha,
3591 imgMap(t_alpha), mappingAlpha))
3592 tabWrite("}\n")
3593 tabWrite("pigment_map {\n")
3594 tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
3595 tabWrite("[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n" % \
3596 (col[0], col[1], col[2], povFilter, trans))
3597 tabWrite("}\n")
3598 tabWrite("}\n")
3600 else:
3602 tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n" % \
3603 (col[0], col[1], col[2], povFilter, trans))
3605 if texturesSpec != "":
3606 # Level 1 is no specular
3607 tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
3609 else:
3610 # Level 2 is translated spec
3611 tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
3613 else:
3614 mappingDif = imgMapTransforms(t_dif)
3616 if texturesAlpha != "":
3617 mappingAlpha = imgMapTransforms(t_alpha)
3618 # mappingAlpha = " translate <%.4g,%.4g,%.4g> " \
3619 # "scale <%.4g,%.4g,%.4g>" % \
3620 # (-t_alpha.offset.x, -t_alpha.offset.y,
3621 # t_alpha.offset.z, 1.0 / t_alpha.scale.x,
3622 # 1.0 / t_alpha.scale.y, 1.0 / t_alpha.scale.z)
3623 tabWrite("pigment {\n")
3624 tabWrite("pigment_pattern {\n")
3625 if texturesAlpha and texturesAlpha.startswith("PAT_"):
3626 tabWrite("function{f%s(x,y,z).transmit}\n" %texturesAlpha)
3627 else:
3628 tabWrite("uv_mapping image_map{%s \"%s\" %s}%s}\n" % \
3629 (imageFormat(texturesAlpha), texturesAlpha,
3630 imgMap(t_alpha), mappingAlpha))
3631 tabWrite("pigment_map {\n")
3632 tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
3633 #if texturesAlpha and texturesAlpha.startswith("PAT_"):
3634 #tabWrite("[1 pigment{%s}]\n" %texturesDif)
3635 if texturesDif and not texturesDif.startswith("PAT_"):
3636 tabWrite("[1 uv_mapping image_map {%s \"%s\" %s} %s]\n" % \
3637 (imageFormat(texturesDif), texturesDif,
3638 (imgGamma + imgMap(t_dif)), mappingDif))
3639 elif texturesDif and texturesDif.startswith("PAT_"):
3640 tabWrite("[1 %s]\n" %texturesDif)
3641 tabWrite("}\n")
3642 tabWrite("}\n")
3643 if texturesAlpha and texturesAlpha.startswith("PAT_"):
3644 tabWrite("}\n")
3646 else:
3647 if texturesDif and texturesDif.startswith("PAT_"):
3648 tabWrite("pigment{%s}\n" %texturesDif)
3649 else:
3650 tabWrite("pigment {uv_mapping image_map {%s \"%s\" %s}%s}\n" % \
3651 (imageFormat(texturesDif), texturesDif,
3652 (imgGamma + imgMap(t_dif)), mappingDif))
3654 if texturesSpec != "":
3655 # Level 1 is no specular
3656 tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
3658 else:
3659 # Level 2 is translated specular
3660 tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
3662 ## scale 1 rotate y*0
3663 #imageMap = ("{image_map {%s \"%s\" %s }\n" % \
3664 # (imageFormat(textures),textures,imgMap(t_dif)))
3665 #tabWrite("uv_mapping pigment %s} %s finish {%s}\n" % \
3666 # (imageMap,mapping,safety(material_finish)))
3667 #tabWrite("pigment {uv_mapping image_map {%s \"%s\" %s}%s} " \
3668 # "finish {%s}\n" % \
3669 # (imageFormat(texturesDif), texturesDif, imgMap(t_dif),
3670 # mappingDif, safety(material_finish)))
3671 if texturesNorm != "":
3672 ## scale 1 rotate y*0
3673 # POV-Ray "scale" is not a number of repetitions factor, but its
3674 # inverse, a standard scale factor.
3675 # Offset seems needed relatively to scale so probably center of the
3676 # scale is not the same in blender and POV
3677 mappingNor =imgMapTransforms(t_nor)
3678 # mappingNor = " translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
3679 # (-t_nor.offset.x, -t_nor.offset.y, t_nor.offset.z,
3680 # 1.0 / t_nor.scale.x, 1.0 / t_nor.scale.y,
3681 # 1.0 / t_nor.scale.z)
3682 #imageMapNor = ("{bump_map {%s \"%s\" %s mapping}" % \
3683 # (imageFormat(texturesNorm),texturesNorm,imgMap(t_nor)))
3684 #We were not using the above maybe we should?
3685 if texturesNorm and texturesNorm.startswith("PAT_"):
3686 tabWrite("normal{function{f%s(x,y,z).grey} bump_size %.4g}\n" %(texturesNorm, t_nor.normal_factor * 10))
3687 else:
3688 tabWrite("normal {uv_mapping bump_map " \
3689 "{%s \"%s\" %s bump_size %.4g }%s}\n" % \
3690 (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
3691 t_nor.normal_factor * 10, mappingNor))
3692 if texturesSpec != "":
3693 tabWrite("]\n")
3694 ##################Second index for mapping specular max value###############
3695 tabWrite("[1 \n")
3697 if texturesDif == "" and mater.pov.replacement_text == "":
3698 if texturesAlpha != "":
3699 # POV-Ray "scale" is not a number of repetitions factor, but its inverse,
3700 # a standard scale factor.
3701 # Offset seems needed relatively to scale so probably center of the scale
3702 # is not the same in blender and POV
3703 # Strange that the translation factor for scale is not the same as for
3704 # translate.
3705 # TODO: verify both matches with blender internal.
3706 mappingAlpha = imgMapTransforms(t_alpha)
3707 # mappingAlpha = " translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>\n" % \
3708 # (-t_alpha.offset.x, -t_alpha.offset.y, t_alpha.offset.z,
3709 # 1.0 / t_alpha.scale.x, 1.0 / t_alpha.scale.y,
3710 # 1.0 / t_alpha.scale.z)
3711 if texturesAlpha and texturesAlpha.startswith("PAT_"):
3712 tabWrite("function{f%s(x,y,z).transmit}\n" %texturesAlpha)
3713 else:
3714 tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
3715 "{%s \"%s\" %s}%s}\n" % \
3716 (imageFormat(texturesAlpha), texturesAlpha, imgMap(t_alpha),
3717 mappingAlpha))
3718 tabWrite("pigment_map {\n")
3719 tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
3720 tabWrite("[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n" % \
3721 (col[0], col[1], col[2], povFilter, trans))
3722 tabWrite("}\n")
3723 tabWrite("}\n")
3725 else:
3726 tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n" % \
3727 (col[0], col[1], col[2], povFilter, trans))
3730 if texturesSpec != "":
3731 # Level 3 is full specular
3732 tabWrite("finish {%s}\n" % (safety(material_finish, Level=3)))
3734 elif colored_specular_found:
3735 # Level 1 is no specular
3736 tabWrite("finish {%s}\n" % (safety(material_finish, Level=1)))
3738 else:
3739 # Level 2 is translated specular
3740 tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
3742 elif mater.pov.replacement_text == "":
3743 mappingDif = imgMapTransforms(t_dif)
3744 # mappingDif = ("scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
3745 # ( 1.0 / t_dif.scale.x,
3746 # 1.0 / t_dif.scale.y,
3747 # 1.0 / t_dif.scale.z,
3748 # 0.5-(0.5/t_dif.scale.x) + t_dif.offset.x,
3749 # 0.5-(0.5/t_dif.scale.y) + t_dif.offset.y,
3750 # 0.5-(0.5/t_dif.scale.z) + t_dif.offset.z))
3751 if texturesAlpha != "":
3752 # Strange that the translation factor for scale is not the same as for
3753 # translate.
3754 # TODO: verify both matches with blender internal.
3755 mappingAlpha = imgMapTransforms(t_alpha)
3756 # mappingAlpha = "translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
3757 # (-t_alpha.offset.x, -t_alpha.offset.y, t_alpha.offset.z,
3758 # 1.0 / t_alpha.scale.x, 1.0 / t_alpha.scale.y,
3759 # 1.0 / t_alpha.scale.z)
3760 if texturesAlpha and texturesAlpha.startswith("PAT_"):
3761 tabWrite("pigment{pigment_pattern {function{f%s(x,y,z).transmit}}\n" %texturesAlpha)
3762 else:
3763 tabWrite("pigment {pigment_pattern {uv_mapping image_map" \
3764 "{%s \"%s\" %s}%s}\n" % \
3765 (imageFormat(texturesAlpha), texturesAlpha, imgMap(t_alpha),
3766 mappingAlpha))
3767 tabWrite("pigment_map {\n")
3768 tabWrite("[0 color rgbft<0,0,0,1,1>]\n")
3769 if texturesAlpha and texturesAlpha.startswith("PAT_"):
3770 tabWrite("[1 function{f%s(x,y,z).transmit}]\n" %texturesAlpha)
3771 elif texturesDif and not texturesDif.startswith("PAT_"):
3772 tabWrite("[1 uv_mapping image_map {%s \"%s\" %s} %s]\n" % \
3773 (imageFormat(texturesDif), texturesDif,
3774 (imgMap(t_dif) + imgGamma), mappingDif))
3775 elif texturesDif and texturesDif.startswith("PAT_"):
3776 tabWrite("[1 %s]\n" %texturesDif)
3777 tabWrite("}\n")
3778 tabWrite("}\n")
3780 else:
3781 if texturesDif and texturesDif.startswith("PAT_"):
3782 tabWrite("pigment{%s}\n" %texturesDif)
3783 else:
3784 tabWrite("pigment {\n")
3785 tabWrite("uv_mapping image_map {\n")
3786 #tabWrite("%s \"%s\" %s}%s\n" % \
3787 # (imageFormat(texturesDif), texturesDif,
3788 # (imgGamma + imgMap(t_dif)),mappingDif))
3789 tabWrite("%s \"%s\" \n" % (imageFormat(texturesDif), texturesDif))
3790 tabWrite("%s\n" % (imgGamma + imgMap(t_dif)))
3791 tabWrite("}\n")
3792 tabWrite("%s\n" % mappingDif)
3793 tabWrite("}\n")
3795 if texturesSpec != "":
3796 # Level 3 is full specular
3797 tabWrite("finish {%s}\n" % (safety(material_finish, Level=3)))
3798 else:
3799 # Level 2 is translated specular
3800 tabWrite("finish {%s}\n" % (safety(material_finish, Level=2)))
3802 ## scale 1 rotate y*0
3803 #imageMap = ("{image_map {%s \"%s\" %s }" % \
3804 # (imageFormat(textures), textures,imgMap(t_dif)))
3805 #file.write("\n\t\t\tuv_mapping pigment %s} %s finish {%s}" % \
3806 # (imageMap, mapping, safety(material_finish)))
3807 #file.write("\n\t\t\tpigment {uv_mapping image_map " \
3808 # "{%s \"%s\" %s}%s} finish {%s}" % \
3809 # (imageFormat(texturesDif), texturesDif,imgMap(t_dif),
3810 # mappingDif, safety(material_finish)))
3811 if texturesNorm != "" and mater.pov.replacement_text == "":
3812 ## scale 1 rotate y*0
3813 # POV-Ray "scale" is not a number of repetitions factor, but its inverse,
3814 # a standard scale factor.
3815 # Offset seems needed relatively to scale so probably center of the scale is
3816 # not the same in blender and POV
3817 mappingNor =imgMapTransforms(t_nor)
3818 # mappingNor = (" translate <%.4g,%.4g,%.4g> scale <%.4g,%.4g,%.4g>" % \
3819 # (-t_nor.offset.x, -t_nor.offset.y, t_nor.offset.z,
3820 # 1.0 / t_nor.scale.x, 1.0 / t_nor.scale.y, 1.0 / t_nor.scale.z))
3821 #imageMapNor = ("{bump_map {%s \"%s\" %s mapping}" % \
3822 # (imageFormat(texturesNorm),texturesNorm,imgMap(t_nor)))
3823 #We were not using the above maybe we should?
3824 if texturesNorm and texturesNorm.startswith("PAT_"):
3825 tabWrite("normal{function{f%s(x,y,z).grey} bump_size %.4g}\n" %(texturesNorm, t_nor.normal_factor * 10))
3826 else:
3827 tabWrite("normal {uv_mapping bump_map {%s \"%s\" %s bump_size %.4g }%s}\n" % \
3828 (imageFormat(texturesNorm), texturesNorm, imgMap(t_nor),
3829 t_nor.normal_factor * 10.0, mappingNor))
3830 if texturesSpec != "" and mater.pov.replacement_text == "":
3831 tabWrite("]\n")
3833 tabWrite("}\n")
3835 #End of slope/ior texture_map
3836 if mater.diffuse_shader == 'MINNAERT' and mater.pov.replacement_text == "":
3837 tabWrite("]\n")
3838 tabWrite("}\n")
3839 if mater.diffuse_shader == 'FRESNEL' and mater.pov.replacement_text == "":
3840 c = 1
3841 while (c <= lampCount):
3842 tabWrite("]\n")
3843 tabWrite("}\n")
3844 c += 1
3848 # Close first layer of POV "texture" (Blender material)
3849 tabWrite("}\n")
3851 if (mater.specular_color.s > 0.0):
3852 colored_specular_found = True
3853 else:
3854 colored_specular_found = False
3856 # Write another layered texture using invisible diffuse and metallic trick
3857 # to emulate colored specular highlights
3858 special_texture_found = False
3859 for t in mater.texture_slots:
3860 if(t and t.use and ((t.texture.type == 'IMAGE' and t.texture.image) or t.texture.type != 'IMAGE') and
3861 (t.use_map_specular or t.use_map_raymir)):
3862 # Specular mapped textures would conflict with colored specular
3863 # because POV can't layer over or under pigment patterned textures
3864 special_texture_found = True
3866 if colored_specular_found and not special_texture_found:
3867 if comments:
3868 file.write(" // colored highlights with a stransparent metallic layer\n")
3869 else:
3870 tabWrite("\n")
3872 tabWrite("texture {\n")
3873 tabWrite("pigment {rgbft<%.3g, %.3g, %.3g, 0, 1>}\n" % \
3874 (mater.specular_color[0], mater.specular_color[1], mater.specular_color[2]))
3875 tabWrite("finish {%s}\n" % (safety(material_finish, Level=2))) # Level 2 is translated spec
3877 texturesNorm = ""
3878 for t in mater.texture_slots:
3880 if t and t.texture.pov.tex_pattern_type != 'emulator':
3881 proceduralFlag=True
3882 image_filename = string_strip_hyphen(bpy.path.clean_name(t.texture.name))
3883 if (t and t.texture.type == 'IMAGE' and
3884 t.use and t.texture.image and
3885 t.texture.pov.tex_pattern_type == 'emulator'):
3886 proceduralFlag=False
3887 image_filename = path_image(t.texture.image)
3888 imgGamma = ""
3889 if image_filename:
3890 if t.use_map_normal:
3891 texturesNorm = image_filename
3892 # colvalue = t.normal_factor * 10.0 # UNUSED
3893 #textNormName=t.texture.image.name + ".normal"
3894 #was the above used? --MR
3895 t_nor = t
3896 if proceduralFlag:
3897 tabWrite("normal{function" \
3898 "{f%s(x,y,z).grey} bump_size %.4g}\n" % \
3899 (texturesNorm,
3900 t_nor.normal_factor * 10))
3901 else:
3902 tabWrite("normal {uv_mapping bump_map " \
3903 "{%s \"%s\" %s bump_size %.4g }%s}\n" % \
3904 (imageFormat(texturesNorm),
3905 texturesNorm, imgMap(t_nor),
3906 t_nor.normal_factor * 10,
3907 mappingNor))
3909 tabWrite("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
3912 ###################################################################
3913 index[0] = idx
3914 idx += 1
3919 # Vert Colors
3920 tabWrite("texture_list {\n")
3921 # In case there's is no material slot, give at least one texture
3922 #(an empty one so it uses pov default)
3923 if len(vertCols)==0:
3924 file.write(tabStr + "1")
3925 else:
3926 file.write(tabStr + "%s" % (len(vertCols))) # vert count
3928 # below "material" alias, changed to ob.active_material
3929 # because variable referenced before assignment
3930 if ob.active_material is not None:
3931 if material.pov.replacement_text != "":
3932 file.write("\n")
3933 file.write(" texture{%s}\n" % material.pov.replacement_text)
3935 else:
3936 # Loop through declared materials list
3937 for cMN in LocalMaterialNames:
3938 if material != "Default":
3939 file.write("\n texture{MAT_%s}\n" % cMN)
3940 #use string_strip_hyphen(materialNames[material]))
3941 #or Something like that to clean up the above?
3942 else:
3943 file.write(" texture{}\n")
3944 tabWrite("}\n")
3946 # Face indices
3947 tabWrite("face_indices {\n")
3948 tabWrite("%d" % (len(me_faces) + quadCount)) # faces count
3949 tabStr = tab * tabLevel
3951 for fi, f in enumerate(me_faces):
3952 fv = faces_verts[fi]
3953 material_index = f.material_index
3954 if len(fv) == 4:
3955 indices = (0, 1, 2), (0, 2, 3)
3956 else:
3957 indices = ((0, 1, 2),)
3959 if vcol_layer:
3960 col = vcol_layer[fi]
3962 if len(fv) == 4:
3963 cols = col.color1, col.color2, col.color3, col.color4
3964 else:
3965 cols = col.color1, col.color2, col.color3
3967 if not me_materials or me_materials[material_index] is None: # No materials
3968 for i1, i2, i3 in indices:
3969 if linebreaksinlists:
3970 file.write(",\n")
3971 # vert count
3972 file.write(tabStr + "<%d,%d,%d>" % (fv[i1], fv[i2], fv[i3]))
3973 else:
3974 file.write(", ")
3975 file.write("<%d,%d,%d>" % (fv[i1], fv[i2], fv[i3])) # vert count
3976 else:
3977 material = me_materials[material_index]
3978 for i1, i2, i3 in indices:
3979 if me.vertex_colors: #and material.use_vertex_color_paint:
3980 # Color per vertex - vertex color
3982 col1 = cols[i1]
3983 col2 = cols[i2]
3984 col3 = cols[i3]
3986 ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
3987 ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
3988 ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
3989 else:
3990 # Color per material - flat material color
3991 if material.subsurface_scattering.use:
3992 diffuse_color = [i * j for i, j in
3993 zip(material.subsurface_scattering.color[:],
3994 material.diffuse_color[:])]
3995 else:
3996 diffuse_color = material.diffuse_color[:]
3997 ci1 = ci2 = ci3 = vertCols[diffuse_color[0], diffuse_color[1], \
3998 diffuse_color[2], f.material_index][0]
4000 if linebreaksinlists:
4001 file.write(",\n")
4002 file.write(tabStr + "<%d,%d,%d>, %d,%d,%d" % \
4003 (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count
4004 else:
4005 file.write(", ")
4006 file.write("<%d,%d,%d>, %d,%d,%d" % \
4007 (fv[i1], fv[i2], fv[i3], ci1, ci2, ci3)) # vert count
4009 file.write("\n")
4010 tabWrite("}\n")
4012 # normal_indices indices
4013 tabWrite("normal_indices {\n")
4014 tabWrite("%d" % (len(me_faces) + quadCount)) # faces count
4015 tabStr = tab * tabLevel
4016 for fi, fv in enumerate(faces_verts):
4018 if len(fv) == 4:
4019 indices = (0, 1, 2), (0, 2, 3)
4020 else:
4021 indices = ((0, 1, 2),)
4023 for i1, i2, i3 in indices:
4024 if me_faces[fi].use_smooth:
4025 if linebreaksinlists:
4026 file.write(",\n")
4027 file.write(tabStr + "<%d,%d,%d>" %\
4028 (uniqueNormals[verts_normals[fv[i1]]][0],\
4029 uniqueNormals[verts_normals[fv[i2]]][0],\
4030 uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
4031 else:
4032 file.write(", ")
4033 file.write("<%d,%d,%d>" %\
4034 (uniqueNormals[verts_normals[fv[i1]]][0],\
4035 uniqueNormals[verts_normals[fv[i2]]][0],\
4036 uniqueNormals[verts_normals[fv[i3]]][0])) # vert count
4037 else:
4038 idx = uniqueNormals[faces_normals[fi]][0]
4039 if linebreaksinlists:
4040 file.write(",\n")
4041 file.write(tabStr + "<%d,%d,%d>" % (idx, idx, idx)) # vertcount
4042 else:
4043 file.write(", ")
4044 file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
4046 file.write("\n")
4047 tabWrite("}\n")
4049 if uv_layer:
4050 tabWrite("uv_indices {\n")
4051 tabWrite("%d" % (len(me_faces) + quadCount)) # faces count
4052 tabStr = tab * tabLevel
4053 for fi, fv in enumerate(faces_verts):
4055 if len(fv) == 4:
4056 indices = (0, 1, 2), (0, 2, 3)
4057 else:
4058 indices = ((0, 1, 2),)
4060 uv = uv_layer[fi]
4061 if len(faces_verts[fi]) == 4:
4062 uvs = uv.uv[0][:], uv.uv[1][:], uv.uv[2][:], uv.uv[3][:]
4063 else:
4064 uvs = uv.uv[0][:], uv.uv[1][:], uv.uv[2][:]
4066 for i1, i2, i3 in indices:
4067 if linebreaksinlists:
4068 file.write(",\n")
4069 file.write(tabStr + "<%d,%d,%d>" % (
4070 uniqueUVs[uvs[i1]][0],\
4071 uniqueUVs[uvs[i2]][0],\
4072 uniqueUVs[uvs[i3]][0]))
4073 else:
4074 file.write(", ")
4075 file.write("<%d,%d,%d>" % (
4076 uniqueUVs[uvs[i1]][0],\
4077 uniqueUVs[uvs[i2]][0],\
4078 uniqueUVs[uvs[i3]][0]))
4080 file.write("\n")
4081 tabWrite("}\n")
4083 if me.materials:
4084 try:
4085 material = me.materials[0] # dodgy
4086 writeObjectMaterial(material, ob)
4087 except IndexError:
4088 print(me)
4090 #Importance for radiosity sampling added here:
4091 tabWrite("radiosity { \n")
4092 tabWrite("importance %3g \n" % importance)
4093 tabWrite("}\n")
4095 tabWrite("}\n") # End of mesh block
4097 bpy.data.meshes.remove(me)
4099 for data_name, inst in data_ref.items():
4100 for ob_name, matrix_str in inst:
4101 tabWrite("//----Blender Object Name:%s----\n" % ob_name)
4102 tabWrite("object { \n")
4103 tabWrite("%s\n" % data_name)
4104 tabWrite("%s\n" % matrix_str)
4105 tabWrite("}\n")
4107 def exportWorld(world):
4108 render = scene.render
4109 camera = scene.camera
4110 matrix = global_matrix * camera.matrix_world
4111 if not world:
4112 return
4113 #############Maurice####################################
4114 #These lines added to get sky gradient (visible with PNG output)
4115 if world:
4116 #For simple flat background:
4117 if not world.use_sky_blend:
4118 # Non fully transparent background could premultiply alpha and avoid anti-aliasing
4119 # display issue:
4120 if render.alpha_mode == 'TRANSPARENT':
4121 tabWrite("background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n" % \
4122 (world.horizon_color[:]))
4123 #Currently using no alpha with Sky option:
4124 elif render.alpha_mode == 'SKY':
4125 tabWrite("background {rgbt<%.3g, %.3g, %.3g, 0>}\n" % (world.horizon_color[:]))
4126 #StraightAlpha:
4127 # XXX Does not exists anymore
4128 #else:
4129 #tabWrite("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.horizon_color[:]))
4131 worldTexCount = 0
4132 #For Background image textures
4133 for t in world.texture_slots: # risk to write several sky_spheres but maybe ok.
4134 if t and t.texture.type is not None:
4135 worldTexCount += 1
4136 # XXX No enable checkbox for world textures yet (report it?)
4137 #if t and t.texture.type == 'IMAGE' and t.use:
4138 if t and t.texture.type == 'IMAGE':
4139 image_filename = path_image(t.texture.image)
4140 if t.texture.image.filepath != image_filename:
4141 t.texture.image.filepath = image_filename
4142 if image_filename != "" and t.use_map_blend:
4143 texturesBlend = image_filename
4144 #colvalue = t.default_value
4145 t_blend = t
4147 # Commented below was an idea to make the Background image oriented as camera
4148 # taken here:
4149 #http://news.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
4150 # Replace 4/3 by the ratio of each image found by some custom or existing
4151 # function
4152 #mappingBlend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees" \
4153 # "(atan((camLocation - camLookAt).x/(camLocation - " \
4154 # "camLookAt).y)) rotate x*degrees(atan((camLocation - " \
4155 # "camLookAt).y/(camLocation - camLookAt).z)) rotate y*" \
4156 # "degrees(atan((camLocation - camLookAt).z/(camLocation - " \
4157 # "camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % \
4158 # (t_blend.offset.x / 10 , t_blend.offset.y / 10 ,
4159 # t_blend.offset.z / 10, t_blend.scale.x ,
4160 # t_blend.scale.y , t_blend.scale.z))
4161 #using camera rotation valuesdirectly from blender seems much easier
4162 if t_blend.texture_coords == 'ANGMAP':
4163 mappingBlend = ""
4164 else:
4165 # POV-Ray "scale" is not a number of repetitions factor, but its
4166 # inverse, a standard scale factor.
4167 # 0.5 Offset is needed relatively to scale because center of the
4168 # UV scale is 0.5,0.5 in blender and 0,0 in POV
4169 # Further Scale by 2 and translate by -1 are
4170 # required for the sky_sphere not to repeat
4172 mappingBlend = "scale 2 scale <%.4g,%.4g,%.4g> translate -1 " \
4173 "translate <%.4g,%.4g,%.4g> rotate<0,0,0> " % \
4174 ((1.0 / t_blend.scale.x),
4175 (1.0 / t_blend.scale.y),
4176 (1.0 / t_blend.scale.z),
4177 0.5-(0.5/t_blend.scale.x)- t_blend.offset.x,
4178 0.5-(0.5/t_blend.scale.y)- t_blend.offset.y,
4179 t_blend.offset.z)
4181 # The initial position and rotation of the pov camera is probably creating
4182 # the rotation offset should look into it someday but at least background
4183 # won't rotate with the camera now.
4184 # Putting the map on a plane would not introduce the skysphere distortion and
4185 # allow for better image scale matching but also some waay to chose depth and
4186 # size of the plane relative to camera.
4187 tabWrite("sky_sphere {\n")
4188 tabWrite("pigment {\n")
4189 tabWrite("image_map{%s \"%s\" %s}\n" % \
4190 (imageFormat(texturesBlend), texturesBlend, imgMapBG(t_blend)))
4191 tabWrite("}\n")
4192 tabWrite("%s\n" % (mappingBlend))
4193 # The following layered pigment opacifies to black over the texture for
4194 # transmit below 1 or otherwise adds to itself
4195 tabWrite("pigment {rgb 0 transmit %s}\n" % (t.texture.intensity))
4196 tabWrite("}\n")
4197 #tabWrite("scale 2\n")
4198 #tabWrite("translate -1\n")
4200 #For only Background gradient
4202 if worldTexCount == 0:
4203 if world.use_sky_blend:
4204 tabWrite("sky_sphere {\n")
4205 tabWrite("pigment {\n")
4206 # maybe Should follow the advice of POV doc about replacing gradient
4207 # for skysphere..5.5
4208 tabWrite("gradient y\n")
4209 tabWrite("color_map {\n")
4210 # XXX Does not exists anymore
4211 #if render.alpha_mode == 'STRAIGHT':
4212 #tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.horizon_color[:]))
4213 #tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.zenith_color[:]))
4214 if render.alpha_mode == 'TRANSPARENT':
4215 tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.horizon_color[:]))
4216 # aa premult not solved with transmit 1
4217 tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.zenith_color[:]))
4218 else:
4219 tabWrite("[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.horizon_color[:]))
4220 tabWrite("[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.zenith_color[:]))
4221 tabWrite("}\n")
4222 tabWrite("}\n")
4223 tabWrite("}\n")
4224 # Sky_sphere alpha (transmit) is not translating into image alpha the same
4225 # way as 'background'
4227 #if world.light_settings.use_indirect_light:
4228 # scene.pov.radio_enable=1
4230 # Maybe change the above to a funtion copyInternalRenderer settings when
4231 # user pushes a button, then:
4232 #scene.pov.radio_enable = world.light_settings.use_indirect_light
4233 # and other such translations but maybe this would not be allowed either?
4235 ###############################################################
4237 mist = world.mist_settings
4239 if mist.use_mist:
4240 tabWrite("fog {\n")
4241 tabWrite("distance %.6f\n" % mist.depth)
4242 tabWrite("color rgbt<%.3g, %.3g, %.3g, %.3g>\n" % \
4243 (*world.horizon_color, 1.0 - mist.intensity))
4244 #tabWrite("fog_offset %.6f\n" % mist.start)
4245 #tabWrite("fog_alt 5\n")
4246 #tabWrite("turbulence 0.2\n")
4247 #tabWrite("turb_depth 0.3\n")
4248 tabWrite("fog_type 1\n")
4249 tabWrite("}\n")
4250 if scene.pov.media_enable:
4251 tabWrite("media {\n")
4252 tabWrite("scattering { 1, rgb <%.4g, %.4g, %.4g>}\n" % scene.pov.media_color[:])
4253 tabWrite("samples %.d\n" % scene.pov.media_samples)
4254 tabWrite("}\n")
4256 def exportGlobalSettings(scene):
4258 tabWrite("global_settings {\n")
4259 tabWrite("assumed_gamma 1.0\n")
4260 tabWrite("max_trace_level %d\n" % scene.pov.max_trace_level)
4262 if scene.pov.radio_enable:
4263 tabWrite("radiosity {\n")
4264 tabWrite("adc_bailout %.4g\n" % scene.pov.radio_adc_bailout)
4265 tabWrite("always_sample %d\n" % scene.pov.radio_always_sample)
4266 tabWrite("brightness %.4g\n" % scene.pov.radio_brightness)
4267 tabWrite("count %d\n" % scene.pov.radio_count)
4268 tabWrite("error_bound %.4g\n" % scene.pov.radio_error_bound)
4269 tabWrite("gray_threshold %.4g\n" % scene.pov.radio_gray_threshold)
4270 tabWrite("low_error_factor %.4g\n" % scene.pov.radio_low_error_factor)
4271 tabWrite("media %d\n" % scene.pov.radio_media)
4272 tabWrite("minimum_reuse %.4g\n" % scene.pov.radio_minimum_reuse)
4273 tabWrite("nearest_count %d\n" % scene.pov.radio_nearest_count)
4274 tabWrite("normal %d\n" % scene.pov.radio_normal)
4275 tabWrite("pretrace_start %.3g\n" % scene.pov.radio_pretrace_start)
4276 tabWrite("pretrace_end %.3g\n" % scene.pov.radio_pretrace_end)
4277 tabWrite("recursion_limit %d\n" % scene.pov.radio_recursion_limit)
4278 tabWrite("}\n")
4279 onceSss = 1
4280 onceAmbient = 1
4281 oncePhotons = 1
4282 for material in bpy.data.materials:
4283 if material.subsurface_scattering.use and onceSss:
4284 # In pov, the scale has reversed influence compared to blender. these number
4285 # should correct that
4286 tabWrite("mm_per_unit %.6f\n" % \
4287 (material.subsurface_scattering.scale * 1000.0))
4288 # 1000 rather than scale * (-100.0) + 15.0))
4290 # In POV-Ray, the scale factor for all subsurface shaders needs to be the same
4292 # formerly sslt_samples were multiplied by 100 instead of 10
4293 sslt_samples = (11 - material.subsurface_scattering.error_threshold) * 10
4295 tabWrite("subsurface { samples %d, %d }\n" % (sslt_samples, sslt_samples / 10))
4296 onceSss = 0
4298 if world and onceAmbient:
4299 tabWrite("ambient_light rgbt<%.3g, %.3g, %.3g,1>\n" % world.ambient_color[:])
4300 onceAmbient = 0
4302 if (oncePhotons and
4303 (material.pov.refraction_type == "2" or
4304 material.pov.photons_reflection == True)):
4305 tabWrite("photons {\n")
4306 tabWrite("spacing %.6f\n" % scene.pov.photon_spacing)
4307 tabWrite("max_trace_level %d\n" % scene.pov.photon_max_trace_level)
4308 tabWrite("adc_bailout %.3g\n" % scene.pov.photon_adc_bailout)
4309 tabWrite("gather %d, %d\n" % (scene.pov.photon_gather_min,
4310 scene.pov.photon_gather_max))
4311 tabWrite("}\n")
4312 oncePhotons = 0
4314 tabWrite("}\n")
4316 def exportCustomCode():
4317 # Write CurrentAnimation Frame for use in Custom POV Code
4318 file.write("#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current)
4319 #Change path and uncomment to add an animated include file by hand:
4320 file.write("//#include \"/home/user/directory/animation_include_file.inc\"\n")
4321 for txt in bpy.data.texts:
4322 if txt.pov.custom_code:
4323 # Why are the newlines needed?
4324 file.write("\n")
4325 file.write(txt.as_string())
4326 file.write("\n")
4328 sel = renderable_objects()
4329 if comments:
4330 file.write("//----------------------------------------------\n" \
4331 "//--Exported with POV-Ray exporter for Blender--\n" \
4332 "//----------------------------------------------\n\n")
4333 file.write("#version 3.7;\n")
4335 if comments:
4336 file.write("\n//--Global settings--\n\n")
4338 exportGlobalSettings(scene)
4341 if comments:
4342 file.write("\n//--Custom Code--\n\n")
4343 exportCustomCode()
4345 if comments:
4346 file.write("\n//--Patterns Definitions--\n\n")
4347 LocalPatternNames = []
4348 for texture in bpy.data.textures: #ok?
4349 if texture.users > 0:
4350 currentPatName = string_strip_hyphen(bpy.path.clean_name(texture.name))
4351 #string_strip_hyphen(patternNames[texture.name]) #maybe instead of the above
4352 LocalPatternNames.append(currentPatName)
4353 #use above list to prevent writing texture instances several times and assign in mats?
4354 file.write("\n #declare PAT_%s = \n" % currentPatName)
4355 file.write(exportPattern(texture))
4356 file.write("\n")
4357 if comments:
4358 file.write("\n//--Background--\n\n")
4360 exportWorld(scene.world)
4362 if comments:
4363 file.write("\n//--Cameras--\n\n")
4365 exportCamera()
4367 if comments:
4368 file.write("\n//--Lamps--\n\n")
4370 exportLamps([L for L in sel if (L.type == 'LAMP' and L.pov.object_as != 'RAINBOW')])
4372 if comments:
4373 file.write("\n//--Rainbows--\n\n")
4374 exportRainbows([L for L in sel if (L.type == 'LAMP' and L.pov.object_as == 'RAINBOW')])
4377 if comments:
4378 file.write("\n//--Special Curves--\n\n")
4379 for c in sel:
4380 if c.type == 'CURVE' and (c.pov.curveshape in {'lathe','sphere_sweep','loft','birail'}):
4381 exportCurves(scene,c)
4384 if comments:
4385 file.write("\n//--Material Definitions--\n\n")
4386 # write a default pigment for objects with no material (comment out to show black)
4387 file.write("#default{ pigment{ color rgb 0.8 }}\n")
4388 # Convert all materials to strings we can access directly per vertex.
4389 #exportMaterials()
4390 writeMaterial(None) # default material
4391 for material in bpy.data.materials:
4392 if material.users > 0:
4393 writeMaterial(material)
4394 if comments:
4395 file.write("\n")
4397 exportMeta([m for m in sel if m.type == 'META'])
4399 if comments:
4400 file.write("//--Mesh objects--\n")
4402 exportMeshes(scene, sel)
4404 #What follow used to happen here:
4405 #exportCamera()
4406 #exportWorld(scene.world)
4407 #exportGlobalSettings(scene)
4408 # MR:..and the order was important for implementing pov 3.7 baking
4409 # (mesh camera) comment for the record
4410 # CR: Baking should be a special case than. If "baking", than we could change the order.
4412 #print("pov file closed %s" % file.closed)
4413 file.close()
4414 #print("pov file closed %s" % file.closed)
4417 def write_pov_ini(scene, filename_ini, filename_pov, filename_image):
4418 feature_set = bpy.context.user_preferences.addons[__package__].preferences.branch_feature_set_povray
4419 using_uberpov = (feature_set=='uberpov')
4420 #scene = bpy.data.scenes[0]
4421 render = scene.render
4423 x = int(render.resolution_x * render.resolution_percentage * 0.01)
4424 y = int(render.resolution_y * render.resolution_percentage * 0.01)
4426 file = open(filename_ini, "w")
4427 file.write("Version=3.7\n")
4428 file.write("Input_File_Name='%s'\n" % filename_pov)
4429 file.write("Output_File_Name='%s'\n" % filename_image)
4431 file.write("Width=%d\n" % x)
4432 file.write("Height=%d\n" % y)
4434 # Border render.
4435 if render.use_border:
4436 file.write("Start_Column=%4g\n" % render.border_min_x)
4437 file.write("End_Column=%4g\n" % (render.border_max_x))
4439 file.write("Start_Row=%4g\n" % (1.0 - render.border_max_y))
4440 file.write("End_Row=%4g\n" % (1.0 - render.border_min_y))
4442 file.write("Bounding_Method=2\n") # The new automatic BSP is faster in most scenes
4444 # Activated (turn this back off when better live exchange is done between the two programs
4445 # (see next comment)
4446 file.write("Display=1\n")
4447 file.write("Pause_When_Done=0\n")
4448 # PNG, with POV-Ray 3.7, can show background color with alpha. In the long run using the
4449 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
4450 file.write("Output_File_Type=N\n")
4451 #file.write("Output_File_Type=T\n") # TGA, best progressive loading
4452 file.write("Output_Alpha=1\n")
4454 if scene.pov.antialias_enable:
4455 # method 2 (recursive) with higher max subdiv forced because no mipmapping in POV-Ray
4456 # needs higher sampling.
4457 # aa_mapping = {"5": 2, "8": 3, "11": 4, "16": 5}
4458 if using_uberpov:
4459 method = {"0": 1, "1": 2, "2": 3}
4460 else:
4461 method = {"0": 1, "1": 2, "2": 2}
4462 file.write("Antialias=on\n")
4463 file.write("Antialias_Depth=%d\n" % scene.pov.antialias_depth)
4464 file.write("Antialias_Threshold=%.3g\n" % scene.pov.antialias_threshold)
4465 if using_uberpov and scene.pov.antialias_method == '2':
4466 file.write("Sampling_Method=%s\n" % method[scene.pov.antialias_method])
4467 file.write("Antialias_Confidence=%.3g\n" % scene.pov.antialias_confidence)
4468 else:
4469 file.write("Sampling_Method=%s\n" % method[scene.pov.antialias_method])
4470 file.write("Antialias_Gamma=%.3g\n" % scene.pov.antialias_gamma)
4471 if scene.pov.jitter_enable:
4472 file.write("Jitter=on\n")
4473 file.write("Jitter_Amount=%3g\n" % scene.pov.jitter_amount)
4474 else:
4475 file.write("Jitter=off\n") # prevent animation flicker
4477 else:
4478 file.write("Antialias=off\n")
4479 #print("ini file closed %s" % file.closed)
4480 file.close()
4481 #print("ini file closed %s" % file.closed)
4484 class PovrayRender(bpy.types.RenderEngine):
4485 bl_idname = 'POVRAY_RENDER'
4486 bl_label = "POV-Ray 3.7"
4487 DELAY = 0.5
4489 @staticmethod
4490 def _locate_binary():
4491 addon_prefs = bpy.context.user_preferences.addons[__package__].preferences
4493 # Use the system preference if its set.
4494 pov_binary = addon_prefs.filepath_povray
4495 if pov_binary:
4496 if os.path.exists(pov_binary):
4497 return pov_binary
4498 else:
4499 print("User Preferences path to povray %r NOT FOUND, checking $PATH" % pov_binary)
4501 # Windows Only
4502 # assume if there is a 64bit binary that the user has a 64bit capable OS
4503 if sys.platform[:3] == "win":
4504 import winreg
4505 win_reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
4506 "Software\\POV-Ray\\v3.7\\Windows")
4507 win_home = winreg.QueryValueEx(win_reg_key, "Home")[0]
4509 # First try 64bits UberPOV
4510 pov_binary = os.path.join(win_home, "bin", "uberpov64.exe")
4511 if os.path.exists(pov_binary):
4512 return pov_binary
4514 # Then try 64bits POV
4515 pov_binary = os.path.join(win_home, "bin", "pvengine64.exe")
4516 if os.path.exists(pov_binary):
4517 return pov_binary
4519 # Then try 32bits UberPOV
4520 pov_binary = os.path.join(win_home, "bin", "uberpov32.exe")
4521 if os.path.exists(pov_binary):
4522 return pov_binary
4524 # Then try 32bits POV
4525 pov_binary = os.path.join(win_home, "bin", "pvengine.exe")
4526 if os.path.exists(pov_binary):
4527 return pov_binary
4529 # search the path all os's
4530 pov_binary_default = "povray"
4532 os_path_ls = os.getenv("PATH").split(':') + [""]
4534 for dir_name in os_path_ls:
4535 pov_binary = os.path.join(dir_name, pov_binary_default)
4536 if os.path.exists(pov_binary):
4537 return pov_binary
4538 return ""
4540 def _export(self, scene, povPath, renderImagePath):
4541 import tempfile
4543 if scene.pov.tempfiles_enable:
4544 self._temp_file_in = tempfile.NamedTemporaryFile(suffix=".pov", delete=False).name
4545 # PNG with POV 3.7, can show the background color with alpha. In the long run using the
4546 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
4547 self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
4548 #self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
4549 self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
4550 else:
4551 self._temp_file_in = povPath + ".pov"
4552 # PNG with POV 3.7, can show the background color with alpha. In the long run using the
4553 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
4554 self._temp_file_out = renderImagePath + ".png"
4555 #self._temp_file_out = renderImagePath + ".tga"
4556 self._temp_file_ini = povPath + ".ini"
4558 self._temp_file_in = "/test.pov"
4559 # PNG with POV 3.7, can show the background color with alpha. In the long run using the
4560 # POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
4561 self._temp_file_out = "/test.png"
4562 #self._temp_file_out = "/test.tga"
4563 self._temp_file_ini = "/test.ini"
4566 def info_callback(txt):
4567 self.update_stats("", "POV-Ray 3.7: " + txt)
4569 # os.makedirs(user_dir, exist_ok=True) # handled with previews
4570 os.makedirs(preview_dir, exist_ok=True)
4572 write_pov(self._temp_file_in, scene, info_callback)
4574 def _render(self, scene):
4575 try:
4576 os.remove(self._temp_file_out) # so as not to load the old file
4577 except OSError:
4578 pass
4580 pov_binary = PovrayRender._locate_binary()
4581 if not pov_binary:
4582 print("POV-Ray 3.7: could not execute povray, possibly POV-Ray isn't installed")
4583 return False
4585 write_pov_ini(scene, self._temp_file_ini, self._temp_file_in, self._temp_file_out)
4587 print ("***-STARTING-***")
4589 extra_args = []
4591 if scene.pov.command_line_switches != "":
4592 for newArg in scene.pov.command_line_switches.split(" "):
4593 extra_args.append(newArg)
4595 self._is_windows = False
4596 if sys.platform[:3] == "win":
4597 self._is_windows = True
4598 if"/EXIT" not in extra_args and not scene.pov.pov_editor:
4599 extra_args.append("/EXIT")
4600 else:
4601 # added -d option to prevent render window popup which leads to segfault on linux
4602 extra_args.append("-d")
4604 # Start Rendering!
4605 try:
4606 self._process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args,
4607 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
4608 except OSError:
4609 # TODO, report api
4610 print("POV-Ray 3.7: could not execute '%s'" % pov_binary)
4611 import traceback
4612 traceback.print_exc()
4613 print ("***-DONE-***")
4614 return False
4616 else:
4617 print("Engine ready!...")
4618 print("Command line arguments passed: " + str(extra_args))
4619 return True
4621 # Now that we have a valid process
4623 def _cleanup(self):
4624 for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
4625 for i in range(5):
4626 try:
4627 os.unlink(f)
4628 break
4629 except OSError:
4630 # Wait a bit before retrying file might be still in use by Blender,
4631 # and Windows does not know how to delete a file in use!
4632 time.sleep(self.DELAY)
4633 for i in unpacked_images:
4634 for c in range(5):
4635 try:
4636 os.unlink(i)
4637 break
4638 except OSError:
4639 # Wait a bit before retrying file might be still in use by Blender,
4640 # and Windows does not know how to delete a file in use!
4641 time.sleep(self.DELAY)
4642 def render(self, scene):
4643 import tempfile
4645 print("***INITIALIZING***")
4647 ##WIP output format
4648 ## if r.image_settings.file_format == 'OPENEXR':
4649 ## fformat = 'EXR'
4650 ## render.image_settings.color_mode = 'RGBA'
4651 ## else:
4652 ## fformat = 'TGA'
4653 ## r.image_settings.file_format = 'TARGA'
4654 ## r.image_settings.color_mode = 'RGBA'
4656 blendSceneName = bpy.data.filepath.split(os.path.sep)[-1].split(".")[0]
4657 povSceneName = ""
4658 povPath = ""
4659 renderImagePath = ""
4661 # has to be called to update the frame on exporting animations
4662 scene.frame_set(scene.frame_current)
4664 if not scene.pov.tempfiles_enable:
4666 # check paths
4667 povPath = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
4668 if povPath == "":
4669 if bpy.data.is_saved:
4670 povPath = bpy.path.abspath("//")
4671 else:
4672 povPath = tempfile.gettempdir()
4673 elif povPath.endswith("/"):
4674 if povPath == "/":
4675 povPath = bpy.path.abspath("//")
4676 else:
4677 povPath = bpy.path.abspath(scene.pov.scene_path)
4679 if not os.path.exists(povPath):
4680 try:
4681 os.makedirs(povPath)
4682 except:
4683 import traceback
4684 traceback.print_exc()
4686 print("POV-Ray 3.7: Cannot create scenes directory: %r" % povPath)
4687 self.update_stats("", "POV-Ray 3.7: Cannot create scenes directory %r" % \
4688 povPath)
4689 time.sleep(2.0)
4690 return
4693 # Bug in POV-Ray RC3
4694 renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
4695 if renderImagePath == "":
4696 if bpy.data.is_saved:
4697 renderImagePath = bpy.path.abspath("//")
4698 else:
4699 renderImagePath = tempfile.gettempdir()
4700 #print("Path: " + renderImagePath)
4701 elif path.endswith("/"):
4702 if renderImagePath == "/":
4703 renderImagePath = bpy.path.abspath("//")
4704 else:
4705 renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
4706 if not os.path.exists(path):
4707 print("POV-Ray 3.7: Cannot find render image directory")
4708 self.update_stats("", "POV-Ray 3.7: Cannot find render image directory")
4709 time.sleep(2.0)
4710 return
4713 # check name
4714 if scene.pov.scene_name == "":
4715 if blendSceneName != "":
4716 povSceneName = blendSceneName
4717 else:
4718 povSceneName = "untitled"
4719 else:
4720 povSceneName = scene.pov.scene_name
4721 if os.path.isfile(povSceneName):
4722 povSceneName = os.path.basename(povSceneName)
4723 povSceneName = povSceneName.split('/')[-1].split('\\')[-1]
4724 if not povSceneName:
4725 print("POV-Ray 3.7: Invalid scene name")
4726 self.update_stats("", "POV-Ray 3.7: Invalid scene name")
4727 time.sleep(2.0)
4728 return
4729 povSceneName = os.path.splitext(povSceneName)[0]
4731 print("Scene name: " + povSceneName)
4732 print("Export path: " + povPath)
4733 povPath = os.path.join(povPath, povSceneName)
4734 povPath = os.path.realpath(povPath)
4736 # for now this has to be the same like the pov output. Bug in POV-Ray RC3.
4737 # renderImagePath = renderImagePath + "\\" + povSceneName
4738 renderImagePath = povPath # Bugfix for POV-Ray RC3 bug
4739 # renderImagePath = os.path.realpath(renderImagePath) # Bugfix for POV-Ray RC3 bug
4741 #print("Export path: %s" % povPath)
4742 #print("Render Image path: %s" % renderImagePath)
4744 # start export
4745 self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
4746 self._export(scene, povPath, renderImagePath)
4747 self.update_stats("", "POV-Ray 3.7: Parsing File")
4749 if not self._render(scene):
4750 self.update_stats("", "POV-Ray 3.7: Not found")
4751 return
4753 r = scene.render
4754 # compute resolution
4755 x = int(r.resolution_x * r.resolution_percentage * 0.01)
4756 y = int(r.resolution_y * r.resolution_percentage * 0.01)
4758 # This makes some tests on the render, returning True if all goes good, and False if
4759 # it was finished one way or the other.
4760 # It also pauses the script (time.sleep())
4761 def _test_wait():
4762 time.sleep(self.DELAY)
4764 # User interrupts the rendering
4765 if self.test_break():
4766 try:
4767 self._process.terminate()
4768 print("***POV INTERRUPTED***")
4769 except OSError:
4770 pass
4771 return False
4773 poll_result = self._process.poll()
4774 # POV process is finisehd, one way or the other
4775 if poll_result is not None:
4776 if poll_result < 0:
4777 print("***POV PROCESS FAILED : %s ***" % poll_result)
4778 self.update_stats("", "POV-Ray 3.7: Failed")
4779 return False
4781 return True
4783 # Wait for the file to be created
4784 # XXX This is no more valid, as 3.7 always creates output file once render is finished!
4785 parsing = re.compile(br"= \[Parsing\.\.\.\] =")
4786 rendering = re.compile(br"= \[Rendering\.\.\.\] =")
4787 percent = re.compile(r"\(([0-9]{1,3})%\)")
4788 # print("***POV WAITING FOR FILE***")
4790 data = b""
4791 last_line = ""
4792 while _test_wait():
4793 # POV in Windows does not output its stdout/stderr, it displays them in its GUI
4794 if self._is_windows:
4795 self.update_stats("", "POV-Ray 3.7: Rendering File")
4796 else:
4797 t_data = self._process.stdout.read(10000)
4798 if not t_data:
4799 continue
4801 data += t_data
4802 # XXX This is working for UNIX, not sure whether it might need adjustments for
4803 # other OSs
4804 # First replace is for windows
4805 t_data = str(t_data).replace('\\r\\n', '\\n').replace('\\r', '\r')
4806 lines = t_data.split('\\n')
4807 last_line += lines[0]
4808 lines[0] = last_line
4809 print('\n'.join(lines), end="")
4810 last_line = lines[-1]
4812 if rendering.search(data):
4813 _pov_rendering = True
4814 match = percent.findall(str(data))
4815 if match:
4816 self.update_stats("", "POV-Ray 3.7: Rendering File (%s%%)" % match[-1])
4817 else:
4818 self.update_stats("", "POV-Ray 3.7: Rendering File")
4820 elif parsing.search(data):
4821 self.update_stats("", "POV-Ray 3.7: Parsing File")
4823 if os.path.exists(self._temp_file_out):
4824 # print("***POV FILE OK***")
4825 #self.update_stats("", "POV-Ray 3.7: Rendering")
4827 # prev_size = -1
4829 xmin = int(r.border_min_x * x)
4830 ymin = int(r.border_min_y * y)
4831 xmax = int(r.border_max_x * x)
4832 ymax = int(r.border_max_y * y)
4834 # print("***POV UPDATING IMAGE***")
4835 result = self.begin_result(0, 0, x, y)
4836 # XXX, tests for border render.
4837 #result = self.begin_result(xmin, ymin, xmax - xmin, ymax - ymin)
4838 #result = self.begin_result(0, 0, xmax - xmin, ymax - ymin)
4839 lay = result.layers[0]
4841 # This assumes the file has been fully written We wait a bit, just in case!
4842 time.sleep(self.DELAY)
4843 try:
4844 lay.load_from_file(self._temp_file_out)
4845 # XXX, tests for border render.
4846 #lay.load_from_file(self._temp_file_out, xmin, ymin)
4847 except RuntimeError:
4848 print("***POV ERROR WHILE READING OUTPUT FILE***")
4850 # Not needed right now, might only be useful if we find a way to use temp raw output of
4851 # pov 3.7 (in which case it might go under _test_wait()).
4853 def update_image():
4854 # possible the image wont load early on.
4855 try:
4856 lay.load_from_file(self._temp_file_out)
4857 # XXX, tests for border render.
4858 #lay.load_from_file(self._temp_file_out, xmin, ymin)
4859 #lay.load_from_file(self._temp_file_out, xmin, ymin)
4860 except RuntimeError:
4861 pass
4863 # Update while POV-Ray renders
4864 while True:
4865 # print("***POV RENDER LOOP***")
4867 # test if POV-Ray exists
4868 if self._process.poll() is not None:
4869 print("***POV PROCESS FINISHED***")
4870 update_image()
4871 break
4873 # user exit
4874 if self.test_break():
4875 try:
4876 self._process.terminate()
4877 print("***POV PROCESS INTERRUPTED***")
4878 except OSError:
4879 pass
4881 break
4883 # Would be nice to redirect the output
4884 # stdout_value, stderr_value = self._process.communicate() # locks
4886 # check if the file updated
4887 new_size = os.path.getsize(self._temp_file_out)
4889 if new_size != prev_size:
4890 update_image()
4891 prev_size = new_size
4893 time.sleep(self.DELAY)
4896 self.end_result(result)
4898 else:
4899 print("***POV FILE NOT FOUND***")
4901 print("***POV FINISHED***")
4903 self.update_stats("", "")
4905 if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable:
4906 self._cleanup()
4909 ##################################################################################
4910 #################################Operators########################################
4911 ##################################################################################
4912 class RenderPovTexturePreview(Operator):
4913 bl_idname = "tex.preview_update"
4914 bl_label = "Update preview"
4915 def execute(self, context):
4916 tex=bpy.context.object.active_material.active_texture #context.texture
4917 texPrevName=string_strip_hyphen(bpy.path.clean_name(tex.name))+"_prev"
4919 ## Make sure Preview directory exists and is empty
4920 if not os.path.isdir(preview_dir):
4921 os.mkdir(preview_dir)
4923 iniPrevFile=os.path.join(preview_dir, "Preview.ini")
4924 inputPrevFile=os.path.join(preview_dir, "Preview.pov")
4925 outputPrevFile=os.path.join(preview_dir, texPrevName)
4926 ##################### ini ##########################################
4927 fileIni=open("%s"%iniPrevFile,"w")
4928 fileIni.write('Version=3.7\n')
4929 fileIni.write('Input_File_Name="%s"\n'%inputPrevFile)
4930 fileIni.write('Output_File_Name="%s.png"\n'%outputPrevFile)
4931 fileIni.write('Library_Path="%s"\n' % preview_dir)
4932 fileIni.write('Width=256\n')
4933 fileIni.write('Height=256\n')
4934 fileIni.write('Pause_When_Done=0\n')
4935 fileIni.write('Output_File_Type=N\n')
4936 fileIni.write('Output_Alpha=1\n')
4937 fileIni.write('Antialias=on\n')
4938 fileIni.write('Sampling_Method=2\n')
4939 fileIni.write('Antialias_Depth=3\n')
4940 fileIni.write('-d\n')
4941 fileIni.close()
4942 ##################### pov ##########################################
4943 filePov=open("%s"%inputPrevFile,"w")
4944 PATname = "PAT_"+string_strip_hyphen(bpy.path.clean_name(tex.name))
4945 filePov.write("#declare %s = \n"%PATname)
4946 filePov.write(exportPattern(tex))
4948 filePov.write("#declare Plane =\n")
4949 filePov.write("mesh {\n")
4950 filePov.write(" triangle {<-2.021,-1.744,2.021>,<-2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n")
4951 filePov.write(" triangle {<-2.021,-1.744,-2.021>,<2.021,-1.744,-2.021>,<2.021,-1.744,2.021>}\n")
4952 filePov.write(" texture{%s}\n"%PATname)
4953 filePov.write("}\n")
4954 filePov.write("object {Plane}\n")
4955 filePov.write("light_source {\n")
4956 filePov.write(" <0,4.38,-1.92e-07>\n")
4957 filePov.write(" color rgb<4, 4, 4>\n")
4958 filePov.write(" parallel\n")
4959 filePov.write(" point_at <0, 0, -1>\n")
4960 filePov.write("}\n")
4961 filePov.write("camera {\n")
4962 filePov.write(" location <0, 0, 0>\n")
4963 filePov.write(" look_at <0, 0, -1>\n")
4964 filePov.write(" right <-1.0, 0, 0>\n")
4965 filePov.write(" up <0, 1, 0>\n")
4966 filePov.write(" angle 96.805211\n")
4967 filePov.write(" rotate <-90.000003, -0.000000, 0.000000>\n")
4968 filePov.write(" translate <0.000000, 0.000000, 0.000000>\n")
4969 filePov.write("}\n")
4970 filePov.close()
4971 ##################### end write ##########################################
4973 pov_binary = PovrayRender._locate_binary()
4975 if sys.platform[:3] == "win":
4976 p1=subprocess.Popen(["%s"%pov_binary,"/EXIT","%s"%iniPrevFile],
4977 stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
4978 else:
4979 p1=subprocess.Popen(["%s"%pov_binary,"-d","%s"%iniPrevFile],
4980 stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
4981 p1.wait()
4983 tex.use_nodes = True
4984 tree = tex.node_tree
4985 links = tree.links
4986 for n in tree.nodes:
4987 tree.nodes.remove(n)
4988 im = tree.nodes.new("TextureNodeImage")
4989 pathPrev="%s.png"%outputPrevFile
4990 im.image = bpy.data.images.load(pathPrev)
4991 name=pathPrev
4992 name=name.split("/")
4993 name=name[len(name)-1]
4994 im.name = name
4995 im.location = 200,200
4996 previewer = tree.nodes.new('TextureNodeOutput')
4997 previewer.label = "Preview"
4998 previewer.location = 400,400
4999 links.new(im.outputs[0],previewer.inputs[0])
5000 #tex.type="IMAGE" # makes clip extend possible
5001 #tex.extension="CLIP"
5002 return {'FINISHED'}
5004 #################################POV-Ray specific###############################
5006 # XXX This should really be in a separate file imho (primitives.py eg?)
5008 from bpy.props import (
5009 StringProperty,
5010 BoolProperty,
5011 IntProperty,
5012 FloatProperty,
5013 FloatVectorProperty,
5014 EnumProperty,
5015 PointerProperty,
5016 CollectionProperty,
5020 def pov_define_mesh(mesh, verts, edges, faces, name, hide_geometry=True):
5021 if mesh is None:
5022 mesh = bpy.data.meshes.new(name)
5023 mesh.from_pydata(verts, edges, faces)
5024 mesh.update()
5025 mesh.validate(False) # Set it to True to see debug messages (helps ensure you generate valid geometry).
5026 if hide_geometry:
5027 mesh.vertices.foreach_set("hide", [True] * len(mesh.vertices))
5028 mesh.edges.foreach_set("hide", [True] * len(mesh.edges))
5029 mesh.polygons.foreach_set("hide", [True] * len(mesh.polygons))
5030 return mesh
5033 class POVRAY_OT_lathe_add(bpy.types.Operator):
5034 bl_idname = "pov.addlathe"
5035 bl_label = "Lathe"
5036 bl_options = {'REGISTER','UNDO'}
5037 bl_description = "adds lathe"
5040 def execute(self, context):
5041 layers=[False]*20
5042 layers[0]=True
5043 bpy.ops.curve.primitive_bezier_curve_add(location=(0, 0, 0),
5044 rotation=(0, 0, 0), layers=layers)
5045 ob=context.scene.objects.active
5046 ob.name = ob.data.name = "PovLathe"
5047 ob.pov.object_as='LATHE'
5048 bpy.ops.object.mode_set(mode='EDIT')
5049 self.report({'WARNING'}, "This native POV-Ray primitive "
5050 "won't have any vertex to show in edit mode")
5051 bpy.ops.transform.rotate(value=-pi/2, axis=(0, 0, 1))
5052 bpy.ops.object.mode_set(mode='OBJECT')
5053 ob.pov.curveshape = "lathe"
5054 bpy.ops.object.modifier_add(type='SCREW')
5055 bpy.context.object.modifiers["Screw"].axis = 'Y'
5056 bpy.context.object.modifiers["Screw"].show_render = False
5057 return {'FINISHED'}
5061 def pov_superellipsoid_define(context, op, ob):
5063 if op:
5064 mesh = None
5066 u = op.se_u
5067 v = op.se_v
5068 n1 = op.se_n1
5069 n2 = op.se_n2
5070 edit = op.se_edit
5071 se_param1 = n2 # op.se_param1
5072 se_param2 = n1 # op.se_param2
5074 else:
5075 assert(ob)
5076 mesh = ob.data
5078 u = ob.pov.se_u
5079 v = ob.pov.se_v
5080 n1 = ob.pov.se_n1
5081 n2 = ob.pov.se_n2
5082 edit = ob.pov.se_edit
5083 se_param1 = ob.pov.se_param1
5084 se_param2 = ob.pov.se_param2
5086 verts = []
5089 stepSegment=360/v*pi/180
5090 stepRing=pi/u
5091 angSegment=0
5092 angRing=-pi/2
5094 step=0
5095 for ring in range(0,u-1):
5096 angRing += stepRing
5097 for segment in range(0,v):
5098 step += 1
5099 angSegment += stepSegment
5100 x = r*(abs(cos(angRing))**n1)*(abs(cos(angSegment))**n2)
5101 if (cos(angRing) < 0 and cos(angSegment) > 0) or \
5102 (cos(angRing) > 0 and cos(angSegment) < 0):
5103 x = -x
5104 y = r*(abs(cos(angRing))**n1)*(abs(sin(angSegment))**n2)
5105 if (cos(angRing) < 0 and sin(angSegment) > 0) or \
5106 (cos(angRing) > 0 and sin(angSegment) < 0):
5107 y = -y
5108 z = r*(abs(sin(angRing))**n1)
5109 if sin(angRing) < 0:
5110 z = -z
5111 x = round(x,4)
5112 y = round(y,4)
5113 z = round(z,4)
5114 verts.append((x,y,z))
5115 if edit == 'TRIANGLES':
5116 verts.append((0,0,1))
5117 verts.append((0,0,-1))
5119 faces = []
5121 for i in range(0,u-2):
5122 m=i*v
5123 for p in range(0,v):
5124 if p < v-1:
5125 face=(m+p,1+m+p,v+1+m+p,v+m+p)
5126 if p == v-1:
5127 face=(m+p,m,v+m,v+m+p)
5128 faces.append(face)
5129 if edit == 'TRIANGLES':
5130 indexUp=len(verts)-2
5131 indexDown=len(verts)-1
5132 indexStartDown=len(verts)-2-v
5133 for i in range(0,v):
5134 if i < v-1:
5135 face=(indexDown,i,i+1)
5136 faces.append(face)
5137 if i == v-1:
5138 face=(indexDown,i,0)
5139 faces.append(face)
5140 for i in range(0,v):
5141 if i < v-1:
5142 face=(indexUp,i+indexStartDown,i+indexStartDown+1)
5143 faces.append(face)
5144 if i == v-1:
5145 face=(indexUp,i+indexStartDown,indexStartDown)
5146 faces.append(face)
5147 if edit == 'NGONS':
5148 face=[]
5149 for i in range(0,v):
5150 face.append(i)
5151 faces.append(face)
5152 face=[]
5153 indexUp=len(verts)-1
5154 for i in range(0,v):
5155 face.append(indexUp-i)
5156 faces.append(face)
5157 mesh = pov_define_mesh(mesh, verts, [], faces, "SuperEllipsoid")
5159 if not ob:
5160 ob_base = object_utils.object_data_add(context, mesh, operator=None)
5161 ob = ob_base.object
5162 #engine = context.scene.render.engine what for?
5163 ob = context.object
5164 ob.name = ob.data.name = "PovSuperellipsoid"
5165 ob.pov.object_as = 'SUPERELLIPSOID'
5166 ob.pov.se_param1 = n2
5167 ob.pov.se_param2 = n1
5169 ob.pov.se_u = u
5170 ob.pov.se_v = v
5171 ob.pov.se_n1 = n1
5172 ob.pov.se_n2 = n2
5173 ob.pov.se_edit = edit
5175 bpy.ops.object.mode_set(mode="EDIT")
5176 bpy.ops.mesh.hide(unselected=False)
5177 bpy.ops.object.mode_set(mode="OBJECT")
5179 class POVRAY_OT_superellipsoid_add(bpy.types.Operator):
5180 bl_idname = "pov.addsuperellipsoid"
5181 bl_label = "Add SuperEllipsoid"
5182 bl_description = "Create a SuperEllipsoid"
5183 bl_options = {'REGISTER', 'UNDO'}
5184 COMPAT_ENGINES = {'POVRAY_RENDER'}
5186 # XXX Keep it in sync with __init__'s RenderPovSettingsConePrimitive
5187 # If someone knows how to define operators' props from a func, I'd be delighted to learn it!
5188 se_param1 = FloatProperty(
5189 name="Parameter 1",
5190 description="",
5191 min=0.00, max=10.0, default=0.04)
5193 se_param2 = FloatProperty(
5194 name="Parameter 2",
5195 description="",
5196 min=0.00, max=10.0, default=0.04)
5198 se_u = IntProperty(name = "U-segments",
5199 description = "radial segmentation",
5200 default = 20, min = 4, max = 265)
5201 se_v = IntProperty(name = "V-segments",
5202 description = "lateral segmentation",
5203 default = 20, min = 4, max = 265)
5204 se_n1 = FloatProperty(name = "Ring manipulator",
5205 description = "Manipulates the shape of the Ring",
5206 default = 1.0, min = 0.01, max = 100.0)
5207 se_n2 = FloatProperty(name = "Cross manipulator",
5208 description = "Manipulates the shape of the cross-section",
5209 default = 1.0, min = 0.01, max = 100.0)
5210 se_edit = EnumProperty(items=[("NOTHING", "Nothing", ""),
5211 ("NGONS", "N-Gons", ""),
5212 ("TRIANGLES", "Triangles", "")],
5213 name="Fill up and down",
5214 description="",
5215 default='TRIANGLES')
5217 @classmethod
5218 def poll(cls, context):
5219 engine = context.scene.render.engine
5220 return (engine in cls.COMPAT_ENGINES)
5222 def execute(self,context):
5223 pov_superellipsoid_define(context, self, None)
5225 self.report({'WARNING'}, "This native POV-Ray primitive won't have any vertex to show in edit mode")
5227 return {'FINISHED'}
5229 class POVRAY_OT_superellipsoid_update(bpy.types.Operator):
5230 bl_idname = "pov.superellipsoid_update"
5231 bl_label = "Update"
5232 bl_description = "Update Superellipsoid"
5233 bl_options = {'REGISTER', 'UNDO'}
5234 COMPAT_ENGINES = {'POVRAY_RENDER'}
5236 @classmethod
5237 def poll(cls, context):
5238 engine = context.scene.render.engine
5239 ob = context.object
5240 return (ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES)
5242 def execute(self, context):
5243 bpy.ops.object.mode_set(mode="EDIT")
5244 bpy.ops.mesh.reveal()
5245 bpy.ops.mesh.select_all(action='SELECT')
5246 bpy.ops.mesh.delete(type='VERT')
5247 bpy.ops.object.mode_set(mode="OBJECT")
5249 pov_superellipsoid_define(context, None, context.object)
5251 return {'FINISHED'}
5253 def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
5254 faces = []
5255 if not vertIdx1 or not vertIdx2:
5256 return None
5257 if len(vertIdx1) < 2 and len(vertIdx2) < 2:
5258 return None
5259 fan = False
5260 if (len(vertIdx1) != len(vertIdx2)):
5261 if (len(vertIdx1) == 1 and len(vertIdx2) > 1):
5262 fan = True
5263 else:
5264 return None
5265 total = len(vertIdx2)
5266 if closed:
5267 if flipped:
5268 face = [
5269 vertIdx1[0],
5270 vertIdx2[0],
5271 vertIdx2[total - 1]]
5272 if not fan:
5273 face.append(vertIdx1[total - 1])
5274 faces.append(face)
5276 else:
5277 face = [vertIdx2[0], vertIdx1[0]]
5278 if not fan:
5279 face.append(vertIdx1[total - 1])
5280 face.append(vertIdx2[total - 1])
5281 faces.append(face)
5282 for num in range(total - 1):
5283 if flipped:
5284 if fan:
5285 face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
5286 else:
5287 face = [vertIdx2[num], vertIdx1[num],
5288 vertIdx1[num + 1], vertIdx2[num + 1]]
5289 faces.append(face)
5290 else:
5291 if fan:
5292 face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
5293 else:
5294 face = [vertIdx1[num], vertIdx2[num],
5295 vertIdx2[num + 1], vertIdx1[num + 1]]
5296 faces.append(face)
5298 return faces
5300 def power(a,b):
5301 if a < 0:
5302 return -((-a)**b)
5303 return a**b
5305 def supertoroid(R,r,u,v,n1,n2):
5306 a = 2*pi/u
5307 b = 2*pi/v
5308 verts = []
5309 faces = []
5310 for i in range(u):
5311 s = power(sin(i*a),n1)
5312 c = power(cos(i*a),n1)
5313 for j in range(v):
5314 c2 = R+r*power(cos(j*b),n2)
5315 s2 = r*power(sin(j*b),n2)
5316 verts.append((c*c2,s*c2,s2))# type as a (mathutils.Vector(c*c2,s*c2,s2))?
5317 if i > 0:
5318 f = createFaces(range((i-1)*v,i*v),range(i*v,(i+1)*v),closed = True)
5319 faces.extend(f)
5320 f = createFaces(range((u-1)*v,u*v),range(v),closed=True)
5321 faces.extend(f)
5322 return verts, faces
5324 def pov_supertorus_define(context, op, ob):
5325 if op:
5326 mesh = None
5327 st_R = op.st_R
5328 st_r = op.st_r
5329 st_u = op.st_u
5330 st_v = op.st_v
5331 st_n1 = op.st_n1
5332 st_n2 = op.st_n2
5333 st_ie = op.st_ie
5334 st_edit = op.st_edit
5336 else:
5337 assert(ob)
5338 mesh = ob.data
5339 st_R = ob.pov.st_major_radius
5340 st_r = ob.pov.st_minor_radius
5341 st_u = ob.pov.st_u
5342 st_v = ob.pov.st_v
5343 st_n1 = ob.pov.st_ring
5344 st_n2 = ob.pov.st_cross
5345 st_ie = ob.pov.st_ie
5346 st_edit = ob.pov.st_edit
5348 if st_ie:
5349 rad1 = (st_R+st_r)/2
5350 rad2 = (st_R-st_r)/2
5351 if rad2 > rad1:
5352 [rad1,rad2] = [rad2,rad1]
5353 else:
5354 rad1 = st_R
5355 rad2 = st_r
5356 if rad2 > rad1:
5357 rad1 = rad2
5358 verts,faces = supertoroid(rad1,
5359 rad2,
5360 st_u,
5361 st_v,
5362 st_n1,
5363 st_n2)
5364 mesh = pov_define_mesh(mesh, verts, [], faces, "PovSuperTorus", True)
5365 if not ob:
5366 ob_base = object_utils.object_data_add(context, mesh, operator=None)
5368 ob = ob_base.object
5369 ob.pov.object_as = 'SUPERTORUS'
5370 ob.pov.st_major_radius = st_R
5371 ob.pov.st_minor_radius = st_r
5372 ob.pov.st_u = st_u
5373 ob.pov.st_v = st_v
5374 ob.pov.st_ring = st_n1
5375 ob.pov.st_cross = st_n2
5376 ob.pov.st_ie = st_ie
5377 ob.pov.st_edit = st_edit
5379 class POVRAY_OT_supertorus_add(bpy.types.Operator):
5380 bl_idname = "pov.addsupertorus"
5381 bl_label = "Add Supertorus"
5382 bl_description = "Create a SuperTorus"
5383 bl_options = {'REGISTER', 'UNDO'}
5384 COMPAT_ENGINES = {'POVRAY_RENDER'}
5386 st_R = FloatProperty(name = "big radius",
5387 description = "The radius inside the tube",
5388 default = 1.0, min = 0.01, max = 100.0)
5389 st_r = FloatProperty(name = "small radius",
5390 description = "The radius of the tube",
5391 default = 0.3, min = 0.01, max = 100.0)
5392 st_u = IntProperty(name = "U-segments",
5393 description = "radial segmentation",
5394 default = 16, min = 3, max = 265)
5395 st_v = IntProperty(name = "V-segments",
5396 description = "lateral segmentation",
5397 default = 8, min = 3, max = 265)
5398 st_n1 = FloatProperty(name = "Ring manipulator",
5399 description = "Manipulates the shape of the Ring",
5400 default = 1.0, min = 0.01, max = 100.0)
5401 st_n2 = FloatProperty(name = "Cross manipulator",
5402 description = "Manipulates the shape of the cross-section",
5403 default = 1.0, min = 0.01, max = 100.0)
5404 st_ie = BoolProperty(name = "Use Int.+Ext. radii",
5405 description = "Use internal and external radii",
5406 default = False)
5407 st_edit = BoolProperty(name="",
5408 description="",
5409 default=False,
5410 options={'HIDDEN'})
5412 @classmethod
5413 def poll(cls, context):
5414 engine = context.scene.render.engine
5415 return (engine in cls.COMPAT_ENGINES)
5417 def execute(self, context):
5418 pov_supertorus_define(context, self, None)
5420 self.report({'WARNING'}, "This native POV-Ray primitive won't have any vertex to show in edit mode")
5421 return {'FINISHED'}
5423 class POVRAY_OT_supertorus_update(bpy.types.Operator):
5424 bl_idname = "pov.supertorus_update"
5425 bl_label = "Update"
5426 bl_description = "Update SuperTorus"
5427 bl_options = {'REGISTER', 'UNDO'}
5428 COMPAT_ENGINES = {'POVRAY_RENDER'}
5430 @classmethod
5431 def poll(cls, context):
5432 engine = context.scene.render.engine
5433 ob = context.object
5434 return (ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES)
5436 def execute(self, context):
5437 bpy.ops.object.mode_set(mode="EDIT")
5438 bpy.ops.mesh.reveal()
5439 bpy.ops.mesh.select_all(action='SELECT')
5440 bpy.ops.mesh.delete(type='VERT')
5441 bpy.ops.object.mode_set(mode="OBJECT")
5443 pov_supertorus_define(context, None, context.object)
5445 return {'FINISHED'}
5446 #########################################################################################################
5447 class POVRAY_OT_loft_add(bpy.types.Operator):
5448 bl_idname = "pov.addloft"
5449 bl_label = "Add Loft Data"
5450 bl_description = "Create a Curve data for Meshmaker"
5451 bl_options = {'REGISTER', 'UNDO'}
5452 COMPAT_ENGINES = {'POVRAY_RENDER'}
5454 loft_n = IntProperty(name = "Segments",
5455 description = "Vertical segments",
5456 default = 16, min = 3, max = 720)
5457 loft_rings_bottom = IntProperty(name = "Bottom",
5458 description = "Bottom rings",
5459 default = 5, min = 2, max = 100)
5460 loft_rings_side = IntProperty(name = "Side",
5461 description = "Side rings",
5462 default = 10, min = 2, max = 100)
5463 loft_thick = FloatProperty(name = "Thickness",
5464 description = "Manipulates the shape of the Ring",
5465 default = 0.3, min = 0.01, max = 1.0)
5466 loft_r = FloatProperty(name = "Radius",
5467 description = "Radius",
5468 default = 1, min = 0.01, max = 10)
5469 loft_height = FloatProperty(name = "Height",
5470 description = "Manipulates the shape of the Ring",
5471 default = 2, min = 0.01, max = 10.0)
5473 def execute(self,context):
5475 props = self.properties
5476 loftData = bpy.data.curves.new('Loft', type='CURVE')
5477 loftData.dimensions = '3D'
5478 loftData.resolution_u = 2
5479 loftData.show_normal_face = False
5480 n=props.loft_n
5481 thick = props.loft_thick
5482 side = props.loft_rings_side
5483 bottom = props.loft_rings_bottom
5484 h = props.loft_height
5485 r = props.loft_r
5486 distB = r/bottom
5487 r0 = 0.00001
5488 z = -h/2
5489 print("New")
5490 for i in range(bottom+1):
5491 coords = []
5492 angle = 0
5493 for p in range(n):
5494 x = r0*cos(angle)
5495 y = r0*sin(angle)
5496 coords.append((x,y,z))
5497 angle+=pi*2/n
5498 r0+=distB
5499 nurbs = loftData.splines.new('NURBS')
5500 nurbs.points.add(len(coords)-1)
5501 for i, coord in enumerate(coords):
5502 x,y,z = coord
5503 nurbs.points[i].co = (x, y, z, 1)
5504 nurbs.use_cyclic_u = True
5505 for i in range(side):
5506 z+=h/side
5507 coords = []
5508 angle = 0
5509 for p in range(n):
5510 x = r*cos(angle)
5511 y = r*sin(angle)
5512 coords.append((x,y,z))
5513 angle+=pi*2/n
5514 nurbs = loftData.splines.new('NURBS')
5515 nurbs.points.add(len(coords)-1)
5516 for i, coord in enumerate(coords):
5517 x,y,z = coord
5518 nurbs.points[i].co = (x, y, z, 1)
5519 nurbs.use_cyclic_u = True
5520 r-=thick
5521 for i in range(side):
5522 coords = []
5523 angle = 0
5524 for p in range(n):
5525 x = r*cos(angle)
5526 y = r*sin(angle)
5527 coords.append((x,y,z))
5528 angle+=pi*2/n
5529 nurbs = loftData.splines.new('NURBS')
5530 nurbs.points.add(len(coords)-1)
5531 for i, coord in enumerate(coords):
5532 x,y,z = coord
5533 nurbs.points[i].co = (x, y, z, 1)
5534 nurbs.use_cyclic_u = True
5535 z-=h/side
5536 z = (-h/2) + thick
5537 distB = (r-0.00001)/bottom
5538 for i in range(bottom+1):
5539 coords = []
5540 angle = 0
5541 for p in range(n):
5542 x = r*cos(angle)
5543 y = r*sin(angle)
5544 coords.append((x,y,z))
5545 angle+=pi*2/n
5546 r-=distB
5547 nurbs = loftData.splines.new('NURBS')
5548 nurbs.points.add(len(coords)-1)
5549 for i, coord in enumerate(coords):
5550 x,y,z = coord
5551 nurbs.points[i].co = (x, y, z, 1)
5552 nurbs.use_cyclic_u = True
5553 ob = bpy.data.objects.new('Loft_shape', loftData)
5554 scn = bpy.context.scene
5555 scn.objects.link(ob)
5556 scn.objects.active = ob
5557 ob.select = True
5558 ob.pov.curveshape = "loft"
5559 return {'FINISHED'}
5561 class POVRAY_OT_plane_add(bpy.types.Operator):
5562 bl_idname = "pov.addplane"
5563 bl_label = "Plane"
5564 bl_description = "Add Plane"
5565 bl_options = {'REGISTER', 'UNDO'}
5567 def execute(self,context):
5568 layers = 20*[False]
5569 layers[0] = True
5570 bpy.ops.mesh.primitive_plane_add(radius = 100000,layers=layers)
5571 ob = context.object
5572 ob.name = ob.data.name = 'PovInfinitePlane'
5573 bpy.ops.object.mode_set(mode="EDIT")
5574 self.report({'WARNING'}, "This native POV-Ray primitive "
5575 "won't have any vertex to show in edit mode")
5576 bpy.ops.mesh.hide(unselected=False)
5577 bpy.ops.object.mode_set(mode="OBJECT")
5578 bpy.ops.object.shade_smooth()
5579 ob.pov.object_as = "PLANE"
5580 return {'FINISHED'}
5582 class POVRAY_OT_box_add(bpy.types.Operator):
5583 bl_idname = "pov.addbox"
5584 bl_label = "Box"
5585 bl_description = "Add Box"
5586 bl_options = {'REGISTER', 'UNDO'}
5588 def execute(self,context):
5589 layers = 20*[False]
5590 layers[0] = True
5591 bpy.ops.mesh.primitive_cube_add(layers=layers)
5592 ob = context.object
5593 ob.name = ob.data.name = 'PovBox'
5594 bpy.ops.object.mode_set(mode="EDIT")
5595 self.report({'WARNING'}, "This native POV-Ray primitive "
5596 "won't have any vertex to show in edit mode")
5597 bpy.ops.mesh.hide(unselected=False)
5598 bpy.ops.object.mode_set(mode="OBJECT")
5599 ob.pov.object_as = "BOX"
5600 return {'FINISHED'}
5602 class POVRAY_OT_cylinder_add(bpy.types.Operator):
5603 bl_idname = "pov.addcylinder"
5604 bl_label = "Cylinder"
5605 bl_description = "Add Cylinder"
5606 bl_options = {'REGISTER', 'UNDO'}
5608 def execute(self,context):
5609 layers = 20*[False]
5610 layers[0] = True
5611 bpy.ops.mesh.primitive_cylinder_add(layers = layers)
5612 ob = context.object
5613 ob.name = ob.data.name = 'PovCylinder'
5614 bpy.ops.object.mode_set(mode="EDIT")
5615 self.report({'WARNING'}, "This native POV-Ray primitive "
5616 "won't have any vertex to show in edit mode")
5617 bpy.ops.mesh.hide(unselected=False)
5618 bpy.ops.object.mode_set(mode="OBJECT")
5619 ob.pov.object_as = "CYLINDER"
5621 return {'FINISHED'}
5622 ################################SPHERE##########################################
5623 def pov_sphere_define(context, op, ob, loc):
5624 if op:
5625 R = op.R
5627 else:
5628 assert(ob)
5629 R = ob.pov.sphere_radius
5631 #keep object rotation and location for the add object operator
5632 obrot = ob.rotation_euler
5633 #obloc = ob.location
5634 obscale = ob.scale
5636 bpy.ops.object.mode_set(mode="EDIT")
5637 bpy.ops.mesh.reveal()
5638 bpy.ops.mesh.select_all(action='SELECT')
5639 bpy.ops.mesh.delete(type='VERT')
5640 bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, size=ob.pov.sphere_radius, location=loc, rotation=obrot)
5641 #bpy.ops.transform.rotate(axis=obrot,constraint_orientation='GLOBAL')
5642 bpy.ops.transform.resize(value=obscale)
5643 #bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
5646 bpy.ops.mesh.hide(unselected=False)
5647 bpy.ops.object.mode_set(mode="OBJECT")
5648 #bpy.ops.transform.rotate(axis=obrot,constraint_orientation='GLOBAL')
5650 if not ob:
5651 bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, size=R, location=loc)
5652 ob = context.object
5653 ob.name = ob.data.name = "PovSphere"
5654 ob.pov.object_as = "SPHERE"
5655 ob.pov.sphere_radius = R
5656 bpy.ops.object.mode_set(mode="EDIT")
5657 bpy.ops.mesh.hide(unselected=False)
5658 bpy.ops.object.mode_set(mode="OBJECT")
5659 class POVRAY_OT_sphere_add(bpy.types.Operator):
5660 bl_idname = "pov.addsphere"
5661 bl_label = "Sphere"
5662 bl_description = "Add Sphere Shape"
5663 bl_options = {'REGISTER', 'UNDO'}
5665 # XXX Keep it in sync with __init__'s torus Primitive
5666 R = FloatProperty(name="Sphere radius",min=0.00, max=10.0, default=0.5)
5668 imported_loc = FloatVectorProperty(
5669 name="Imported Pov location",
5670 precision=6,
5671 default=(0.0, 0.0, 0.0))
5673 def execute(self,context):
5674 props = self.properties
5675 R = props.R
5676 ob = context.object
5677 if ob:
5678 if ob.pov.imported_loc:
5679 LOC = ob.pov.imported_loc
5680 else:
5681 LOC = bpy.context.scene.cursor_location
5682 pov_sphere_define(context, self, None, LOC)
5683 self.report({'WARNING'}, "This native POV-Ray primitive "
5684 "won't have any vertex to show in edit mode")
5685 return {'FINISHED'}
5687 # def execute(self,context):
5688 # layers = 20*[False]
5689 # layers[0] = True
5691 # bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4, radius=ob.pov.sphere_radius, layers=layers)
5692 # ob = context.object
5693 # bpy.ops.object.mode_set(mode="EDIT")
5694 # self.report({'WARNING'}, "This native POV-Ray primitive "
5695 # "won't have any vertex to show in edit mode")
5696 # bpy.ops.mesh.hide(unselected=False)
5697 # bpy.ops.object.mode_set(mode="OBJECT")
5698 # bpy.ops.object.shade_smooth()
5699 # ob.pov.object_as = "SPHERE"
5700 # ob.name = ob.data.name = 'PovSphere'
5701 # return {'FINISHED'}
5702 class POVRAY_OT_sphere_update(bpy.types.Operator):
5703 bl_idname = "pov.sphere_update"
5704 bl_label = "Update"
5705 bl_description = "Update Sphere"
5706 bl_options = {'REGISTER', 'UNDO'}
5707 COMPAT_ENGINES = {'POVRAY_RENDER'}
5709 @classmethod
5710 def poll(cls, context):
5711 engine = context.scene.render.engine
5712 ob = context.object
5713 return (ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES)
5715 def execute(self, context):
5717 pov_sphere_define(context, None, context.object,context.object.location)
5719 return {'FINISHED'}
5722 ####################################CONE#######################################
5723 def pov_cone_define(context, op, ob):
5724 verts = []
5725 faces = []
5726 if op:
5727 mesh = None
5728 base = op.base
5729 cap = op.cap
5730 seg = op.seg
5731 height = op.height
5732 else:
5733 assert(ob)
5734 mesh = ob.data
5735 base = ob.pov.cone_base_radius
5736 cap = ob.pov.cone_cap_radius
5737 seg = ob.pov.cone_segments
5738 height = ob.pov.cone_height
5740 zc = height / 2
5741 zb = -zc
5742 angle = 2 * pi / seg
5743 t = 0
5744 for i in range(seg):
5745 xb = base * cos(t)
5746 yb = base * sin(t)
5747 xc = cap * cos(t)
5748 yc = cap * sin(t)
5749 verts.append((xb, yb, zb))
5750 verts.append((xc, yc, zc))
5751 t += angle
5752 for i in range(seg):
5753 f = i * 2
5754 if i == seg - 1:
5755 faces.append([0, 1, f + 1, f])
5756 else:
5757 faces.append([f + 2, f + 3, f + 1, f])
5758 if base != 0:
5759 base_face = []
5760 for i in range(seg - 1, -1, -1):
5761 p = i * 2
5762 base_face.append(p)
5763 faces.append(base_face)
5764 if cap != 0:
5765 cap_face = []
5766 for i in range(seg):
5767 p = i * 2 + 1
5768 cap_face.append(p)
5769 faces.append(cap_face)
5771 mesh = pov_define_mesh(mesh, verts, [], faces, "PovCone", True)
5772 if not ob:
5773 ob_base = object_utils.object_data_add(context, mesh, operator=None)
5774 ob = ob_base.object
5775 ob.pov.object_as = "CONE"
5776 ob.pov.cone_base_radius = base
5777 ob.pov.cone_cap_radius = cap
5778 ob.pov.cone_height = height
5779 ob.pov.cone_base_z = zb
5780 ob.pov.cone_cap_z = zc
5783 class POVRAY_OT_cone_add(bpy.types.Operator):
5784 bl_idname = "pov.cone_add"
5785 bl_label = "Cone"
5786 bl_description = "Add Cone"
5787 bl_options = {'REGISTER', 'UNDO'}
5788 COMPAT_ENGINES = {'POVRAY_RENDER'}
5790 # XXX Keep it in sync with __init__'s RenderPovSettingsConePrimitive
5791 # If someone knows how to define operators' props from a func, I'd be delighted to learn it!
5792 base = FloatProperty(
5793 name = "Base radius", description = "The first radius of the cone",
5794 default = 1.0, min = 0.01, max = 100.0)
5795 cap = FloatProperty(
5796 name = "Cap radius", description = "The second radius of the cone",
5797 default = 0.3, min = 0.0, max = 100.0)
5798 seg = IntProperty(
5799 name = "Segments", description = "Radial segmentation of the proxy mesh",
5800 default = 16, min = 3, max = 265)
5801 height = FloatProperty(
5802 name = "Height", description = "Height of the cone",
5803 default = 2.0, min = 0.01, max = 100.0)
5805 @classmethod
5806 def poll(cls, context):
5807 engine = context.scene.render.engine
5808 return (engine in cls.COMPAT_ENGINES)
5810 def execute(self, context):
5811 pov_cone_define(context, self, None)
5813 self.report({'WARNING'}, "This native POV-Ray primitive won't have any vertex to show in edit mode")
5814 return {'FINISHED'}
5817 class POVRAY_OT_cone_update(bpy.types.Operator):
5818 bl_idname = "pov.cone_update"
5819 bl_label = "Update"
5820 bl_description = "Update Cone"
5821 bl_options = {'REGISTER', 'UNDO'}
5822 COMPAT_ENGINES = {'POVRAY_RENDER'}
5824 @classmethod
5825 def poll(cls, context):
5826 engine = context.scene.render.engine
5827 ob = context.object
5828 return (ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES)
5830 def execute(self, context):
5831 bpy.ops.object.mode_set(mode="EDIT")
5832 bpy.ops.mesh.reveal()
5833 bpy.ops.mesh.select_all(action='SELECT')
5834 bpy.ops.mesh.delete(type='VERT')
5835 bpy.ops.object.mode_set(mode="OBJECT")
5837 pov_cone_define(context, None, context.object)
5839 return {'FINISHED'}
5840 #########################################################################################################
5842 class POVRAY_OT_isosurface_box_add(bpy.types.Operator):
5843 bl_idname = "pov.addisosurfacebox"
5844 bl_label = "Isosurface Box"
5845 bl_description = "Add Isosurface contained by Box"
5846 bl_options = {'REGISTER', 'UNDO'}
5849 def execute(self,context):
5850 layers = 20*[False]
5851 layers[0] = True
5852 bpy.ops.mesh.primitive_cube_add(layers = layers)
5853 ob = context.object
5854 bpy.ops.object.mode_set(mode="EDIT")
5855 self.report({'WARNING'}, "This native POV-Ray primitive "
5856 "won't have any vertex to show in edit mode")
5857 bpy.ops.mesh.hide(unselected=False)
5858 bpy.ops.object.mode_set(mode="OBJECT")
5859 ob.pov.object_as = "ISOSURFACE"
5860 ob.pov.contained_by = 'box'
5861 ob.name = 'Isosurface'
5862 return {'FINISHED'}
5864 class POVRAY_OT_isosurface_sphere_add(bpy.types.Operator):
5865 bl_idname = "pov.addisosurfacesphere"
5866 bl_label = "Isosurface Sphere"
5867 bl_description = "Add Isosurface contained by Sphere"
5868 bl_options = {'REGISTER', 'UNDO'}
5871 def execute(self,context):
5872 layers = 20*[False]
5873 layers[0] = True
5874 bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=4,layers=layers)
5875 ob = context.object
5876 bpy.ops.object.mode_set(mode="EDIT")
5877 self.report({'WARNING'}, "This native POV-Ray primitive "
5878 "won't have any vertex to show in edit mode")
5879 bpy.ops.mesh.hide(unselected=False)
5880 bpy.ops.object.mode_set(mode="OBJECT")
5881 bpy.ops.object.shade_smooth()
5882 ob.pov.object_as = "ISOSURFACE"
5883 ob.pov.contained_by = 'sphere'
5884 ob.name = 'Isosurface'
5885 return {'FINISHED'}
5887 class POVRAY_OT_sphere_sweep_add(bpy.types.Operator):
5888 bl_idname = "pov.addspheresweep"
5889 bl_label = "Sphere Sweep"
5890 bl_description = "Create Sphere Sweep along curve"
5891 bl_options = {'REGISTER', 'UNDO'}
5893 def execute(self,context):
5894 layers = 20*[False]
5895 layers[0] = True
5896 bpy.ops.curve.primitive_nurbs_curve_add(layers = layers)
5897 ob = context.object
5898 ob.name = ob.data.name = "PovSphereSweep"
5899 ob.pov.curveshape = "sphere_sweep"
5900 ob.data.bevel_depth = 0.02
5901 ob.data.bevel_resolution = 4
5902 ob.data.fill_mode = 'FULL'
5903 #ob.data.splines[0].order_u = 4
5905 return {'FINISHED'}
5907 class POVRAY_OT_blob_add(bpy.types.Operator):
5908 bl_idname = "pov.addblobsphere"
5909 bl_label = "Blob Sphere"
5910 bl_description = "Add Blob Sphere"
5911 bl_options = {'REGISTER', 'UNDO'}
5913 def execute(self,context):
5914 layers = 20*[False]
5915 layers[0] = True
5916 bpy.ops.object.metaball_add(type = 'BALL',layers = layers)
5917 ob = context.object
5918 ob.name = "Blob"
5919 return {'FINISHED'}
5922 class POVRAY_OT_rainbow_add(bpy.types.Operator):
5923 bl_idname = "pov.addrainbow"
5924 bl_label = "Rainbow"
5925 bl_description = "Add Rainbow"
5926 bl_options = {'REGISTER', 'UNDO'}
5928 def execute(self,context):
5929 cam = context.scene.camera
5930 bpy.ops.object.lamp_add(type='SPOT', radius=1)
5931 ob = context.object
5932 ob.data.show_cone = False
5933 ob.data.spot_blend = 0.5
5934 ob.data.shadow_buffer_clip_end = 0
5935 ob.data.shadow_buffer_clip_start = 4*cam.location.length
5936 ob.data.distance = cam.location.length
5937 ob.data.energy = 0
5938 ob.name = ob.data.name = "PovRainbow"
5939 ob.pov.object_as = "RAINBOW"
5941 #obj = context.object
5942 bpy.ops.object.constraint_add(type='DAMPED_TRACK')
5946 ob.constraints["Damped Track"].target = cam
5947 ob.constraints["Damped Track"].track_axis = 'TRACK_NEGATIVE_Z'
5948 ob.location = -cam.location
5950 #refocus on the actual rainbow
5951 bpy.context.scene.objects.active = ob
5952 ob.select=True
5954 return {'FINISHED'}
5956 class POVRAY_OT_height_field_add(bpy.types.Operator, ImportHelper):
5957 bl_idname = "pov.addheightfield"
5958 bl_label = "Height Field"
5959 bl_description = "Add Height Field "
5960 bl_options = {'REGISTER', 'UNDO'}
5962 # XXX Keep it in sync with __init__'s hf Primitive
5963 # filename_ext = ".png"
5965 # filter_glob = StringProperty(
5966 # default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
5967 # options={'HIDDEN'},
5969 quality = IntProperty(name = "Quality",
5970 description = "",
5971 default = 100, min = 1, max = 100)
5972 hf_filename = StringProperty(maxlen = 1024)
5974 hf_gamma = FloatProperty(
5975 name="Gamma",
5976 description="Gamma",
5977 min=0.0001, max=20.0, default=1.0)
5979 hf_premultiplied = BoolProperty(
5980 name="Premultiplied",
5981 description="Premultiplied",
5982 default=True)
5984 hf_smooth = BoolProperty(
5985 name="Smooth",
5986 description="Smooth",
5987 default=False)
5989 hf_water = FloatProperty(
5990 name="Water Level",
5991 description="Wather Level",
5992 min=0.00, max=1.00, default=0.0)
5994 hf_hierarchy = BoolProperty(
5995 name="Hierarchy",
5996 description="Height field hierarchy",
5997 default=True)
5998 def execute(self,context):
5999 props = self.properties
6000 impath = bpy.path.abspath(self.filepath)
6001 img = bpy.data.images.load(impath)
6002 im_name = img.name
6003 im_name, file_extension = os.path.splitext(im_name)
6004 hf_tex = bpy.data.textures.new('%s_hf_image'%im_name, type = 'IMAGE')
6005 hf_tex.image = img
6006 mat = bpy.data.materials.new('Tex_%s_hf'%im_name)
6007 hf_slot = mat.texture_slots.create(-1)
6008 hf_slot.texture = hf_tex
6009 layers = 20*[False]
6010 layers[0] = True
6011 quality = props.quality
6012 res = 100/quality
6013 w,h = hf_tex.image.size[:]
6014 w = int(w/res)
6015 h = int(h/res)
6016 bpy.ops.mesh.primitive_grid_add(x_subdivisions=w, y_subdivisions=h,radius = 0.5,layers=layers)
6017 ob = context.object
6018 ob.name = ob.data.name = '%s'%im_name
6019 ob.data.materials.append(mat)
6020 bpy.ops.object.mode_set(mode="EDIT")
6021 bpy.ops.mesh.noise(factor=1)
6022 bpy.ops.object.mode_set(mode="OBJECT")
6024 #needs a loop to select by index?
6025 #bpy.ops.object.material_slot_remove()
6026 #material just left there for now
6029 mat.texture_slots.clear(-1)
6030 bpy.ops.object.mode_set(mode="EDIT")
6031 bpy.ops.mesh.hide(unselected=False)
6032 bpy.ops.object.mode_set(mode="OBJECT")
6033 ob.pov.object_as = 'HEIGHT_FIELD'
6034 ob.pov.hf_filename = impath
6035 return {'FINISHED'}
6038 ############################TORUS############################################
6039 def pov_torus_define(context, op, ob):
6040 if op:
6041 mas = op.mas
6042 mis = op.mis
6043 mar = op.mar
6044 mir = op.mir
6045 else:
6046 assert(ob)
6047 mas = ob.pov.torus_major_segments
6048 mis = ob.pov.torus_minor_segments
6049 mar = ob.pov.torus_major_radius
6050 mir = ob.pov.torus_minor_radius
6052 #keep object rotation and location for the add object operator
6053 obrot = ob.rotation_euler
6054 obloc = ob.location
6056 bpy.ops.object.mode_set(mode="EDIT")
6057 bpy.ops.mesh.reveal()
6058 bpy.ops.mesh.select_all(action='SELECT')
6059 bpy.ops.mesh.delete(type='VERT')
6060 bpy.ops.mesh.primitive_torus_add(rotation = obrot, location = obloc, major_segments=mas, minor_segments=mis,major_radius=mar, minor_radius=mir)
6063 bpy.ops.mesh.hide(unselected=False)
6064 bpy.ops.object.mode_set(mode="OBJECT")
6067 if not ob:
6068 bpy.ops.mesh.primitive_torus_add(major_segments=mas, minor_segments=mis,major_radius=mar, minor_radius=mir)
6069 ob = context.object
6070 ob.name = ob.data.name = "PovTorus"
6071 ob.pov.object_as = "TORUS"
6072 ob.pov.torus_major_segments = mas
6073 ob.pov.torus_minor_segments = mis
6074 ob.pov.torus_major_radius = mar
6075 ob.pov.torus_minor_radius = mir
6076 bpy.ops.object.mode_set(mode="EDIT")
6077 bpy.ops.mesh.hide(unselected=False)
6078 bpy.ops.object.mode_set(mode="OBJECT")
6080 class POVRAY_OT_torus_add(bpy.types.Operator):
6081 bl_idname = "pov.addtorus"
6082 bl_label = "Torus"
6083 bl_description = "Add Torus"
6084 bl_options = {'REGISTER', 'UNDO'}
6086 # XXX Keep it in sync with __init__'s torus Primitive
6087 mas = IntProperty(name = "Major Segments",
6088 description = "",
6089 default = 48, min = 3, max = 720)
6090 mis = IntProperty(name = "Minor Segments",
6091 description = "",
6092 default = 12, min = 3, max = 720)
6093 mar = FloatProperty(name = "Major Radius",
6094 description = "",
6095 default = 1.0)
6096 mir = FloatProperty(name = "Minor Radius",
6097 description = "",
6098 default = 0.25)
6099 def execute(self,context):
6100 props = self.properties
6101 mar = props.mar
6102 mir = props.mir
6103 mas = props.mas
6104 mis = props.mis
6105 pov_torus_define(context, self, None)
6106 self.report({'WARNING'}, "This native POV-Ray primitive "
6107 "won't have any vertex to show in edit mode")
6108 return {'FINISHED'}
6111 class POVRAY_OT_torus_update(bpy.types.Operator):
6112 bl_idname = "pov.torus_update"
6113 bl_label = "Update"
6114 bl_description = "Update Torus"
6115 bl_options = {'REGISTER', 'UNDO'}
6116 COMPAT_ENGINES = {'POVRAY_RENDER'}
6118 @classmethod
6119 def poll(cls, context):
6120 engine = context.scene.render.engine
6121 ob = context.object
6122 return (ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES)
6124 def execute(self, context):
6126 pov_torus_define(context, None, context.object)
6128 return {'FINISHED'}
6130 ###################################################################################
6133 class POVRAY_OT_prism_add(bpy.types.Operator):
6134 bl_idname = "pov.addprism"
6135 bl_label = "Prism"
6136 bl_description = "Create Prism"
6137 bl_options = {'REGISTER', 'UNDO'}
6139 prism_n = IntProperty(name = "Sides",
6140 description = "Number of sides",
6141 default = 5, min = 3, max = 720)
6142 prism_r = FloatProperty(name = "Radius",
6143 description = "Radius",
6144 default = 1.0)
6145 def execute(self,context):
6147 props = self.properties
6148 loftData = bpy.data.curves.new('Prism', type='CURVE')
6149 loftData.dimensions = '2D'
6150 loftData.resolution_u = 2
6151 loftData.show_normal_face = False
6152 loftData.extrude = 2
6153 n=props.prism_n
6154 r=props.prism_r
6155 coords = []
6156 z = 0
6157 angle = 0
6158 for p in range(n):
6159 x = r*cos(angle)
6160 y = r*sin(angle)
6161 coords.append((x,y,z))
6162 angle+=pi*2/n
6163 poly = loftData.splines.new('POLY')
6164 poly.points.add(len(coords)-1)
6165 for i, coord in enumerate(coords):
6166 x,y,z = coord
6167 poly.points[i].co = (x, y, z, 1)
6168 poly.use_cyclic_u = True
6170 ob = bpy.data.objects.new('Prism_shape', loftData)
6171 scn = bpy.context.scene
6172 scn.objects.link(ob)
6173 scn.objects.active = ob
6174 ob.select = True
6175 ob.pov.curveshape = "prism"
6176 ob.name = ob.data.name = "Prism"
6177 return {'FINISHED'}
6179 ##############################PARAMETRIC######################################
6180 def pov_parametric_define(context, op, ob):
6181 if op:
6182 u_min = op.u_min
6183 u_max = op.u_max
6184 v_min = op.v_min
6185 v_max = op.v_max
6186 x_eq = op.x_eq
6187 y_eq = op.y_eq
6188 z_eq = op.z_eq
6190 else:
6191 assert(ob)
6192 u_min = ob.pov.u_min
6193 u_max = ob.pov.u_max
6194 v_min = ob.pov.v_min
6195 v_max = ob.pov.v_max
6196 x_eq = ob.pov.x_eq
6197 y_eq = ob.pov.y_eq
6198 z_eq = ob.pov.z_eq
6200 #keep object rotation and location for the updated object
6201 obloc = ob.location
6202 obrot = ob.rotation_euler # In radians
6203 #Parametric addon has no loc rot, some extra work is needed
6204 #in case cursor has moved
6205 curloc = bpy.context.scene.cursor_location
6208 bpy.ops.object.mode_set(mode="EDIT")
6209 bpy.ops.mesh.reveal()
6210 bpy.ops.mesh.select_all(action='SELECT')
6211 bpy.ops.mesh.delete(type='VERT')
6212 bpy.ops.mesh.primitive_xyz_function_surface(x_eq=x_eq, y_eq=y_eq, z_eq=z_eq, range_u_min=u_min, range_u_max=u_max, range_v_min=v_min, range_v_max=v_max)
6213 bpy.ops.mesh.select_all(action='SELECT')
6214 #extra work:
6215 bpy.ops.transform.translate(value=(obloc-curloc), proportional_size=1)
6216 bpy.ops.transform.rotate(axis=obrot, proportional_size=1)
6218 bpy.ops.mesh.hide(unselected=False)
6219 bpy.ops.object.mode_set(mode="OBJECT")
6222 if not ob:
6223 bpy.ops.mesh.primitive_xyz_function_surface(x_eq=x_eq, y_eq=y_eq, z_eq=z_eq, range_u_min=u_min, range_u_max=u_max, range_v_min=v_min, range_v_max=v_max)
6224 ob = context.object
6225 ob.name = ob.data.name = "PovParametric"
6226 ob.pov.object_as = "PARAMETRIC"
6228 ob.pov.u_min = u_min
6229 ob.pov.u_max = u_max
6230 ob.pov.v_min = v_min
6231 ob.pov.v_max = v_max
6232 ob.pov.x_eq = x_eq
6233 ob.pov.y_eq = y_eq
6234 ob.pov.z_eq = z_eq
6236 bpy.ops.object.mode_set(mode="EDIT")
6237 bpy.ops.mesh.hide(unselected=False)
6238 bpy.ops.object.mode_set(mode="OBJECT")
6239 class POVRAY_OT_parametric_add(bpy.types.Operator):
6240 bl_idname = "pov.addparametric"
6241 bl_label = "Parametric"
6242 bl_description = "Add Paramertic"
6243 bl_options = {'REGISTER', 'UNDO'}
6245 # XXX Keep it in sync with __init__'s Parametric primitive
6246 u_min = FloatProperty(name = "U Min",
6247 description = "",
6248 default = 0.0)
6249 v_min = FloatProperty(name = "V Min",
6250 description = "",
6251 default = 0.0)
6252 u_max = FloatProperty(name = "U Max",
6253 description = "",
6254 default = 6.28)
6255 v_max = FloatProperty(name = "V Max",
6256 description = "",
6257 default = 12.57)
6258 x_eq = StringProperty(
6259 maxlen=1024, default = "cos(v)*(1+cos(u))*sin(v/8)")
6260 y_eq = StringProperty(
6261 maxlen=1024, default = "sin(u)*sin(v/8)+cos(v/8)*1.5")
6262 z_eq = StringProperty(
6263 maxlen=1024, default = "sin(v)*(1+cos(u))*sin(v/8)")
6265 def execute(self,context):
6266 props = self.properties
6267 u_min = props.u_min
6268 v_min = props.v_min
6269 u_max = props.u_max
6270 v_max = props.v_max
6271 x_eq = props.x_eq
6272 y_eq = props.y_eq
6273 z_eq = props.z_eq
6275 pov_parametric_define(context, self, None)
6276 self.report({'WARNING'}, "This native POV-Ray primitive "
6277 "won't have any vertex to show in edit mode")
6278 return {'FINISHED'}
6280 class POVRAY_OT_parametric_update(bpy.types.Operator):
6281 bl_idname = "pov.parametric_update"
6282 bl_label = "Update"
6283 bl_description = "Update parametric object"
6284 bl_options = {'REGISTER', 'UNDO'}
6285 COMPAT_ENGINES = {'POVRAY_RENDER'}
6287 @classmethod
6288 def poll(cls, context):
6289 engine = context.scene.render.engine
6290 ob = context.object
6291 return (ob and ob.data and ob.type == 'MESH' and engine in cls.COMPAT_ENGINES)
6293 def execute(self, context):
6295 pov_parametric_define(context, None, context.object)
6297 return {'FINISHED'}
6298 #######################################################################
6299 class POVRAY_OT_shape_polygon_to_circle_add(bpy.types.Operator):
6300 bl_idname = "pov.addpolygontocircle"
6301 bl_label = "Polygon To Circle Blending"
6302 bl_description = "Add Polygon To Circle Blending Surface"
6303 bl_options = {'REGISTER', 'UNDO'}
6304 COMPAT_ENGINES = {'POVRAY_RENDER'}
6306 # XXX Keep it in sync with __init__'s polytocircle properties
6307 polytocircle_resolution = IntProperty(name = "Resolution",
6308 description = "",
6309 default = 3, min = 0, max = 256)
6310 polytocircle_ngon = IntProperty(name = "NGon",
6311 description = "",
6312 min = 3, max = 64,default = 5)
6313 polytocircle_ngonR = FloatProperty(name = "NGon Radius",
6314 description = "",
6315 default = 0.3)
6316 polytocircle_circleR = FloatProperty(name = "Circle Radius",
6317 description = "",
6318 default = 1.0)
6319 def execute(self,context):
6320 props = self.properties
6321 ngon = props.polytocircle_ngon
6322 ngonR = props.polytocircle_ngonR
6323 circleR = props.polytocircle_circleR
6324 resolution = props.polytocircle_resolution
6325 layers = 20*[False]
6326 layers[0] = True
6327 bpy.ops.mesh.primitive_circle_add(vertices=ngon, radius=ngonR, fill_type='NGON',enter_editmode=True, layers=layers)
6328 bpy.ops.transform.translate(value=(0, 0, 1))
6329 bpy.ops.mesh.subdivide(number_cuts=resolution)
6330 numCircleVerts = ngon + (ngon*resolution)
6331 bpy.ops.mesh.select_all(action='DESELECT')
6332 bpy.ops.mesh.primitive_circle_add(vertices=numCircleVerts, radius=circleR, fill_type='NGON',enter_editmode=True, layers=layers)
6333 bpy.ops.transform.translate(value=(0, 0, -1))
6334 bpy.ops.mesh.select_all(action='SELECT')
6335 bpy.ops.mesh.bridge_edge_loops()
6336 if ngon < 5:
6337 bpy.ops.mesh.select_all(action='DESELECT')
6338 bpy.ops.mesh.primitive_circle_add(vertices=ngon, radius=ngonR, fill_type='TRIFAN',enter_editmode=True, layers=layers)
6339 bpy.ops.transform.translate(value=(0, 0, 1))
6340 bpy.ops.mesh.select_all(action='SELECT')
6341 bpy.ops.mesh.remove_doubles()
6342 bpy.ops.object.mode_set(mode='OBJECT')
6343 ob = context.object
6344 ob.name = "Polygon_To_Circle"
6345 ob.pov.object_as = 'POLYCIRCLE'
6346 ob.pov.ngon = ngon
6347 ob.pov.ngonR = ngonR
6348 ob.pov.circleR = circleR
6349 bpy.ops.object.mode_set(mode="EDIT")
6350 bpy.ops.mesh.hide(unselected=False)
6351 bpy.ops.object.mode_set(mode="OBJECT")
6352 return {'FINISHED'}
6354 #############################IMPORT
6355 class ImportAvogadroPOV(bpy.types.Operator, ImportHelper):
6356 """Load Povray File as output by Avogadro"""
6357 bl_idname = "import_scene.avogadro"
6358 bl_label = "Import POV Avogadro"
6359 bl_options = {'PRESET', 'UNDO'}
6360 COMPAT_ENGINES = {'POVRAY_RENDER'}
6362 filename_ext = ".pov"
6363 filter_glob = StringProperty(
6364 default="*.pov",
6365 options={'HIDDEN'},
6368 def execute(self, context):
6369 coords=[]
6370 colors = []
6371 matNames = []
6372 xall = yall = zall = []
6373 layers = 20*[False]
6374 layers[0] = True
6375 ob = None
6376 camloc = (0,0,0)
6377 filepov = bpy.path.abspath(self.filepath)
6378 for line in open(filepov):
6379 string = line.replace("<"," ")
6380 chars = [">","{","}",","]
6381 for symbol in chars:
6382 string = string.replace(symbol," ")
6383 split = string.split()
6384 if split and split[0] == "location":
6385 x = float(split[1])
6386 y = float(split[2])
6387 z = float(split[3])
6388 camloc = ((x,y,z))
6389 if split and len(split) == 7:
6390 try:
6391 x1 = float(split[0])
6392 coords.append(x1)
6393 except:
6394 pass
6395 if coords != []:
6396 x1 = float(split[0])
6397 y1 = float(split[1])
6398 z1 = float(split[2])
6399 x2 = float(split[3])
6400 y2 = float(split[4])
6401 z2 = float(split[5])
6402 xall.append(x1)
6403 yall.append(y1)
6404 zall.append(z1)
6405 xall.append(x2)
6406 yall.append(y2)
6407 zall.append(z2)
6408 radius = float(split[6])
6409 curveData = bpy.data.curves.new('myCurve', type='CURVE')
6410 curveData.dimensions = '3D'
6411 curveData.resolution_u = 2
6412 curveData.fill_mode = "FULL"
6413 curveData.bevel_depth = radius
6414 curveData.bevel_resolution = 5
6415 polyline = curveData.splines.new('POLY')
6416 polyline.points.add(1)
6417 polyline.points[0].co = (x1, y1, z1, 1)
6418 polyline.points[1].co = (x2, y2, z2, 1)
6419 ob = bpy.data.objects.new('myCurve', curveData)
6420 scn = bpy.context.scene
6421 scn.objects.link(ob)
6422 scn.objects.active = ob
6423 ob.select = True
6424 bpy.ops.object.convert(target='MESH',keep_original=False)
6425 #XXX TODO use a PovCylinder instead of mesh
6426 #but add end points and radius to addPovcylinder op first
6427 ob.select=False
6428 coords = []
6429 if split and len(split) == 4:
6430 try:
6431 x = float(split[0])
6432 coords.append(x)
6433 except:
6434 pass
6435 if coords != []:
6436 x = float(split[0])
6437 y = float(split[1])
6438 z = float(split[2])
6439 xall.append(x)
6440 yall.append(y)
6441 zall.append(z)
6442 radius = float(split[3])
6445 ob.pov.imported_loc=(x, y, z)
6446 bpy.ops.pov.addsphere(R=radius, imported_loc=(x, y, z))
6447 bpy.ops.object.shade_smooth()
6448 ob = bpy.context.object
6449 coords = []
6450 if split and len(split) == 6:
6451 if split[0] == "pigment":
6452 r,g,b,t = float(split[2]),float(split[3]),float(split[4]),float(split[5])
6453 color = (r,g,b,t)
6454 if colors == [] or (colors != [] and color not in colors):
6455 colors.append(color)
6456 name = ob.name+"_mat"
6457 matNames.append(name)
6458 mat = bpy.data.materials.new(name)
6459 mat.diffuse_color = (r,g,b)
6460 mat.alpha = 1-t
6461 ob.data.materials.append(mat)
6462 print (colors)
6463 else:
6464 for i in range(len(colors)):
6465 if color == colors[i]:
6466 ob.data.materials.append(bpy.data.materials[matNames[i]])
6467 x0 = min(xall)
6468 x1 = max(xall)
6469 y0 = min(yall)
6470 y1 = max(yall)
6471 z0 = min(zall)
6472 z1 = max(zall)
6473 x = (x0+x1)/2
6474 y = (y0+y1)/2
6475 z = (z0+z1)/2
6476 bpy.ops.object.empty_add(layers=layers)
6477 ob = bpy.context.object
6478 ob.location = ((x,y,z))
6479 for obj in bpy.context.scene.objects:
6480 if obj.type == "CAMERA":
6481 track = obj.constraints.new(type = "TRACK_TO")
6482 track.target = ob
6483 track.track_axis ="TRACK_NEGATIVE_Z"
6484 track.up_axis = "UP_Y"
6485 obj.location = camloc
6486 for obj in bpy.context.scene.objects:
6487 if obj.type == "LAMP":
6488 obj.location = camloc
6489 obj.pov.light_type = "shadowless"
6490 break
6491 return {'FINISHED'}