-
Maurice Raybaud authored
* FIX: wrongly nested pov braces made the default outpout file fail * FIX: use agnostic metallic property rather than create a duplicate * FIX: some 2.8 deprecated properties rewired in spec;diff; emit;ambient * FIX: clean up, hierarchize and redesign Global Settings ui panel * FIX: re-wire world background alpha to agnostic prop and redo its ui * FIX: wrong nested pov braces making the default outpout file fail * FIX: use agnostic metallic property rather than create a duplicate * FIX: reduced arguments numbers by imports and relocating variables * FIX: use more list comprehesions to reduce nested conditions levels * FIX: use more consistent class names but cleanup still not finished * FIX: use single quotes for enums preferably to distinguish strings * FIX: basic level of nodes based material (diffuse color) broken API * FIX: blurry reflection corner case caused output file to fail * FIX: added context managing ("with") syntaxes reducing crash cases ___________________________________________________________ * ADD: model_all.py file to extract mostly object level loop and utils * ADD: model_meta_topology.py file to extract metaballs export * ADD: object_primitives_topology.py to extract pov compound primitives * ADD: nodes_fn.py file to extract main node exporting function * ADD: nodes_gui.py file to extract node operators and menus * ADD: nodes_properties.py file to extract nodes sub parameters * ADD: particles_properties.py to extract particles and fx parameters * ADD: render_core.py to extract main RenderEngine inheriting class(es) * ADD: shading_ray_properties.py to extract pathtraced shader parameters * ADD: texturing_procedural.py to extract algorithmic texture influences ___________________________________________________________ * UPDATE: workspace tools icons and a couple of other icons choices * RENAME: pov.add.polygontocircle.dat macro workspace tool icon * RENAME: base_ui.py to ui_core.py * RENAME: shading_nodes.py to nodes.py * RENAME: df3_library.py to voxel_lib.py to make dot lookup inform more * RENAME: object_mesh_topology.py to model_poly_topology.py * RENAME: object_curve_topology.py to model_curve_topology.py * RENAME: object_gui.py to model_gui.py * RENAME: object_primitives.py to model_primitives.py * RENAME: object_properties.py to model_properties.py * RENAME: object_particles.py to particles.py
Maurice Raybaud authored* FIX: wrongly nested pov braces made the default outpout file fail * FIX: use agnostic metallic property rather than create a duplicate * FIX: some 2.8 deprecated properties rewired in spec;diff; emit;ambient * FIX: clean up, hierarchize and redesign Global Settings ui panel * FIX: re-wire world background alpha to agnostic prop and redo its ui * FIX: wrong nested pov braces making the default outpout file fail * FIX: use agnostic metallic property rather than create a duplicate * FIX: reduced arguments numbers by imports and relocating variables * FIX: use more list comprehesions to reduce nested conditions levels * FIX: use more consistent class names but cleanup still not finished * FIX: use single quotes for enums preferably to distinguish strings * FIX: basic level of nodes based material (diffuse color) broken API * FIX: blurry reflection corner case caused output file to fail * FIX: added context managing ("with") syntaxes reducing crash cases ___________________________________________________________ * ADD: model_all.py file to extract mostly object level loop and utils * ADD: model_meta_topology.py file to extract metaballs export * ADD: object_primitives_topology.py to extract pov compound primitives * ADD: nodes_fn.py file to extract main node exporting function * ADD: nodes_gui.py file to extract node operators and menus * ADD: nodes_properties.py file to extract nodes sub parameters * ADD: particles_properties.py to extract particles and fx parameters * ADD: render_core.py to extract main RenderEngine inheriting class(es) * ADD: shading_ray_properties.py to extract pathtraced shader parameters * ADD: texturing_procedural.py to extract algorithmic texture influences ___________________________________________________________ * UPDATE: workspace tools icons and a couple of other icons choices * RENAME: pov.add.polygontocircle.dat macro workspace tool icon * RENAME: base_ui.py to ui_core.py * RENAME: shading_nodes.py to nodes.py * RENAME: df3_library.py to voxel_lib.py to make dot lookup inform more * RENAME: object_mesh_topology.py to model_poly_topology.py * RENAME: object_curve_topology.py to model_curve_topology.py * RENAME: object_gui.py to model_gui.py * RENAME: object_primitives.py to model_primitives.py * RENAME: object_properties.py to model_properties.py * RENAME: object_particles.py to particles.py
model_poly_topology.py 26.45 KiB
# SPDX-License-Identifier: GPL-2.0-or-later
# <pep8 compliant>
"""Translate to POV the control point compound geometries.
Here polygon meshes as POV mesh2 objects.
"""
import bpy
from . import texturing
from .scenography import image_format, img_map, img_map_transforms
from .shading import write_object_material_interior
from .model_primitives import write_object_modifiers
def write_object_csg_inside_vector(ob, file):
"""Write inside vector for use by pov CSG, only once per object using boolean"""
has_csg_inside_vector = False
for modif in ob.modifiers:
if not has_csg_inside_vector and modif.type == "BOOLEAN" and ob.pov.boolean_mod == "POV":
file.write(
"\tinside_vector <%.6g, %.6g, %.6g>\n"
% (
ob.pov.inside_vector[0],
ob.pov.inside_vector[1],
ob.pov.inside_vector[2],
)
)
has_csg_inside_vector = True
def export_mesh(file,
ob,
povdataname,
material_names_dictionary,
unpacked_images,
tab_level,
tab_write,
linebreaksinlists):
from .render import (
string_strip_hyphen,
tab,
comments,
preview_dir,
)
ob_eval = ob # not sure this is needed in case to_mesh_clear could damage obj ?
importance = ob.pov.importance_value
try:
me = ob_eval.to_mesh()
# Here identify the exception for mesh object with no data: Runtime-Error ?
# So we can write something for the dataname or maybe treated "if not me" below
except BaseException as e:
print(e.__doc__)
print("An exception occurred: {}".format(e))
# also happens when curves cant be made into meshes because of no-data
return False # To continue object loop
if me:
me.calc_loop_triangles()
me_materials = me.materials
me_faces = me.loop_triangles[:]
# --- numpytest
# me_looptris = me.loops
# Below otypes = ['int32'] is a 32-bit signed integer number numpy datatype
# get_v_index = np.vectorize(lambda l: l.vertex_index, otypes = ['int32'], cache = True)
# faces_verts_idx = get_v_index(me_looptris)
# if len(me_faces)==0:
# tab_write(file, "\n//dummy sphere to represent empty mesh location\n")
# 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)
if not me or not me_faces:
tab_write(file, "\n//dummy sphere to represent empty mesh location\n")
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,
)
return False # To continue object loop
uv_layers = me.uv_layers
if len(uv_layers) > 0:
if me.uv_layers.active and uv_layers.active.data:
uv_layer = uv_layers.active.data
else:
uv_layer = None
try:
# vcol_layer = me.vertex_colors.active.data
vcol_layer = me.vertex_colors.active.data
except AttributeError:
vcol_layer = None
faces_verts = [f.vertices[:] for f in me_faces]
faces_normals = [f.normal[:] for f in me_faces]
verts_normals = [v.normal[:] for v in me.vertices]
# Use named declaration to allow reference e.g. for baking. MR
file.write("\n")
tab_write(file, "#declare %s =\n" % povdataname)
tab_write(file, "mesh2 {\n")
tab_write(file, "vertex_vectors {\n")
tab_write(file, "%d" % len(me.vertices)) # vert count
tab_str = tab * tab_level
for v in me.vertices:
if linebreaksinlists:
file.write(",\n")
file.write(tab_str + "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
else:
file.write(", ")
file.write("<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
# tab_write(file, "<%.6f, %.6f, %.6f>" % v.co[:]) # vert count
file.write("\n")
tab_write(file, "}\n")
# Build unique Normal list
uniqueNormals = {}
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
# [-1] is a dummy index, use a list so we can modify in place
if f.use_smooth: # Use vertex normals
for v in fv:
key = verts_normals[v]
uniqueNormals[key] = [-1]
else: # Use face normal
key = faces_normals[fi]
uniqueNormals[key] = [-1]
tab_write(file, "normal_vectors {\n")
tab_write(file, "%d" % len(uniqueNormals)) # vert count
idx = 0
tab_str = tab * tab_level
for no, index in uniqueNormals.items():
if linebreaksinlists:
file.write(",\n")
file.write(tab_str + "<%.6f, %.6f, %.6f>" % no) # vert count
else:
file.write(", ")
file.write("<%.6f, %.6f, %.6f>" % no) # vert count
index[0] = idx
idx += 1
file.write("\n")
tab_write(file, "}\n")
# Vertex colors
vertCols = {} # Use for material colors also.
if uv_layer:
# Generate unique UV's
uniqueUVs = {}
# n = 0
for f in me_faces: # me.faces in 2.7
uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
for uv in uvs:
uniqueUVs[uv[:]] = [-1]
tab_write(file, "uv_vectors {\n")
# print unique_uvs
tab_write(file, "%d" % len(uniqueUVs)) # vert count
idx = 0
tab_str = tab * tab_level
for uv, index in uniqueUVs.items():
if linebreaksinlists:
file.write(",\n")
file.write(tab_str + "<%.6f, %.6f>" % uv)
else:
file.write(", ")
file.write("<%.6f, %.6f>" % uv)
index[0] = idx
idx += 1
"""
else:
# Just add 1 dummy vector, no real UV's
tab_write(file, '1') # vert count
file.write(',\n\t\t<0.0, 0.0>')
"""
file.write("\n")
tab_write(file, "}\n")
if me.vertex_colors:
# Write down vertex colors as a texture for each vertex
tab_write(file, "texture_list {\n")
tab_write(
file, "%d\n" % (len(me_faces) * 3)
) # assumes we have only triangles
VcolIdx = 0
if comments:
file.write(
"\n //Vertex colors: one simple pigment texture per vertex\n"
)
for fi, f in enumerate(me_faces):
# annoying, index may be invalid
material_index = f.material_index
try:
material = me_materials[material_index]
except BaseException as e:
print(e.__doc__)
print("An exception occurred: {}".format(e))
material = None
if (
material
# and material.pov.use_vertex_color_paint
): # Or maybe Always use vertex color when there is some for now
cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
for col in cols:
key = (
col[0],
col[1],
col[2],
material_index,
) # Material index!
VcolIdx += 1
vertCols[key] = [VcolIdx]
if linebreaksinlists:
tab_write(
file,
"texture {pigment{ color srgb <%6f,%6f,%6f> }}\n"
% (col[0], col[1], col[2]),
)
else:
tab_write(
file,
"texture {pigment{ color srgb <%6f,%6f,%6f> }}"
% (col[0], col[1], col[2]),
)
tab_str = tab * tab_level
else:
if material:
# Multiply diffuse with SSS Color
if material.pov_subsurface_scattering.use:
diffuse_color = [
i * j
for i, j in zip(
material.pov_subsurface_scattering.color[:],
material.diffuse_color[:],
)
]
key = (
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
material_index,
)
vertCols[key] = [-1]
else:
diffuse_color = material.diffuse_color[:]
key = (
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
material_index,
)
vertCols[key] = [-1]
tab_write(file, "\n}\n")
# Face indices
tab_write(file, "\nface_indices {\n")
tab_write(file, "%d" % (len(me_faces))) # faces count
tab_str = tab * tab_level
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
material_index = f.material_index
if vcol_layer:
cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
if not me_materials or (
me_materials[material_index] is None
): # No materials
if linebreaksinlists:
file.write(",\n")
# vert count
file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
else:
material = me_materials[material_index]
if me.vertex_colors: # and material.pov.use_vertex_color_paint:
# Color per vertex - vertex color
col1 = cols[0]
col2 = cols[1]
col3 = cols[2]
ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
else:
# Color per material - flat material color
if material.pov_subsurface_scattering.use:
diffuse_color = [
i * j
for i, j in zip(
material.pov_subsurface_scattering.color[:],
material.diffuse_color[:],
)
]
else:
diffuse_color = material.diffuse_color[:]
ci1 = ci2 = ci3 = vertCols[
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
f.material_index,
][0]
# ci are zero based index so we'll subtract 1 from them
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str
+ "<%d,%d,%d>, %d,%d,%d"
% (
fv[0],
fv[1],
fv[2],
ci1 - 1,
ci2 - 1,
ci3 - 1,
)
) # vert count
else:
file.write(", ")
file.write(
"<%d,%d,%d>, %d,%d,%d"
% (
fv[0],
fv[1],
fv[2],
ci1 - 1,
ci2 - 1,
ci3 - 1,
)
) # vert count
file.write("\n")
tab_write(file, "}\n")
# normal_indices indices
tab_write(file, "normal_indices {\n")
tab_write(file, "%d" % (len(me_faces))) # faces count
tab_str = tab * tab_level
for fi, fv in enumerate(faces_verts):
if me_faces[fi].use_smooth:
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str
+ "<%d,%d,%d>"
% (
uniqueNormals[verts_normals[fv[0]]][0],
uniqueNormals[verts_normals[fv[1]]][0],
uniqueNormals[verts_normals[fv[2]]][0],
)
) # vert count
else:
file.write(", ")
file.write(
"<%d,%d,%d>"
% (
uniqueNormals[verts_normals[fv[0]]][0],
uniqueNormals[verts_normals[fv[1]]][0],
uniqueNormals[verts_normals[fv[2]]][0],
)
) # vert count
else:
idx = uniqueNormals[faces_normals[fi]][0]
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str + "<%d,%d,%d>" % (idx, idx, idx)
) # vert count
else:
file.write(", ")
file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
file.write("\n")
tab_write(file, "}\n")
if uv_layer:
tab_write(file, "uv_indices {\n")
tab_write(file, "%d" % (len(me_faces))) # faces count
tab_str = tab * tab_level
for f in me_faces:
uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str
+ "<%d,%d,%d>"
% (
uniqueUVs[uvs[0]][0],
uniqueUVs[uvs[1]][0],
uniqueUVs[uvs[2]][0],
)
)
else:
file.write(", ")
file.write(
"<%d,%d,%d>"
% (
uniqueUVs[uvs[0]][0],
uniqueUVs[uvs[1]][0],
uniqueUVs[uvs[2]][0],
)
)
file.write("\n")
tab_write(file, "}\n")
# XXX BOOLEAN MODIFIER
write_object_csg_inside_vector(ob, file)
if me.materials:
try:
material = me.materials[0] # dodgy
write_object_material_interior(file, material, ob, tab_write)
except IndexError:
print(me)
# POV object modifiers such as
# hollow / sturm / double_illuminate etc.
write_object_modifiers(ob, file)
# Importance for radiosity sampling added here:
tab_write(file, "radiosity { \n")
tab_write(file, "importance %3g \n" % importance)
tab_write(file, "}\n")
tab_write(file, "}\n") # End of mesh block
else:
facesMaterials = [] # WARNING!!!!!!!!!!!!!!!!!!!!!!
if me_materials:
new_me_faces_mat_idx = (f for f in me_faces if f.material_index not in
facesMaterials)
for f in new_me_faces_mat_idx:
facesMaterials.append(f.material_index)
# No vertex colors, so write material colors as vertex colors
for i, material in enumerate(me_materials):
if (
material and material.pov.material_use_nodes is False
): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Multiply diffuse with SSS Color
if material.pov_subsurface_scattering.use:
diffuse_color = [
i * j
for i, j in zip(
material.pov_subsurface_scattering.color[:],
material.diffuse_color[:],
)
]
key = (
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
i,
) # i == f.mat
vertCols[key] = [-1]
else:
diffuse_color = material.diffuse_color[:]
key = (
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
i,
) # i == f.mat
vertCols[key] = [-1]
idx = 0
texturing.local_material_names = []
for col, index in vertCols.items():
# if me_materials:
mater = me_materials[col[3]]
if me_materials is not None:
texturing.write_texture_influence(
file,
mater,
material_names_dictionary,
image_format,
img_map,
img_map_transforms,
tab_write,
comments,
col,
preview_dir,
unpacked_images,
)
# ------------------------------------------------
index[0] = idx
idx += 1
# Vert Colors
tab_write(file, "texture_list {\n")
# In case there's is no material slot, give at least one texture
# (an empty one so it uses pov default)
if len(vertCols) != 0:
tab_write(
file, "%s" % (len(vertCols))
) # vert count
else:
tab_write(file, "1")
# below "material" alias, added check obj.active_material
# to avoid variable referenced before assignment error
try:
material = ob.active_material
except IndexError:
# when no material slot exists,
material = None
# WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (
material
and ob.active_material is not None
and not material.pov.material_use_nodes
and not material.use_nodes
):
if material.pov.replacement_text != "":
file.write("\n")
file.write(" texture{%s}\n" % material.pov.replacement_text)
else:
# Loop through declared materials list
# global local_material_names
for cMN in texturing.local_material_names:
if material != "Default":
file.write("\n texture{MAT_%s}\n" % cMN)
# use string_strip_hyphen(material_names_dictionary[material]))
# or Something like that to clean up the above?
elif material and material.pov.material_use_nodes:
for index in facesMaterials:
faceMaterial = string_strip_hyphen(
bpy.path.clean_name(me_materials[index].name)
)
file.write("\n texture{%s}\n" % faceMaterial)
# END!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
elif vertCols:
for cMN in vertCols: # or in texturing.local_material_names:
# if possible write only one, though
file.write(" texture{}\n")
else:
file.write(" texture{}\n")
tab_write(file, "}\n")
# Face indices
tab_write(file, "face_indices {\n")
tab_write(file, "%d" % (len(me_faces))) # faces count
tab_str = tab * tab_level
for fi, f in enumerate(me_faces):
fv = faces_verts[fi]
material_index = f.material_index
if vcol_layer:
cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops]
if (
not me_materials or me_materials[material_index] is None
): # No materials
if linebreaksinlists:
file.write(",\n")
# vert count
file.write(tab_str + "<%d,%d,%d>" % (fv[0], fv[1], fv[2]))
else:
file.write(", ")
file.write("<%d,%d,%d>" % (fv[0], fv[1], fv[2])) # vert count
else:
material = me_materials[material_index]
ci1 = ci2 = ci3 = f.material_index
if me.vertex_colors: # and material.pov.use_vertex_color_paint:
# Color per vertex - vertex color
col1 = cols[0]
col2 = cols[1]
col3 = cols[2]
ci1 = vertCols[col1[0], col1[1], col1[2], material_index][0]
ci2 = vertCols[col2[0], col2[1], col2[2], material_index][0]
ci3 = vertCols[col3[0], col3[1], col3[2], material_index][0]
elif material.pov.material_use_nodes:
ci1 = ci2 = ci3 = 0
else:
# Color per material - flat material color
if material.pov_subsurface_scattering.use:
diffuse_color = [
i * j
for i, j in zip(
material.pov_subsurface_scattering.color[:],
material.diffuse_color[:],
)
]
else:
diffuse_color = material.diffuse_color[:]
ci1 = ci2 = ci3 = vertCols[
diffuse_color[0],
diffuse_color[1],
diffuse_color[2],
f.material_index,
][0]
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str
+ "<%d,%d,%d>, %d,%d,%d"
% (fv[0], fv[1], fv[2], ci1, ci2, ci3)
) # vert count
else:
file.write(", ")
file.write(
"<%d,%d,%d>, %d,%d,%d"
% (fv[0], fv[1], fv[2], ci1, ci2, ci3)
) # vert count
file.write("\n")
tab_write(file, "}\n")
# normal_indices indices
tab_write(file, "normal_indices {\n")
tab_write(file, "%d" % (len(me_faces))) # faces count
tab_str = tab * tab_level
for fi, fv in enumerate(faces_verts):
if me_faces[fi].use_smooth:
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str
+ "<%d,%d,%d>"
% (
uniqueNormals[verts_normals[fv[0]]][0],
uniqueNormals[verts_normals[fv[1]]][0],
uniqueNormals[verts_normals[fv[2]]][0],
)
) # vert count
else:
file.write(", ")
file.write(
"<%d,%d,%d>"
% (
uniqueNormals[verts_normals[fv[0]]][0],
uniqueNormals[verts_normals[fv[1]]][0],
uniqueNormals[verts_normals[fv[2]]][0],
)
) # vert count
else:
idx = uniqueNormals[faces_normals[fi]][0]
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str + "<%d,%d,%d>" % (idx, idx, idx)
) # vertcount
else:
file.write(", ")
file.write("<%d,%d,%d>" % (idx, idx, idx)) # vert count
file.write("\n")
tab_write(file, "}\n")
if uv_layer:
tab_write(file, "uv_indices {\n")
tab_write(file, "%d" % (len(me_faces))) # faces count
tab_str = tab * tab_level
for f in me_faces:
uvs = [uv_layer[loop_index].uv[:] for loop_index in f.loops]
if linebreaksinlists:
file.write(",\n")
file.write(
tab_str
+ "<%d,%d,%d>"
% (
uniqueUVs[uvs[0]][0],
uniqueUVs[uvs[1]][0],
uniqueUVs[uvs[2]][0],
)
)
else:
file.write(", ")
file.write(
"<%d,%d,%d>"
% (
uniqueUVs[uvs[0]][0],
uniqueUVs[uvs[1]][0],
uniqueUVs[uvs[2]][0],
)
)
file.write("\n")
tab_write(file, "}\n")
# XXX BOOLEAN
write_object_csg_inside_vector(ob, file)
if me.materials:
try:
material = me.materials[0] # dodgy
write_object_material_interior(file, material, ob, tab_write)
except IndexError:
print(me)
# POV object modifiers such as
# hollow / sturm / double_illuminate etc.
write_object_modifiers(ob, file)
# Importance for radiosity sampling added here:
tab_write(file, "radiosity { \n")
tab_write(file, "importance %3g \n" % importance)
tab_write(file, "}\n")
tab_write(file, "}\n") # End of mesh block
ob_eval.to_mesh_clear()
return True