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.
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":
20 "\tinside_vector <%.6g, %.6g, %.6g>\n"
22 ob
.pov
.inside_vector
[0],
23 ob
.pov
.inside_vector
[1],
24 ob
.pov
.inside_vector
[2],
27 has_csg_inside_vector
= True
32 material_names_dictionary
,
44 ob_eval
= ob
# not sure this is needed in case to_mesh_clear could damage obj ?
45 importance
= ob
.pov
.importance_value
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
:
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
58 me
.calc_loop_triangles()
59 me_materials
= me
.materials
60 me_faces
= me
.loop_triangles
[:]
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")
76 "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
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
89 # vcol_layer = me.vertex_colors.active.data
90 vcol_layer
= me
.vertex_colors
.active
.data
91 except AttributeError:
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
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
:
109 file.write(tab_str
+ "<%.6f, %.6f, %.6f>" % v
.co
[:]) # vert count
112 file.write("<%.6f, %.6f, %.6f>" % v
.co
[:]) # vert count
113 # tab_write(file, "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
115 tab_write(file, "}\n")
117 # Build unique Normal list
119 for fi
, f
in enumerate(me_faces
):
121 # [-1] is a dummy index, use a list so we can modify in place
122 if f
.use_smooth
: # Use vertex normals
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
133 tab_str
= tab
* tab_level
134 for no
, index
in uniqueNormals
.items():
135 if linebreaksinlists
:
137 file.write(tab_str
+ "<%.6f, %.6f, %.6f>" % no
) # vert count
140 file.write("<%.6f, %.6f, %.6f>" % no
) # vert count
144 tab_write(file, "}\n")
146 vertCols
= {} # Use for material colors also.
149 # Generate unique UV's
152 for f
in me_faces
: # me.faces in 2.7
153 uvs
= [uv_layer
[loop_index
].uv
[:] for loop_index
in f
.loops
]
156 uniqueUVs
[uv
[:]] = [-1]
158 tab_write(file, "uv_vectors {\n")
160 tab_write(file, "%d" % len(uniqueUVs
)) # vert count
162 tab_str
= tab
* tab_level
163 for uv
, index
in uniqueUVs
.items():
164 if linebreaksinlists
:
166 file.write(tab_str
+ "<%.6f, %.6f>" % uv
)
169 file.write("<%.6f, %.6f>" % uv
)
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>')
179 tab_write(file, "}\n")
181 # Write down vertex colors as a texture for each vertex
182 tab_write(file, "texture_list {\n")
184 file, "%d\n" % (len(me_faces
) * 3)
185 ) # assumes we have only triangles
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
195 material
= me_materials
[material_index
]
196 except BaseException
as e
:
198 print("An exception occurred: {}".format(e
))
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
]
215 vertCols
[key
] = [VcolIdx
]
216 if linebreaksinlists
:
219 "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
220 % (col
[0], col
[1], col
[2]),
225 "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
226 % (col
[0], col
[1], col
[2]),
228 tab_str
= tab
* tab_level
231 # Multiply diffuse with SSS Color
232 if material
.pov_subsurface_scattering
.use
:
236 material
.pov_subsurface_scattering
.color
[:],
237 material
.diffuse_color
[:],
248 diffuse_color
= material
.diffuse_color
[:]
257 tab_write(file, "\n}\n")
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
):
265 material_index
= f
.material_index
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
273 if linebreaksinlists
:
276 file.write(tab_str
+ "<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2]))
279 file.write("<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2])) # vert count
281 material
= me_materials
[material_index
]
282 if me
.vertex_colors
: # and material.pov.use_vertex_color_paint:
283 # Color per vertex - vertex color
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]
293 # Color per material - flat material color
294 if material
.pov_subsurface_scattering
.use
:
298 material
.pov_subsurface_scattering
.color
[:],
299 material
.diffuse_color
[:],
303 diffuse_color
= material
.diffuse_color
[:]
304 ci1
= ci2
= ci3
= vertCols
[
310 # ci are zero based index so we'll subtract 1 from them
311 if linebreaksinlists
:
315 + "<%d,%d,%d>, %d,%d,%d"
328 "<%d,%d,%d>, %d,%d,%d"
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
:
355 uniqueNormals
[verts_normals
[fv
[0]]][0],
356 uniqueNormals
[verts_normals
[fv
[1]]][0],
357 uniqueNormals
[verts_normals
[fv
[2]]][0],
365 uniqueNormals
[verts_normals
[fv
[0]]][0],
366 uniqueNormals
[verts_normals
[fv
[1]]][0],
367 uniqueNormals
[verts_normals
[fv
[2]]][0],
371 idx
= uniqueNormals
[faces_normals
[fi
]][0]
372 if linebreaksinlists
:
375 tab_str
+ "<%d,%d,%d>" % (idx
, idx
, idx
)
379 file.write("<%d,%d,%d>" % (idx
, idx
, idx
)) # vert count
382 tab_write(file, "}\n")
385 tab_write(file, "uv_indices {\n")
386 tab_write(file, "%d" % (len(me_faces
))) # faces count
387 tab_str
= tab
* tab_level
389 uvs
= [uv_layer
[loop_index
].uv
[:] for loop_index
in f
.loops
]
391 if linebreaksinlists
:
397 uniqueUVs
[uvs
[0]][0],
398 uniqueUVs
[uvs
[1]][0],
399 uniqueUVs
[uvs
[2]][0],
407 uniqueUVs
[uvs
[0]][0],
408 uniqueUVs
[uvs
[1]][0],
409 uniqueUVs
[uvs
[2]][0],
414 tab_write(file, "}\n")
416 # XXX BOOLEAN MODIFIER
417 write_object_csg_inside_vector(ob
, file)
421 material
= me
.materials
[0] # dodgy
422 write_object_material_interior(file, material
, ob
, tab_write
)
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
437 facesMaterials
= [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
439 new_me_faces_mat_idx
= (f
for f
in me_faces
if f
.material_index
not in
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
):
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
:
454 material
.pov_subsurface_scattering
.color
[:],
455 material
.diffuse_color
[:],
466 diffuse_color
= material
.diffuse_color
[:]
476 texturing
.local_material_names
= []
477 for col
, index
in vertCols
.items():
479 mater
= me_materials
[col
[3]]
480 if me_materials
is not None:
481 texturing
.write_texture_influence(
484 material_names_dictionary
,
494 # ------------------------------------------------
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:
504 file, "%s" % (len(vertCols
))
508 # below "material" alias, added check obj.active_material
509 # to avoid variable referenced before assignment error
511 material
= ob
.active_material
513 # when no material slot exists,
516 # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
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
!= "":
525 file.write(" texture{%s}\n" % material
.pov
.replacement_text
)
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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
543 for cMN
in vertCols
: # or in texturing.local_material_names:
544 # if possible write only one, though
545 file.write(" texture{}\n")
547 file.write(" texture{}\n")
548 tab_write(file, "}\n")
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
):
557 material_index
= f
.material_index
560 cols
= [vcol_layer
[loop_index
].color
[:] for loop_index
in f
.loops
]
563 not me_materials
or me_materials
[material_index
] is None
565 if linebreaksinlists
:
568 file.write(tab_str
+ "<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2]))
571 file.write("<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2])) # vert count
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
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
:
588 # Color per material - flat material color
589 if material
.pov_subsurface_scattering
.use
:
593 material
.pov_subsurface_scattering
.color
[:],
594 material
.diffuse_color
[:],
598 diffuse_color
= material
.diffuse_color
[:]
599 ci1
= ci2
= ci3
= vertCols
[
606 if linebreaksinlists
:
610 + "<%d,%d,%d>, %d,%d,%d"
611 % (fv
[0], fv
[1], fv
[2], ci1
, ci2
, ci3
)
616 "<%d,%d,%d>, %d,%d,%d"
617 % (fv
[0], fv
[1], fv
[2], ci1
, ci2
, ci3
)
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
:
635 uniqueNormals
[verts_normals
[fv
[0]]][0],
636 uniqueNormals
[verts_normals
[fv
[1]]][0],
637 uniqueNormals
[verts_normals
[fv
[2]]][0],
645 uniqueNormals
[verts_normals
[fv
[0]]][0],
646 uniqueNormals
[verts_normals
[fv
[1]]][0],
647 uniqueNormals
[verts_normals
[fv
[2]]][0],
651 idx
= uniqueNormals
[faces_normals
[fi
]][0]
652 if linebreaksinlists
:
655 tab_str
+ "<%d,%d,%d>" % (idx
, idx
, idx
)
659 file.write("<%d,%d,%d>" % (idx
, idx
, idx
)) # vert count
662 tab_write(file, "}\n")
665 tab_write(file, "uv_indices {\n")
666 tab_write(file, "%d" % (len(me_faces
))) # faces count
667 tab_str
= tab
* tab_level
669 uvs
= [uv_layer
[loop_index
].uv
[:] for loop_index
in f
.loops
]
671 if linebreaksinlists
:
677 uniqueUVs
[uvs
[0]][0],
678 uniqueUVs
[uvs
[1]][0],
679 uniqueUVs
[uvs
[2]][0],
687 uniqueUVs
[uvs
[0]][0],
688 uniqueUVs
[uvs
[1]][0],
689 uniqueUVs
[uvs
[2]][0],
694 tab_write(file, "}\n")
697 write_object_csg_inside_vector(ob
, file)
700 material
= me
.materials
[0] # dodgy
701 write_object_material_interior(file, material
, ob
, tab_write
)
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()