Fix T104270: Error in materials_utils "unregister" function
[blender-addons.git] / render_povray / model_poly_topology.py
blobb4d200ecfe0d65f2ec28b327681b50358352cd39
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """Translate to POV the control point compound geometries.
5 Here polygon meshes as POV mesh2 objects.
6 """
8 import bpy
9 from . import texturing
10 from .scenography import image_format, img_map, img_map_transforms
11 from .shading import write_object_material_interior
12 from .model_primitives import write_object_modifiers
14 def write_object_csg_inside_vector(ob, file):
15 """Write inside vector for use by pov CSG, only once per object using boolean"""
16 has_csg_inside_vector = False
17 for modif in ob.modifiers:
18 if not has_csg_inside_vector and modif.type == "BOOLEAN" and ob.pov.boolean_mod == "POV":
19 file.write(
20 "\tinside_vector <%.6g, %.6g, %.6g>\n"
21 % (
22 ob.pov.inside_vector[0],
23 ob.pov.inside_vector[1],
24 ob.pov.inside_vector[2],
27 has_csg_inside_vector = True
29 def export_mesh(file,
30 ob,
31 povdataname,
32 material_names_dictionary,
33 unpacked_images,
34 tab_level,
35 tab_write,
36 linebreaksinlists):
37 from .render import (
38 string_strip_hyphen,
39 tab,
40 comments,
41 preview_dir,
44 ob_eval = ob # not sure this is needed in case to_mesh_clear could damage obj ?
45 importance = ob.pov.importance_value
47 try:
48 me = ob_eval.to_mesh()
50 # Here identify the exception for mesh object with no data: Runtime-Error ?
51 # So we can write something for the dataname or maybe treated "if not me" below
52 except BaseException as e:
53 print(e.__doc__)
54 print("An exception occurred: {}".format(e))
55 # also happens when curves can't be made into meshes because of no-data
56 return False # To continue object loop
57 if me:
58 me.calc_loop_triangles()
59 me_materials = me.materials
60 me_faces = me.loop_triangles[:]
61 # --- numpytest
62 # me_looptris = me.loops
64 # Below otypes = ['int32'] is a 32-bit signed integer number numpy datatype
65 # get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
66 # faces_verts_idx = get_v_index(me_looptris)
68 # if len(me_faces)==0:
69 # tab_write(file, "\n//dummy sphere to represent empty mesh location\n")
70 # 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)
72 if not me or not me_faces:
73 tab_write(file, "\n//dummy sphere to represent empty mesh location\n")
74 tab_write(
75 file,
76 "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
77 % povdataname,
79 return False # To continue object loop
81 uv_layers = me.uv_layers
82 if len(uv_layers) > 0:
83 if me.uv_layers.active and uv_layers.active.data:
84 uv_layer = uv_layers.active.data
85 else:
86 uv_layer = None
88 try:
89 # vcol_layer = me.vertex_colors.active.data
90 vcol_layer = me.vertex_colors.active.data
91 except AttributeError:
92 vcol_layer = None
94 faces_verts = [f.vertices[:] for f in me_faces]
95 faces_normals = [f.normal[:] for f in me_faces]
96 verts_normals = [v.normal[:] for v in me.vertices]
98 # Use named declaration to allow reference e.g. for baking. MR
99 file.write("\n")
100 tab_write(file, "#declare %s =\n" % povdataname)
101 tab_write(file, "mesh2 {\n")
102 tab_write(file, "vertex_vectors {\n")
103 tab_write(file, "%d" % len(me.vertices)) # vert count
105 tab_str = tab * tab_level
106 for v in me.vertices:
107 if linebreaksinlists:
108 file.write(",\n")
109 file.write(tab_str + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
110 else:
111 file.write(", ")
112 file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
113 # tab_write(file, "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
114 file.write("\n")
115 tab_write(file, "}\n")
117 # Build unique Normal list
118 uniqueNormals = {}
119 for fi, f in enumerate(me_faces):
120 fv = faces_verts[fi]
121 # [-1] is a dummy index, use a list so we can modify in place
122 if f.use_smooth: # Use vertex normals
123 for v in fv:
124 key = verts_normals[v]
125 uniqueNormals[key] = [-1]
126 else: # Use face normal
127 key = faces_normals[fi]
128 uniqueNormals[key] = [-1]
130 tab_write(file, "normal_vectors {\n")
131 tab_write(file, "%d" % len(uniqueNormals)) # vert count
132 idx = 0
133 tab_str = tab * tab_level
134 for no, index in uniqueNormals.items():
135 if linebreaksinlists:
136 file.write(",\n")
137 file.write(tab_str + "<%.6f, %.6f, %.6f>" % no) # vert count
138 else:
139 file.write(", ")
140 file.write("<%.6f, %.6f, %.6f>" % no) # vert count
141 index[0] = idx
142 idx += 1
143 file.write("\n")
144 tab_write(file, "}\n")
145 # Vertex colors
146 vertCols = {} # Use for material colors also.
148 if uv_layer:
149 # Generate unique UV's
150 uniqueUVs = {}
151 # n = 0
152 for f in me_faces: # me.faces in 2.7
153 uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
155 for uv in uvs:
156 uniqueUVs[uv[:]] = [-1]
158 tab_write(file, "uv_vectors {\n")
159 # print unique_uvs
160 tab_write(file, "%d" % len(uniqueUVs)) # vert count
161 idx = 0
162 tab_str = tab * tab_level
163 for uv, index in uniqueUVs.items():
164 if linebreaksinlists:
165 file.write(",\n")
166 file.write(tab_str + "<%.6f, %.6f>" % uv)
167 else:
168 file.write(", ")
169 file.write("<%.6f, %.6f>" % uv)
170 index[0] = idx
171 idx += 1
173 else:
174 # Just add 1 dummy vector, no real UV's
175 tab_write(file, '1') # vert count
176 file.write(',\n\t\t<0.0, 0.0>')
178 file.write("\n")
179 tab_write(file, "}\n")
180 if me.vertex_colors:
181 # Write down vertex colors as a texture for each vertex
182 tab_write(file, "texture_list {\n")
183 tab_write(
184 file, "%d\n" % (len(me_faces) * 3)
185 ) # assumes we have only triangles
186 VcolIdx = 0
187 if comments:
188 file.write(
189 "\n //Vertex colors: one simple pigment texture per vertex\n"
191 for fi, f in enumerate(me_faces):
192 # annoying, index may be invalid
193 material_index = f.material_index
194 try:
195 material = me_materials[material_index]
196 except BaseException as e:
197 print(e.__doc__)
198 print("An exception occurred: {}".format(e))
199 material = None
200 if (
201 material
202 # and material.pov.use_vertex_color_paint
203 ): # Or maybe Always use vertex color when there is some for now
205 cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
207 for col in cols:
208 key = (
209 col[0],
210 col[1],
211 col[2],
212 material_index,
213 ) # Material index!
214 VcolIdx += 1
215 vertCols[key] = [VcolIdx]
216 if linebreaksinlists:
217 tab_write(
218 file,
219 "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
220 % (col[0], col[1], col[2]),
222 else:
223 tab_write(
224 file,
225 "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
226 % (col[0], col[1], col[2]),
228 tab_str = tab * tab_level
229 else:
230 if material:
231 # Multiply diffuse with SSS Color
232 if material.pov_subsurface_scattering.use:
233 diffuse_color = [
234 i * j
235 for i, j in zip(
236 material.pov_subsurface_scattering.color[:],
237 material.diffuse_color[:],
240 key = (
241 diffuse_color[0],
242 diffuse_color[1],
243 diffuse_color[2],
244 material_index,
246 vertCols[key] = [-1]
247 else:
248 diffuse_color = material.diffuse_color[:]
249 key = (
250 diffuse_color[0],
251 diffuse_color[1],
252 diffuse_color[2],
253 material_index,
255 vertCols[key] = [-1]
257 tab_write(file, "\n}\n")
258 # Face indices
259 tab_write(file, "\nface_indices {\n")
260 tab_write(file, "%d" % (len(me_faces))) # faces count
261 tab_str = tab * tab_level
263 for fi, f in enumerate(me_faces):
264 fv = faces_verts[fi]
265 material_index = f.material_index
267 if vcol_layer:
268 cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
270 if not me_materials or (
271 me_materials[material_index] is None
272 ): # No materials
273 if linebreaksinlists:
274 file.write(",\n")
275 # vert count
276 file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
277 else:
278 file.write(", ")
279 file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
280 else:
281 material = me_materials[material_index]
282 if me.vertex_colors: # and material.pov.use_vertex_color_paint:
283 # Color per vertex - vertex color
285 col1 = cols[0]
286 col2 = cols[1]
287 col3 = cols[2]
289 ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
290 ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
291 ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
292 else:
293 # Color per material - flat material color
294 if material.pov_subsurface_scattering.use:
295 diffuse_color = [
296 i * j
297 for i, j in zip(
298 material.pov_subsurface_scattering.color[:],
299 material.diffuse_color[:],
302 else:
303 diffuse_color = material.diffuse_color[:]
304 ci1 = ci2 = ci3 = vertCols[
305 diffuse_color[0],
306 diffuse_color[1],
307 diffuse_color[2],
308 f.material_index,
309 ][0]
310 # ci are zero based index so we'll subtract 1 from them
311 if linebreaksinlists:
312 file.write(",\n")
313 file.write(
314 tab_str
315 + "<%d,%d,%d>, %d,%d,%d"
317 fv[0],
318 fv[1],
319 fv[2],
320 ci1 - 1,
321 ci2 - 1,
322 ci3 - 1,
324 ) # vert count
325 else:
326 file.write(", ")
327 file.write(
328 "<%d,%d,%d>, %d,%d,%d"
330 fv[0],
331 fv[1],
332 fv[2],
333 ci1 - 1,
334 ci2 - 1,
335 ci3 - 1,
337 ) # vert count
339 file.write("\n")
340 tab_write(file, "}\n")
342 # normal_indices indices
343 tab_write(file, "normal_indices {\n")
344 tab_write(file, "%d" % (len(me_faces))) # faces count
345 tab_str = tab * tab_level
346 for fi, fv in enumerate(faces_verts):
348 if me_faces[fi].use_smooth:
349 if linebreaksinlists:
350 file.write(",\n")
351 file.write(
352 tab_str
353 + "<%d,%d,%d>"
355 uniqueNormals[verts_normals[fv[0]]][0],
356 uniqueNormals[verts_normals[fv[1]]][0],
357 uniqueNormals[verts_normals[fv[2]]][0],
359 ) # vert count
360 else:
361 file.write(", ")
362 file.write(
363 "<%d,%d,%d>"
365 uniqueNormals[verts_normals[fv[0]]][0],
366 uniqueNormals[verts_normals[fv[1]]][0],
367 uniqueNormals[verts_normals[fv[2]]][0],
369 ) # vert count
370 else:
371 idx = uniqueNormals[faces_normals[fi]][0]
372 if linebreaksinlists:
373 file.write(",\n")
374 file.write(
375 tab_str + "<%d,%d,%d>" % (idx, idx, idx)
376 ) # vert count
377 else:
378 file.write(", ")
379 file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
381 file.write("\n")
382 tab_write(file, "}\n")
384 if uv_layer:
385 tab_write(file, "uv_indices {\n")
386 tab_write(file, "%d" % (len(me_faces))) # faces count
387 tab_str = tab * tab_level
388 for f in me_faces:
389 uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
391 if linebreaksinlists:
392 file.write(",\n")
393 file.write(
394 tab_str
395 + "<%d,%d,%d>"
397 uniqueUVs[uvs[0]][0],
398 uniqueUVs[uvs[1]][0],
399 uniqueUVs[uvs[2]][0],
402 else:
403 file.write(", ")
404 file.write(
405 "<%d,%d,%d>"
407 uniqueUVs[uvs[0]][0],
408 uniqueUVs[uvs[1]][0],
409 uniqueUVs[uvs[2]][0],
413 file.write("\n")
414 tab_write(file, "}\n")
416 # XXX BOOLEAN MODIFIER
417 write_object_csg_inside_vector(ob, file)
419 if me.materials:
420 try:
421 material = me.materials[0] # dodgy
422 write_object_material_interior(file, material, ob, tab_write)
423 except IndexError:
424 print(me)
426 # POV object modifiers such as
427 # hollow / sturm / double_illuminate etc.
428 write_object_modifiers(ob, file)
430 # Importance for radiosity sampling added here:
431 tab_write(file, "radiosity { \n")
432 tab_write(file, "importance %3g \n" % importance)
433 tab_write(file, "}\n")
435 tab_write(file, "}\n") # End of mesh block
436 else:
437 facesMaterials = [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
438 if me_materials:
439 new_me_faces_mat_idx = (f for f in me_faces if f.material_index not in
440 facesMaterials)
441 for f in new_me_faces_mat_idx:
442 facesMaterials.append(f.material_index)
443 # No vertex colors, so write material colors as vertex colors
445 for i, material in enumerate(me_materials):
446 if (
447 material and material.pov.material_use_nodes is False
448 ): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
449 # Multiply diffuse with SSS Color
450 if material.pov_subsurface_scattering.use:
451 diffuse_color = [
452 i * j
453 for i, j in zip(
454 material.pov_subsurface_scattering.color[:],
455 material.diffuse_color[:],
458 key = (
459 diffuse_color[0],
460 diffuse_color[1],
461 diffuse_color[2],
463 ) # i == f.mat
464 vertCols[key] = [-1]
465 else:
466 diffuse_color = material.diffuse_color[:]
467 key = (
468 diffuse_color[0],
469 diffuse_color[1],
470 diffuse_color[2],
472 ) # i == f.mat
473 vertCols[key] = [-1]
475 idx = 0
476 texturing.local_material_names = []
477 for col, index in vertCols.items():
478 # if me_materials:
479 mater = me_materials[col[3]]
480 if me_materials is not None:
481 texturing.write_texture_influence(
482 file,
483 mater,
484 material_names_dictionary,
485 image_format,
486 img_map,
487 img_map_transforms,
488 tab_write,
489 comments,
490 col,
491 preview_dir,
492 unpacked_images,
494 # ------------------------------------------------
495 index[0] = idx
496 idx += 1
498 # Vert Colors
499 tab_write(file, "texture_list {\n")
500 # In case there's is no material slot, give at least one texture
501 # (an empty one so it uses pov default)
502 if len(vertCols) != 0:
503 tab_write(
504 file, "%s" % (len(vertCols))
505 ) # vert count
506 else:
507 tab_write(file, "1")
508 # below "material" alias, added check obj.active_material
509 # to avoid variable referenced before assignment error
510 try:
511 material = ob.active_material
512 except IndexError:
513 # when no material slot exists,
514 material = None
516 # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
517 if (
518 material
519 and ob.active_material is not None
520 and not material.pov.material_use_nodes
521 and not material.use_nodes
523 if material.pov.replacement_text != "":
524 file.write("\n")
525 file.write(" texture{%s}\n" % material.pov.replacement_text)
527 else:
528 # Loop through declared materials list
529 # global local_material_names
530 for cMN in texturing.local_material_names:
531 if material != "Default":
532 file.write("\n texture{MAT_%s}\n" % cMN)
533 # use string_strip_hyphen(material_names_dictionary[material]))
534 # or Something like that to clean up the above?
535 elif material and material.pov.material_use_nodes:
536 for index in facesMaterials:
537 faceMaterial = string_strip_hyphen(
538 bpy.path.clean_name(me_materials[index].name)
540 file.write("\n texture{%s}\n" % faceMaterial)
541 # END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
542 elif vertCols:
543 for cMN in vertCols: # or in texturing.local_material_names:
544 # if possible write only one, though
545 file.write(" texture{}\n")
546 else:
547 file.write(" texture{}\n")
548 tab_write(file, "}\n")
550 # Face indices
551 tab_write(file, "face_indices {\n")
552 tab_write(file, "%d" % (len(me_faces))) # faces count
553 tab_str = tab * tab_level
555 for fi, f in enumerate(me_faces):
556 fv = faces_verts[fi]
557 material_index = f.material_index
559 if vcol_layer:
560 cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
562 if (
563 not me_materials or me_materials[material_index] is None
564 ): # No materials
565 if linebreaksinlists:
566 file.write(",\n")
567 # vert count
568 file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
569 else:
570 file.write(", ")
571 file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
572 else:
573 material = me_materials[material_index]
574 ci1 = ci2 = ci3 = f.material_index
575 if me.vertex_colors: # and material.pov.use_vertex_color_paint:
576 # Color per vertex - vertex color
578 col1 = cols[0]
579 col2 = cols[1]
580 col3 = cols[2]
582 ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
583 ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
584 ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
585 elif material.pov.material_use_nodes:
586 ci1 = ci2 = ci3 = 0
587 else:
588 # Color per material - flat material color
589 if material.pov_subsurface_scattering.use:
590 diffuse_color = [
591 i * j
592 for i, j in zip(
593 material.pov_subsurface_scattering.color[:],
594 material.diffuse_color[:],
597 else:
598 diffuse_color = material.diffuse_color[:]
599 ci1 = ci2 = ci3 = vertCols[
600 diffuse_color[0],
601 diffuse_color[1],
602 diffuse_color[2],
603 f.material_index,
604 ][0]
606 if linebreaksinlists:
607 file.write(",\n")
608 file.write(
609 tab_str
610 + "<%d,%d,%d>, %d,%d,%d"
611 % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
612 ) # vert count
613 else:
614 file.write(", ")
615 file.write(
616 "<%d,%d,%d>, %d,%d,%d"
617 % (fv[0], fv[1], fv[2], ci1, ci2, ci3)
618 ) # vert count
620 file.write("\n")
621 tab_write(file, "}\n")
623 # normal_indices indices
624 tab_write(file, "normal_indices {\n")
625 tab_write(file, "%d" % (len(me_faces))) # faces count
626 tab_str = tab * tab_level
627 for fi, fv in enumerate(faces_verts):
628 if me_faces[fi].use_smooth:
629 if linebreaksinlists:
630 file.write(",\n")
631 file.write(
632 tab_str
633 + "<%d,%d,%d>"
635 uniqueNormals[verts_normals[fv[0]]][0],
636 uniqueNormals[verts_normals[fv[1]]][0],
637 uniqueNormals[verts_normals[fv[2]]][0],
639 ) # vert count
640 else:
641 file.write(", ")
642 file.write(
643 "<%d,%d,%d>"
645 uniqueNormals[verts_normals[fv[0]]][0],
646 uniqueNormals[verts_normals[fv[1]]][0],
647 uniqueNormals[verts_normals[fv[2]]][0],
649 ) # vert count
650 else:
651 idx = uniqueNormals[faces_normals[fi]][0]
652 if linebreaksinlists:
653 file.write(",\n")
654 file.write(
655 tab_str + "<%d,%d,%d>" % (idx, idx, idx)
656 ) # vertcount
657 else:
658 file.write(", ")
659 file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
661 file.write("\n")
662 tab_write(file, "}\n")
664 if uv_layer:
665 tab_write(file, "uv_indices {\n")
666 tab_write(file, "%d" % (len(me_faces))) # faces count
667 tab_str = tab * tab_level
668 for f in me_faces:
669 uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
671 if linebreaksinlists:
672 file.write(",\n")
673 file.write(
674 tab_str
675 + "<%d,%d,%d>"
677 uniqueUVs[uvs[0]][0],
678 uniqueUVs[uvs[1]][0],
679 uniqueUVs[uvs[2]][0],
682 else:
683 file.write(", ")
684 file.write(
685 "<%d,%d,%d>"
687 uniqueUVs[uvs[0]][0],
688 uniqueUVs[uvs[1]][0],
689 uniqueUVs[uvs[2]][0],
693 file.write("\n")
694 tab_write(file, "}\n")
696 # XXX BOOLEAN
697 write_object_csg_inside_vector(ob, file)
698 if me.materials:
699 try:
700 material = me.materials[0] # dodgy
701 write_object_material_interior(file, material, ob, tab_write)
702 except IndexError:
703 print(me)
705 # POV object modifiers such as
706 # hollow / sturm / double_illuminate etc.
707 write_object_modifiers(ob, file)
709 # Importance for radiosity sampling added here:
710 tab_write(file, "radiosity { \n")
711 tab_write(file, "importance %3g \n" % importance)
712 tab_write(file, "}\n")
714 tab_write(file, "}\n") # End of mesh block
716 ob_eval.to_mesh_clear()
717 return True