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.
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":
22 "\tinside_vector <%.6g, %.6g, %.6g>\n"
24 ob
.pov
.inside_vector
[0],
25 ob
.pov
.inside_vector
[1],
26 ob
.pov
.inside_vector
[2],
29 has_csg_inside_vector
= True
34 material_names_dictionary
,
46 ob_eval
= ob
# not sure this is needed in case to_mesh_clear could damage obj ?
47 importance
= ob
.pov
.importance_value
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
:
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
60 me
.calc_loop_triangles()
61 me_materials
= me
.materials
62 me_faces
= me
.loop_triangles
[:]
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")
78 "#declare %s =sphere {<0, 0, 0>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n"
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
91 # vcol_layer = me.vertex_colors.active.data
92 vcol_layer
= me
.vertex_colors
.active
.data
93 except AttributeError:
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
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
:
111 file.write(tab_str
+ "<%.6f, %.6f, %.6f>" % v
.co
[:]) # vert count
114 file.write("<%.6f, %.6f, %.6f>" % v
.co
[:]) # vert count
115 # tab_write(file, "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
117 tab_write(file, "}\n")
119 # Build unique Normal list
121 for fi
, f
in enumerate(me_faces
):
123 # [-1] is a dummy index, use a list so we can modify in place
124 if f
.use_smooth
: # Use vertex normals
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
135 tab_str
= tab
* tab_level
136 for no
, index
in uniqueNormals
.items():
137 if linebreaksinlists
:
139 file.write(tab_str
+ "<%.6f, %.6f, %.6f>" % no
) # vert count
142 file.write("<%.6f, %.6f, %.6f>" % no
) # vert count
146 tab_write(file, "}\n")
148 vertCols
= {} # Use for material colors also.
151 # Generate unique UV's
154 for f
in me_faces
: # me.faces in 2.7
155 uvs
= [uv_layer
[loop_index
].uv
[:] for loop_index
in f
.loops
]
158 uniqueUVs
[uv
[:]] = [-1]
160 tab_write(file, "uv_vectors {\n")
162 tab_write(file, "%d" % len(uniqueUVs
)) # vert count
164 tab_str
= tab
* tab_level
165 for uv
, index
in uniqueUVs
.items():
166 if linebreaksinlists
:
168 file.write(tab_str
+ "<%.6f, %.6f>" % uv
)
171 file.write("<%.6f, %.6f>" % uv
)
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>')
181 tab_write(file, "}\n")
183 # Write down vertex colors as a texture for each vertex
184 tab_write(file, "texture_list {\n")
186 file, "%d\n" % (len(me_faces
) * 3)
187 ) # assumes we have only triangles
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
197 material
= me_materials
[material_index
]
198 except BaseException
as e
:
200 print("An exception occurred: {}".format(e
))
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
]
217 vertCols
[key
] = [VcolIdx
]
218 if linebreaksinlists
:
221 "texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
222 % (col
[0], col
[1], col
[2]),
227 "texture {pigment{ color srgb <%6f,%6f,%6f> }}"
228 % (col
[0], col
[1], col
[2]),
230 tab_str
= tab
* tab_level
233 # Multiply diffuse with SSS Color
234 if material
.pov_subsurface_scattering
.use
:
238 material
.pov_subsurface_scattering
.color
[:],
239 material
.diffuse_color
[:],
250 diffuse_color
= material
.diffuse_color
[:]
259 tab_write(file, "\n}\n")
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
):
267 material_index
= f
.material_index
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
275 if linebreaksinlists
:
278 file.write(tab_str
+ "<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2]))
281 file.write("<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2])) # vert count
283 material
= me_materials
[material_index
]
284 if me
.vertex_colors
: # and material.pov.use_vertex_color_paint:
285 # Color per vertex - vertex color
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]
295 # Color per material - flat material color
296 if material
.pov_subsurface_scattering
.use
:
300 material
.pov_subsurface_scattering
.color
[:],
301 material
.diffuse_color
[:],
305 diffuse_color
= material
.diffuse_color
[:]
306 ci1
= ci2
= ci3
= vertCols
[
312 # ci are zero based index so we'll subtract 1 from them
313 if linebreaksinlists
:
317 + "<%d,%d,%d>, %d,%d,%d"
330 "<%d,%d,%d>, %d,%d,%d"
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
:
357 uniqueNormals
[verts_normals
[fv
[0]]][0],
358 uniqueNormals
[verts_normals
[fv
[1]]][0],
359 uniqueNormals
[verts_normals
[fv
[2]]][0],
367 uniqueNormals
[verts_normals
[fv
[0]]][0],
368 uniqueNormals
[verts_normals
[fv
[1]]][0],
369 uniqueNormals
[verts_normals
[fv
[2]]][0],
373 idx
= uniqueNormals
[faces_normals
[fi
]][0]
374 if linebreaksinlists
:
377 tab_str
+ "<%d,%d,%d>" % (idx
, idx
, idx
)
381 file.write("<%d,%d,%d>" % (idx
, idx
, idx
)) # vert count
384 tab_write(file, "}\n")
387 tab_write(file, "uv_indices {\n")
388 tab_write(file, "%d" % (len(me_faces
))) # faces count
389 tab_str
= tab
* tab_level
391 uvs
= [uv_layer
[loop_index
].uv
[:] for loop_index
in f
.loops
]
393 if linebreaksinlists
:
399 uniqueUVs
[uvs
[0]][0],
400 uniqueUVs
[uvs
[1]][0],
401 uniqueUVs
[uvs
[2]][0],
409 uniqueUVs
[uvs
[0]][0],
410 uniqueUVs
[uvs
[1]][0],
411 uniqueUVs
[uvs
[2]][0],
416 tab_write(file, "}\n")
418 # XXX BOOLEAN MODIFIER
419 write_object_csg_inside_vector(ob
, file)
423 material
= me
.materials
[0] # dodgy
424 write_object_material_interior(file, material
, ob
, tab_write
)
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
439 facesMaterials
= [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
441 new_me_faces_mat_idx
= (f
for f
in me_faces
if f
.material_index
not in
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
):
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
:
456 material
.pov_subsurface_scattering
.color
[:],
457 material
.diffuse_color
[:],
468 diffuse_color
= material
.diffuse_color
[:]
478 texturing
.local_material_names
= []
479 for col
, index
in vertCols
.items():
481 mater
= me_materials
[col
[3]]
482 if me_materials
is not None:
483 texturing
.write_texture_influence(
486 material_names_dictionary
,
496 # ------------------------------------------------
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:
506 file, "%s" % (len(vertCols
))
510 # below "material" alias, added check obj.active_material
511 # to avoid variable referenced before assignment error
513 material
= ob
.active_material
515 # when no material slot exists,
518 # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
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
!= "":
527 file.write(" texture{%s}\n" % material
.pov
.replacement_text
)
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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
545 for cMN
in vertCols
: # or in texturing.local_material_names:
546 # if possible write only one, though
547 file.write(" texture{}\n")
549 file.write(" texture{}\n")
550 tab_write(file, "}\n")
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
):
559 material_index
= f
.material_index
562 cols
= [vcol_layer
[loop_index
].color
[:] for loop_index
in f
.loops
]
565 not me_materials
or me_materials
[material_index
] is None
567 if linebreaksinlists
:
570 file.write(tab_str
+ "<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2]))
573 file.write("<%d,%d,%d>" % (fv
[0], fv
[1], fv
[2])) # vert count
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
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
:
590 # Color per material - flat material color
591 if material
.pov_subsurface_scattering
.use
:
595 material
.pov_subsurface_scattering
.color
[:],
596 material
.diffuse_color
[:],
600 diffuse_color
= material
.diffuse_color
[:]
601 ci1
= ci2
= ci3
= vertCols
[
608 if linebreaksinlists
:
612 + "<%d,%d,%d>, %d,%d,%d"
613 % (fv
[0], fv
[1], fv
[2], ci1
, ci2
, ci3
)
618 "<%d,%d,%d>, %d,%d,%d"
619 % (fv
[0], fv
[1], fv
[2], ci1
, ci2
, ci3
)
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
:
637 uniqueNormals
[verts_normals
[fv
[0]]][0],
638 uniqueNormals
[verts_normals
[fv
[1]]][0],
639 uniqueNormals
[verts_normals
[fv
[2]]][0],
647 uniqueNormals
[verts_normals
[fv
[0]]][0],
648 uniqueNormals
[verts_normals
[fv
[1]]][0],
649 uniqueNormals
[verts_normals
[fv
[2]]][0],
653 idx
= uniqueNormals
[faces_normals
[fi
]][0]
654 if linebreaksinlists
:
657 tab_str
+ "<%d,%d,%d>" % (idx
, idx
, idx
)
661 file.write("<%d,%d,%d>" % (idx
, idx
, idx
)) # vert count
664 tab_write(file, "}\n")
667 tab_write(file, "uv_indices {\n")
668 tab_write(file, "%d" % (len(me_faces
))) # faces count
669 tab_str
= tab
* tab_level
671 uvs
= [uv_layer
[loop_index
].uv
[:] for loop_index
in f
.loops
]
673 if linebreaksinlists
:
679 uniqueUVs
[uvs
[0]][0],
680 uniqueUVs
[uvs
[1]][0],
681 uniqueUVs
[uvs
[2]][0],
689 uniqueUVs
[uvs
[0]][0],
690 uniqueUVs
[uvs
[1]][0],
691 uniqueUVs
[uvs
[2]][0],
696 tab_write(file, "}\n")
699 write_object_csg_inside_vector(ob
, file)
702 material
= me
.materials
[0] # dodgy
703 write_object_material_interior(file, material
, ob
, tab_write
)
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()