Export_3ds: Improved distance cue node search
[blender-addons.git] / render_povray / model_poly_topology.py
blob808facc1c9e8dac0f52921383d4cbd5ccfbc7c56
1 # SPDX-FileCopyrightText: 2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """Translate to POV the control point compound geometries.
7 Here polygon meshes as POV mesh2 objects.
8 """
10 import bpy
11 from . import texturing
12 from .scenography import image_format, img_map, img_map_transforms
13 from .shading import write_object_material_interior
14 from .model_primitives import write_object_modifiers
16 def write_object_csg_inside_vector(ob, file):
17 """Write inside vector for use by pov CSG, only once per object using boolean"""
18 has_csg_inside_vector = False
19 for modif in ob.modifiers:
20 if not has_csg_inside_vector and modif.type == "BOOLEAN" and ob.pov.boolean_mod == "POV":
21 file.write(
22 "\tinside_vector <%.6g, %.6g, %.6g>\n"
23 % (
24 ob.pov.inside_vector[0],
25 ob.pov.inside_vector[1],
26 ob.pov.inside_vector[2],
29 has_csg_inside_vector = True
31 def export_mesh(file,
32 ob,
33 povdataname,
34 material_names_dictionary,
35 unpacked_images,
36 tab_level,
37 tab_write,
38 linebreaksinlists):
39 from .render import (
40 string_strip_hyphen,
41 tab,
42 comments,
43 preview_dir,
46 ob_eval = ob # not sure this is needed in case to_mesh_clear could damage obj ?
47 importance = ob.pov.importance_value
49 try:
50 me = ob_eval.to_mesh()
52 # Here identify the exception for mesh object with no data: Runtime-Error ?
53 # So we can write something for the dataname or maybe treated "if not me" below
54 except BaseException as e:
55 print(e.__doc__)
56 print("An exception occurred: {}".format(e))
57 # also happens when curves can't be made into meshes because of no-data
58 return False # To continue object loop
59 if me:
60 me.calc_loop_triangles()
61 me_materials = me.materials
62 me_faces = me.loop_triangles[:]
63 # --- numpytest
64 # me_looptris = me.loops
66 # Below otypes = ['int32'] is a 32-bit signed integer number numpy datatype
67 # get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
68 # faces_verts_idx = get_v_index(me_looptris)
70 # if len(me_faces)==0:
71 # tab_write(file, "\n//dummy sphere to represent empty mesh location\n")
72 # tab_write(file, "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n" % povdataname)
74 if not me or not me_faces:
75 tab_write(file, "\n//dummy sphere to represent empty mesh location\n")
76 tab_write(
77 file,
78 "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
79 % povdataname,
81 return False # To continue object loop
83 uv_layers = me.uv_layers
84 if len(uv_layers) > 0:
85 if me.uv_layers.active and uv_layers.active.data:
86 uv_layer = uv_layers.active.data
87 else:
88 uv_layer = None
90 try:
91 # vcol_layer = me.vertex_colors.active.data
92 vcol_layer = me.vertex_colors.active.data
93 except AttributeError:
94 vcol_layer = None
96 faces_verts = [f.vertices[:] for f in me_faces]
97 faces_normals = [f.normal[:] for f in me_faces]
98 verts_normals = [v.normal[:] for v in me.vertices]
100 # Use named declaration to allow reference e.g. for baking. MR
101 file.write("\n")
102 tab_write(file, "#declare %s =\n" % povdataname)
103 tab_write(file, "mesh2 {\n")
104 tab_write(file, "vertex_vectors {\n")
105 tab_write(file, "%d" % len(me.vertices)) # vert count
107 tab_str = tab * tab_level
108 for v in me.vertices:
109 if linebreaksinlists:
110 file.write(",\n")
111 file.write(tab_str + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
112 else:
113 file.write(", ")
114 file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
115 # tab_write(file, "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
116 file.write("\n")
117 tab_write(file, "}\n")
119 # Build unique Normal list
120 uniqueNormals = {}
121 for fi, f in enumerate(me_faces):
122 fv = faces_verts[fi]
123 # [-1] is a dummy index, use a list so we can modify in place
124 if f.use_smooth: # Use vertex normals
125 for v in fv:
126 key = verts_normals[v]
127 uniqueNormals[key] = [-1]
128 else: # Use face normal
129 key = faces_normals[fi]
130 uniqueNormals[key] = [-1]
132 tab_write(file, "normal_vectors {\n")
133 tab_write(file, "%d" % len(uniqueNormals)) # vert count
134 idx = 0
135 tab_str = tab * tab_level
136 for no, index in uniqueNormals.items():
137 if linebreaksinlists:
138 file.write(",\n")
139 file.write(tab_str + "<%.6f, %.6f, %.6f>" % no) # vert count
140 else:
141 file.write(", ")
142 file.write("<%.6f, %.6f, %.6f>" % no) # vert count
143 index[0] = idx
144 idx += 1
145 file.write("\n")
146 tab_write(file, "}\n")
147 # Vertex colors
148 vertCols = {} # Use for material colors also.
150 if uv_layer:
151 # Generate unique UV's
152 uniqueUVs = {}
153 # n = 0
154 for f in me_faces: # me.faces in 2.7
155 uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
157 for uv in uvs:
158 uniqueUVs[uv[:]] = [-1]
160 tab_write(file, "uv_vectors {\n")
161 # print unique_uvs
162 tab_write(file, "%d" % len(uniqueUVs)) # vert count
163 idx = 0
164 tab_str = tab * tab_level
165 for uv, index in uniqueUVs.items():
166 if linebreaksinlists:
167 file.write(",\n")
168 file.write(tab_str + "<%.6f, %.6f>" % uv)
169 else:
170 file.write(", ")
171 file.write("<%.6f, %.6f>" % uv)
172 index[0] = idx
173 idx += 1
175 else:
176 # Just add 1 dummy vector, no real UV's
177 tab_write(file, '1') # vert count
178 file.write(',\n\t\t<0.0, 0.0>')
180 file.write("\n")
181 tab_write(file, "}\n")
182 if me.vertex_colors:
183 # Write down vertex colors as a texture for each vertex
184 tab_write(file, "texture_list {\n")
185 tab_write(
186 file, "%d\n" % (len(me_faces) * 3)
187 ) # assumes we have only triangles
188 VcolIdx = 0
189 if comments:
190 file.write(
191 "\n //Vertex colors: one simple pigment texture per vertex\n"
193 for fi, f in enumerate(me_faces):
194 # annoying, index may be invalid
195 material_index = f.material_index
196 try:
197 material = me_materials[material_index]
198 except BaseException as e:
199 print(e.__doc__)
200 print("An exception occurred: {}".format(e))
201 material = None
202 if (
203 material
204 # and material.pov.use_vertex_color_paint
205 ): # Or maybe Always use vertex color when there is some for now
207 cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
209 for col in cols:
210 key = (
211 col[0],
212 col[1],
213 col[2],
214 material_index,
215 ) # Material index!
216 VcolIdx += 1
217 vertCols[key] = [VcolIdx]
218 if linebreaksinlists:
219 tab_write(
220 file,
221 "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
222 % (col[0], col[1], col[2]),
224 else:
225 tab_write(
226 file,
227 "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
228 % (col[0], col[1], col[2]),
230 tab_str = tab * tab_level
231 else:
232 if material:
233 # Multiply diffuse with SSS Color
234 if material.pov_subsurface_scattering.use:
235 diffuse_color = [
236 i * j
237 for i, j in zip(
238 material.pov_subsurface_scattering.color[:],
239 material.diffuse_color[:],
242 key = (
243 diffuse_color[0],
244 diffuse_color[1],
245 diffuse_color[2],
246 material_index,
248 vertCols[key] = [-1]
249 else:
250 diffuse_color = material.diffuse_color[:]
251 key = (
252 diffuse_color[0],
253 diffuse_color[1],
254 diffuse_color[2],
255 material_index,
257 vertCols[key] = [-1]
259 tab_write(file, "\n}\n")
260 # Face indices
261 tab_write(file, "\nface_indices {\n")
262 tab_write(file, "%d" % (len(me_faces))) # faces count
263 tab_str = tab * tab_level
265 for fi, f in enumerate(me_faces):
266 fv = faces_verts[fi]
267 material_index = f.material_index
269 if vcol_layer:
270 cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
272 if not me_materials or (
273 me_materials[material_index] is None
274 ): # No materials
275 if linebreaksinlists:
276 file.write(",\n")
277 # vert count
278 file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
279 else:
280 file.write(", ")
281 file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
282 else:
283 material = me_materials[material_index]
284 if me.vertex_colors: # and material.pov.use_vertex_color_paint:
285 # Color per vertex - vertex color
287 col1 = cols[0]
288 col2 = cols[1]
289 col3 = cols[2]
291 ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
292 ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
293 ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
294 else:
295 # Color per material - flat material color
296 if material.pov_subsurface_scattering.use:
297 diffuse_color = [
298 i * j
299 for i, j in zip(
300 material.pov_subsurface_scattering.color[:],
301 material.diffuse_color[:],
304 else:
305 diffuse_color = material.diffuse_color[:]
306 ci1 = ci2 = ci3 = vertCols[
307 diffuse_color[0],
308 diffuse_color[1],
309 diffuse_color[2],
310 f.material_index,
311 ][0]
312 # ci are zero based index so we'll subtract 1 from them
313 if linebreaksinlists:
314 file.write(",\n")
315 file.write(
316 tab_str
317 + "<%d,%d,%d>, %d,%d,%d"
319 fv[0],
320 fv[1],
321 fv[2],
322 ci1 - 1,
323 ci2 - 1,
324 ci3 - 1,
326 ) # vert count
327 else:
328 file.write(", ")
329 file.write(
330 "<%d,%d,%d>, %d,%d,%d"
332 fv[0],
333 fv[1],
334 fv[2],
335 ci1 - 1,
336 ci2 - 1,
337 ci3 - 1,
339 ) # vert count
341 file.write("\n")
342 tab_write(file, "}\n")
344 # normal_indices indices
345 tab_write(file, "normal_indices {\n")
346 tab_write(file, "%d" % (len(me_faces))) # faces count
347 tab_str = tab * tab_level
348 for fi, fv in enumerate(faces_verts):
350 if me_faces[fi].use_smooth:
351 if linebreaksinlists:
352 file.write(",\n")
353 file.write(
354 tab_str
355 + "<%d,%d,%d>"
357 uniqueNormals[verts_normals[fv[0]]][0],
358 uniqueNormals[verts_normals[fv[1]]][0],
359 uniqueNormals[verts_normals[fv[2]]][0],
361 ) # vert count
362 else:
363 file.write(", ")
364 file.write(
365 "<%d,%d,%d>"
367 uniqueNormals[verts_normals[fv[0]]][0],
368 uniqueNormals[verts_normals[fv[1]]][0],
369 uniqueNormals[verts_normals[fv[2]]][0],
371 ) # vert count
372 else:
373 idx = uniqueNormals[faces_normals[fi]][0]
374 if linebreaksinlists:
375 file.write(",\n")
376 file.write(
377 tab_str + "<%d,%d,%d>" % (idx, idx, idx)
378 ) # vert count
379 else:
380 file.write(", ")
381 file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
383 file.write("\n")
384 tab_write(file, "}\n")
386 if uv_layer:
387 tab_write(file, "uv_indices {\n")
388 tab_write(file, "%d" % (len(me_faces))) # faces count
389 tab_str = tab * tab_level
390 for f in me_faces:
391 uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
393 if linebreaksinlists:
394 file.write(",\n")
395 file.write(
396 tab_str
397 + "<%d,%d,%d>"
399 uniqueUVs[uvs[0]][0],
400 uniqueUVs[uvs[1]][0],
401 uniqueUVs[uvs[2]][0],
404 else:
405 file.write(", ")
406 file.write(
407 "<%d,%d,%d>"
409 uniqueUVs[uvs[0]][0],
410 uniqueUVs[uvs[1]][0],
411 uniqueUVs[uvs[2]][0],
415 file.write("\n")
416 tab_write(file, "}\n")
418 # XXX BOOLEAN MODIFIER
419 write_object_csg_inside_vector(ob, file)
421 if me.materials:
422 try:
423 material = me.materials[0] # dodgy
424 write_object_material_interior(file, material, ob, tab_write)
425 except IndexError:
426 print(me)
428 # POV object modifiers such as
429 # hollow / sturm / double_illuminate etc.
430 write_object_modifiers(ob, file)
432 # Importance for radiosity sampling added here:
433 tab_write(file, "radiosity { \n")
434 tab_write(file, "importance %3g \n" % importance)
435 tab_write(file, "}\n")
437 tab_write(file, "}\n") # End of mesh block
438 else:
439 facesMaterials = [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
440 if me_materials:
441 new_me_faces_mat_idx = (f for f in me_faces if f.material_index not in
442 facesMaterials)
443 for f in new_me_faces_mat_idx:
444 facesMaterials.append(f.material_index)
445 # No vertex colors, so write material colors as vertex colors
447 for i, material in enumerate(me_materials):
448 if (
449 material and material.pov.material_use_nodes is False
450 ): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
451 # Multiply diffuse with SSS Color
452 if material.pov_subsurface_scattering.use:
453 diffuse_color = [
454 i * j
455 for i, j in zip(
456 material.pov_subsurface_scattering.color[:],
457 material.diffuse_color[:],
460 key = (
461 diffuse_color[0],
462 diffuse_color[1],
463 diffuse_color[2],
465 ) # i == f.mat
466 vertCols[key] = [-1]
467 else:
468 diffuse_color = material.diffuse_color[:]
469 key = (
470 diffuse_color[0],
471 diffuse_color[1],
472 diffuse_color[2],
474 ) # i == f.mat
475 vertCols[key] = [-1]
477 idx = 0
478 texturing.local_material_names = []
479 for col, index in vertCols.items():
480 # if me_materials:
481 mater = me_materials[col[3]]
482 if me_materials is not None:
483 texturing.write_texture_influence(
484 file,
485 mater,
486 material_names_dictionary,
487 image_format,
488 img_map,
489 img_map_transforms,
490 tab_write,
491 comments,
492 col,
493 preview_dir,
494 unpacked_images,
496 # ------------------------------------------------
497 index[0] = idx
498 idx += 1
500 # Vert Colors
501 tab_write(file, "texture_list {\n")
502 # In case there's is no material slot, give at least one texture
503 # (an empty one so it uses pov default)
504 if len(vertCols) != 0:
505 tab_write(
506 file, "%s" % (len(vertCols))
507 ) # vert count
508 else:
509 tab_write(file, "1")
510 # below "material" alias, added check obj.active_material
511 # to avoid variable referenced before assignment error
512 try:
513 material = ob.active_material
514 except IndexError:
515 # when no material slot exists,
516 material = None
518 # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
519 if (
520 material
521 and ob.active_material is not None
522 and not material.pov.material_use_nodes
523 and not material.use_nodes
525 if material.pov.replacement_text != "":
526 file.write("\n")
527 file.write(" texture{%s}\n" % material.pov.replacement_text)
529 else:
530 # Loop through declared materials list
531 # global local_material_names
532 for cMN in texturing.local_material_names:
533 if material != "Default":
534 file.write("\n texture{MAT_%s}\n" % cMN)
535 # use string_strip_hyphen(material_names_dictionary[material]))
536 # or Something like that to clean up the above?
537 elif material and material.pov.material_use_nodes:
538 for index in facesMaterials:
539 faceMaterial = string_strip_hyphen(
540 bpy.path.clean_name(me_materials[index].name)
542 file.write("\n texture{%s}\n" % faceMaterial)
543 # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
544 elif vertCols:
545 for cMN in vertCols: # or in texturing.local_material_names:
546 # if possible write only one, though
547 file.write(" texture{}\n")
548 else:
549 file.write(" texture{}\n")
550 tab_write(file, "}\n")
552 # Face indices
553 tab_write(file, "face_indices {\n")
554 tab_write(file, "%d" % (len(me_faces))) # faces count
555 tab_str = tab * tab_level
557 for fi, f in enumerate(me_faces):
558 fv = faces_verts[fi]
559 material_index = f.material_index
561 if vcol_layer:
562 cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
564 if (
565 not me_materials or me_materials[material_index] is None
566 ): # No materials
567 if linebreaksinlists:
568 file.write(",\n")
569 # vert count
570 file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
571 else:
572 file.write(", ")
573 file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
574 else:
575 material = me_materials[material_index]
576 ci1 = ci2 = ci3 = f.material_index
577 if me.vertex_colors: # and material.pov.use_vertex_color_paint:
578 # Color per vertex - vertex color
580 col1 = cols[0]
581 col2 = cols[1]
582 col3 = cols[2]
584 ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
585 ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
586 ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
587 elif material.pov.material_use_nodes:
588 ci1 = ci2 = ci3 = 0
589 else:
590 # Color per material - flat material color
591 if material.pov_subsurface_scattering.use:
592 diffuse_color = [
593 i * j
594 for i, j in zip(
595 material.pov_subsurface_scattering.color[:],
596 material.diffuse_color[:],
599 else:
600 diffuse_color = material.diffuse_color[:]
601 ci1 = ci2 = ci3 = vertCols[
602 diffuse_color[0],
603 diffuse_color[1],
604 diffuse_color[2],
605 f.material_index,
606 ][0]
608 if linebreaksinlists:
609 file.write(",\n")
610 file.write(
611 tab_str
612 + "<%d,%d,%d>, %d,%d,%d"
613 % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
614 ) # vert count
615 else:
616 file.write(", ")
617 file.write(
618 "<%d,%d,%d>, %d,%d,%d"
619 % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
620 ) # vert count
622 file.write("\n")
623 tab_write(file, "}\n")
625 # normal_indices indices
626 tab_write(file, "normal_indices {\n")
627 tab_write(file, "%d" % (len(me_faces))) # faces count
628 tab_str = tab * tab_level
629 for fi, fv in enumerate(faces_verts):
630 if me_faces[fi].use_smooth:
631 if linebreaksinlists:
632 file.write(",\n")
633 file.write(
634 tab_str
635 + "<%d,%d,%d>"
637 uniqueNormals[verts_normals[fv[0]]][0],
638 uniqueNormals[verts_normals[fv[1]]][0],
639 uniqueNormals[verts_normals[fv[2]]][0],
641 ) # vert count
642 else:
643 file.write(", ")
644 file.write(
645 "<%d,%d,%d>"
647 uniqueNormals[verts_normals[fv[0]]][0],
648 uniqueNormals[verts_normals[fv[1]]][0],
649 uniqueNormals[verts_normals[fv[2]]][0],
651 ) # vert count
652 else:
653 idx = uniqueNormals[faces_normals[fi]][0]
654 if linebreaksinlists:
655 file.write(",\n")
656 file.write(
657 tab_str + "<%d,%d,%d>" % (idx, idx, idx)
658 ) # vertcount
659 else:
660 file.write(", ")
661 file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
663 file.write("\n")
664 tab_write(file, "}\n")
666 if uv_layer:
667 tab_write(file, "uv_indices {\n")
668 tab_write(file, "%d" % (len(me_faces))) # faces count
669 tab_str = tab * tab_level
670 for f in me_faces:
671 uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
673 if linebreaksinlists:
674 file.write(",\n")
675 file.write(
676 tab_str
677 + "<%d,%d,%d>"
679 uniqueUVs[uvs[0]][0],
680 uniqueUVs[uvs[1]][0],
681 uniqueUVs[uvs[2]][0],
684 else:
685 file.write(", ")
686 file.write(
687 "<%d,%d,%d>"
689 uniqueUVs[uvs[0]][0],
690 uniqueUVs[uvs[1]][0],
691 uniqueUVs[uvs[2]][0],
695 file.write("\n")
696 tab_write(file, "}\n")
698 # XXX BOOLEAN
699 write_object_csg_inside_vector(ob, file)
700 if me.materials:
701 try:
702 material = me.materials[0] # dodgy
703 write_object_material_interior(file, material, ob, tab_write)
704 except IndexError:
705 print(me)
707 # POV object modifiers such as
708 # hollow / sturm / double_illuminate etc.
709 write_object_modifiers(ob, file)
711 # Importance for radiosity sampling added here:
712 tab_write(file, "radiosity { \n")
713 tab_write(file, "importance %3g \n" % importance)
714 tab_write(file, "}\n")
716 tab_write(file, "}\n") # End of mesh block
718 ob_eval.to_mesh_clear()
719 return True