diff options
author | Maurice Raybaud <mauriceraybaud@hotmail.fr> | 2022-01-26 03:02:18 +0300 |
---|---|---|
committer | Maurice Raybaud <mauriceraybaud@hotmail.fr> | 2022-01-26 03:02:18 +0300 |
commit | 692611358a9189c2f54f916c42a08e1ddf54bb84 (patch) | |
tree | 68ee4016d4be897fd53d5c51419c43443cd9dbe9 /render_povray/object_mesh_topology.py | |
parent | fd5697ebcf879894d84875b593fe00ede14e79a4 (diff) |
POV: Add primitives workspace tools icons, blurry reflections, equation based isourface ; various fixes
* fix tiny formatting of quotes, docstrings, parenthesis
* fix pov centered worspaces
* fix (revert) bad default for text block insertion
* fix primitive exports sorted by most frequent for (slight) speed up
* fix some uninitialized hairstrand root diameter variable
* fix extracted function for CSG inside vector
* fix too big size of proxy mesh for ininite plane caused it to blink
* fix end of render speach error handling
* fix max specular value to better map out under a texture influence
* fix emit, ambient, translucency shading properties UI broken post 2.8
* add workspace tools icons for pov primitives
* add a user input equation based isosurface primitive
* add micro normals based blurry reflections (glossy UI slider)
Diffstat (limited to 'render_povray/object_mesh_topology.py')
-rwxr-xr-x | render_povray/object_mesh_topology.py | 1104 |
1 files changed, 566 insertions, 538 deletions
diff --git a/render_povray/object_mesh_topology.py b/render_povray/object_mesh_topology.py index cd98a6f4..e991070c 100755 --- a/render_povray/object_mesh_topology.py +++ b/render_povray/object_mesh_topology.py @@ -30,28 +30,48 @@ import bpy from . import texturing # for how textures influence shaders from .scenography import export_smoke - def matrix_as_pov_string(matrix): """Translate some transform matrix from Blender UI to POV syntax and return that string """ - matrix_string = ( - "matrix <%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f>\n" - % ( - matrix[0][0], - matrix[1][0], - matrix[2][0], - matrix[0][1], - matrix[1][1], - matrix[2][1], - matrix[0][2], - matrix[1][2], - matrix[2][2], - matrix[0][3], - matrix[1][3], - matrix[2][3], - ) - ) - return matrix_string + return "matrix <" \ + "%.6f, %.6f, %.6f, " \ + "%.6f, %.6f, %.6f, " \ + "%.6f, %.6f, %.6f, " \ + "%.6f, %.6f, %.6f" \ + ">\n" % ( + matrix[0][0], + matrix[1][0], + matrix[2][0], + matrix[0][1], + matrix[1][1], + matrix[2][1], + matrix[0][2], + matrix[1][2], + matrix[2][2], + matrix[0][3], + matrix[1][3], + matrix[2][3], + ) + + +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 # objectNames = {} @@ -59,32 +79,32 @@ DEF_OBJ_NAME = "Default" def export_meshes( - preview_dir, - file, - scene, - sel, - csg, - string_strip_hyphen, - safety, - write_object_modifiers, - material_names_dictionary, - write_object_material_interior, - exported_lights_count, - unpacked_images, - image_format, - img_map, - img_map_transforms, - path_image, - smoke_path, - global_matrix, - write_matrix, - using_uberpov, - comments, - linebreaksinlists, - tab, - tab_level, - tab_write, - info_callback, + preview_dir, + file, + scene, + sel, + csg, + string_strip_hyphen, + safety, + write_object_modifiers, + material_names_dictionary, + write_object_material_interior, + exported_lights_count, + unpacked_images, + image_format, + img_map, + img_map_transforms, + path_image, + smoke_path, + global_matrix, + write_matrix, + using_uberpov, + comments, + linebreaksinlists, + tab, + tab_level, + tab_write, + info_callback, ): """write all meshes as POV mesh2{} syntax to exported file """ # # some numpy functions to speed up mesh export NOT IN USE YET @@ -93,72 +113,72 @@ def export_meshes( # # TODO: also write a numpy function to read matrices at object level? # # feed below with mesh object.data, but only after doing data.calc_loop_triangles() # def read_verts_co(self, mesh): - # #'float64' would be a slower 64-bit floating-point number numpy datatype - # # using 'float32' vert coordinates for now until any issue is reported - # mverts_co = np.zeros((len(mesh.vertices) * 3), dtype=np.float32) - # mesh.vertices.foreach_get("co", mverts_co) - # return np.reshape(mverts_co, (len(mesh.vertices), 3)) + # #'float64' would be a slower 64-bit floating-point number numpy datatype + # # using 'float32' vert coordinates for now until any issue is reported + # mverts_co = np.zeros((len(mesh.vertices) * 3), dtype=np.float32) + # mesh.vertices.foreach_get("co", mverts_co) + # return np.reshape(mverts_co, (len(mesh.vertices), 3)) # def read_verts_idx(self, mesh): - # mverts_idx = np.zeros((len(mesh.vertices)), dtype=np.int64) - # mesh.vertices.foreach_get("index", mverts_idx) - # return np.reshape(mverts_idx, (len(mesh.vertices), 1)) + # mverts_idx = np.zeros((len(mesh.vertices)), dtype=np.int64) + # mesh.vertices.foreach_get("index", mverts_idx) + # return np.reshape(mverts_idx, (len(mesh.vertices), 1)) # def read_verts_norms(self, mesh): - # #'float64' would be a slower 64-bit floating-point number numpy datatype - # # using less accurate 'float16' normals for now until any issue is reported - # mverts_no = np.zeros((len(mesh.vertices) * 3), dtype=np.float16) - # mesh.vertices.foreach_get("normal", mverts_no) - # return np.reshape(mverts_no, (len(mesh.vertices), 3)) + # #'float64' would be a slower 64-bit floating-point number numpy datatype + # # using less accurate 'float16' normals for now until any issue is reported + # mverts_no = np.zeros((len(mesh.vertices) * 3), dtype=np.float16) + # mesh.vertices.foreach_get("normal", mverts_no) + # return np.reshape(mverts_no, (len(mesh.vertices), 3)) # def read_faces_idx(self, mesh): - # mfaces_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int64) - # mesh.loop_triangles.foreach_get("index", mfaces_idx) - # return np.reshape(mfaces_idx, (len(mesh.loop_triangles), 1)) + # mfaces_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int64) + # mesh.loop_triangles.foreach_get("index", mfaces_idx) + # return np.reshape(mfaces_idx, (len(mesh.loop_triangles), 1)) # def read_faces_verts_indices(self, mesh): - # mfaces_verts_idx = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64) - # mesh.loop_triangles.foreach_get("vertices", mfaces_verts_idx) - # return np.reshape(mfaces_verts_idx, (len(mesh.loop_triangles), 3)) + # mfaces_verts_idx = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64) + # mesh.loop_triangles.foreach_get("vertices", mfaces_verts_idx) + # return np.reshape(mfaces_verts_idx, (len(mesh.loop_triangles), 3)) # # Why is below different from vertex indices? # def read_faces_verts_loops(self, mesh): - # mfaces_verts_loops = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64) - # mesh.loop_triangles.foreach_get("loops", mfaces_verts_loops) - # return np.reshape(mfaces_verts_loops, (len(mesh.loop_triangles), 3)) + # mfaces_verts_loops = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.int64) + # mesh.loop_triangles.foreach_get("loops", mfaces_verts_loops) + # return np.reshape(mfaces_verts_loops, (len(mesh.loop_triangles), 3)) # def read_faces_norms(self, mesh): - # #'float64' would be a slower 64-bit floating-point number numpy datatype - # # using less accurate 'float16' normals for now until any issue is reported - # mfaces_no = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.float16) - # mesh.loop_triangles.foreach_get("normal", mfaces_no) - # return np.reshape(mfaces_no, (len(mesh.loop_triangles), 3)) + # #'float64' would be a slower 64-bit floating-point number numpy datatype + # # using less accurate 'float16' normals for now until any issue is reported + # mfaces_no = np.zeros((len(mesh.loop_triangles) * 3), dtype=np.float16) + # mesh.loop_triangles.foreach_get("normal", mfaces_no) + # return np.reshape(mfaces_no, (len(mesh.loop_triangles), 3)) # def read_faces_smooth(self, mesh): - # mfaces_smth = np.zeros((len(mesh.loop_triangles) * 1), dtype=np.bool) - # mesh.loop_triangles.foreach_get("use_smooth", mfaces_smth) - # return np.reshape(mfaces_smth, (len(mesh.loop_triangles), 1)) + # mfaces_smth = np.zeros((len(mesh.loop_triangles) * 1), dtype=np.bool) + # mesh.loop_triangles.foreach_get("use_smooth", mfaces_smth) + # return np.reshape(mfaces_smth, (len(mesh.loop_triangles), 1)) # def read_faces_material_indices(self, mesh): - # mfaces_mats_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int16) - # mesh.loop_triangles.foreach_get("material_index", mfaces_mats_idx) - # return np.reshape(mfaces_mats_idx, (len(mesh.loop_triangles), 1)) + # mfaces_mats_idx = np.zeros((len(mesh.loop_triangles)), dtype=np.int16) + # mesh.loop_triangles.foreach_get("material_index", mfaces_mats_idx) + # return np.reshape(mfaces_mats_idx, (len(mesh.loop_triangles), 1)) # obmatslist = [] # def hasUniqueMaterial(): # # Grab materials attached to object instances ... - # if hasattr(ob, 'material_slots'): - # for ms in ob.material_slots: + # if hasattr(obj, 'material_slots'): + # for ms in obj.material_slots: # if ms.material is not None and ms.link == 'OBJECT': # if ms.material in obmatslist: # return False # else: # obmatslist.append(ms.material) # return True - # def hasObjectMaterial(ob): + # def hasObjectMaterial(obj): # # Grab materials attached to object instances ... - # if hasattr(ob, 'material_slots'): - # for ms in ob.material_slots: + # if hasattr(obj, 'material_slots'): + # for ms in obj.material_slots: # if ms.material is not None and ms.link == 'OBJECT': # # If there is at least one material slot linked to the object # # and not the data (mesh), always create a new, "private" data instance. @@ -173,12 +193,12 @@ def export_meshes( # ... can share a same instance in POV export. obmats2data = {} - def check_object_materials(ob, name, dataname): + def check_object_materials(obj, obj_name, dataname): """Compare other objects exported material slots to avoid rewriting duplicates""" - if hasattr(ob, 'material_slots'): + if hasattr(obj, 'material_slots'): has_local_mats = False key = [dataname] - for ms in ob.material_slots: + for ms in obj.material_slots: if ms.material is not None: key.append(ms.material.name) if ms.link == 'OBJECT' and not has_local_mats: @@ -193,7 +213,7 @@ def export_meshes( # Note that here also, we use object name as new, unique dataname for Pov. key = tuple(key) # Lists are not hashable... if key not in obmats2data: - obmats2data[key] = name + obmats2data[key] = obj_name return obmats2data[key] return None @@ -242,10 +262,10 @@ def export_meshes( 'LATTICE', }: continue - fluid_flag = False + fluid_found = False for mod in ob.modifiers: if mod and hasattr(mod, 'fluid_type'): - fluid_flag = True + fluid_found = True if mod.fluid_type == 'DOMAIN': if mod.domain_settings.domain_type == 'GAS': export_smoke( @@ -255,30 +275,26 @@ def export_meshes( if mod.fluid_type == 'FLOW': # The domain contains all the smoke. so that's it. if mod.flow_settings.flow_type == 'SMOKE': # Check how liquids behave break # don't render smoke flow emitter mesh either, skip to next object. - if not fluid_flag: - # Export Hair - # importing here rather than at the top recommended for addons startup footprint - from .object_particles import export_hair - - render_emitter = True + if not fluid_found: + # No fluid found if hasattr(ob, 'particle_systems'): - render_emitter = False - if ob.show_instancer_for_render: - render_emitter = True + # Importing function Export Hair + # here rather than at the top recommended for addons startup footprint + from .object_particles import export_hair for p_sys in ob.particle_systems: - for mod in [ + for particle_mod in [ m for m in ob.modifiers if (m is not None) and (m.type == 'PARTICLE_SYSTEM') ]: if ( - (p_sys.settings.render_type == 'PATH') - and mod.show_render - and (p_sys.name == mod.particle_system.name) + (p_sys.settings.render_type == 'PATH') + and particle_mod.show_render + and (p_sys.name == particle_mod.particle_system.name) ): - export_hair(file, ob, mod, p_sys, global_matrix, write_matrix) - if not render_emitter: - continue # don't render mesh, skip to next object. + export_hair(file, ob, particle_mod, p_sys, global_matrix, write_matrix) + if not ob.show_instancer_for_render: + continue # don't render emitter mesh, skip to next object. # ------------------------------------------------ # Generating a name for object just like materials to be able to use it @@ -300,8 +316,8 @@ def export_meshes( # original included in list since 2.8 if eachduplicate.is_instance: dataname_orig = "DATA" + eachduplicate.object.name - # ob.dupli_list_clear() #just don't store any reference to instance since 2.8 - elif ob.data: # not an EMPTY type object + # obj.dupli_list_clear() #just don't store any reference to instance since 2.8 + elif ob.data: # not an EMPTY type object name_orig = "OB" + ob.name dataname_orig = "DATA" + ob.data.name elif ob.type == 'EMPTY': @@ -312,7 +328,7 @@ def export_meshes( dataname_orig = DEF_OBJ_NAME name = string_strip_hyphen(bpy.path.clean_name(name_orig)) dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig)) - # for slot in ob.material_slots: + # for slot in obj.material_slots: # if slot.material is not None and slot.link == 'OBJECT': # obmaterial = slot.material @@ -331,397 +347,25 @@ def export_meshes( print("Writing Down First Occurrence of " + name) - # ------------ Povray Primitives ------------ # + # ------------ Mesh Primitives ------------ # # special export_curves() function takes care of writing # lathe, sphere_sweep, birail, and loft except with modifiers # converted to mesh if not ob.is_modified(scene, 'RENDER'): if ob.type == 'CURVE' and ( - ob.pov.curveshape in {'lathe', 'sphere_sweep', 'loft'} + ob.pov.curveshape in {'lathe', 'sphere_sweep', 'loft'} ): continue # Don't render proxy mesh, skip to next object # pov_mat_name = "Default_texture" # Not used...remove? - if ob.pov.object_as == 'ISOSURFACE': - tab_write("#declare %s = isosurface{ \n" % povdataname) - tab_write("function{ \n") - text_name = ob.pov.iso_function_text - if text_name: - node_tree = bpy.context.scene.node_tree - for node in node_tree.nodes: - if node.bl_idname == "IsoPropsNode" and node.label == ob.name: - for inp in node.inputs: - if inp: - tab_write( - "#declare %s = %.6g;\n" % (inp.name, inp.default_value) - ) - - text = bpy.data.texts[text_name] - for line in text.lines: - split = line.body.split() - if split[0] != "#declare": - tab_write("%s\n" % line.body) - else: - tab_write("abs(x) - 2 + y") - tab_write("}\n") - tab_write("threshold %.6g\n" % ob.pov.threshold) - tab_write("max_gradient %.6g\n" % ob.pov.max_gradient) - tab_write("accuracy %.6g\n" % ob.pov.accuracy) - tab_write("contained_by { ") - if ob.pov.contained_by == "sphere": - tab_write("sphere {0,%.6g}}\n" % ob.pov.container_scale) - else: - tab_write( - "box {-%.6g,%.6g}}\n" % (ob.pov.container_scale, ob.pov.container_scale) - ) - if ob.pov.all_intersections: - tab_write("all_intersections\n") - else: - if ob.pov.max_trace > 1: - tab_write("max_trace %.6g\n" % ob.pov.max_trace) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - tab_write("scale %.6g\n" % (1 / ob.pov.container_scale)) - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'SUPERELLIPSOID': - tab_write( - "#declare %s = superellipsoid{ <%.4f,%.4f>\n" - % (povdataname, ob.pov.se_n2, ob.pov.se_n1) - ) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'SUPERTORUS': - rad_maj = ob.pov.st_major_radius - rad_min = ob.pov.st_minor_radius - ring = ob.pov.st_ring - cross = ob.pov.st_cross - accuracy = ob.pov.st_accuracy - gradient = ob.pov.st_max_gradient - # --- Inline Supertorus macro - file.write( - "#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n" - ) - file.write(" #local CP = 2/MinorControl;\n") - file.write(" #local RP = 2/MajorControl;\n") - file.write(" isosurface {\n") - file.write( - " function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n" - ) - file.write(" threshold 0\n") - file.write( - " contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n" - ) - file.write(" #if(MaxGradient >= 1)\n") - file.write(" max_gradient MaxGradient\n") - file.write(" #else\n") - file.write(" evaluate 1, 10, 0.1\n") - file.write(" #end\n") - file.write(" accuracy Accuracy\n") - file.write(" }\n") - file.write("#end\n") - # --- - tab_write( - "#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n" - % (povdataname, rad_maj, rad_min, ring, cross, accuracy, gradient) - ) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'PLANE': - tab_write("#declare %s = plane{ <0,0,1>,1\n" % povdataname) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - # tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - if ob.pov.object_as == 'BOX': - tab_write("#declare %s = box { -1,1\n" % povdataname) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - # tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'CONE': - br = ob.pov.cone_base_radius - cr = ob.pov.cone_cap_radius - bz = ob.pov.cone_base_z - cz = ob.pov.cone_cap_z - tab_write( - "#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n" - % (povdataname, bz, br, cz, cr) - ) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - # tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'CYLINDER': - r = ob.pov.cylinder_radius - x2 = ob.pov.cylinder_location_cap[0] - y2 = ob.pov.cylinder_location_cap[1] - z2 = ob.pov.cylinder_location_cap[2] - tab_write( - "#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n" - % (povdataname, x2, y2, z2, r) - ) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - # cylinders written at origin, translated below - write_object_modifiers(scene, ob, file) - # tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'HEIGHT_FIELD': - data = "" - filename = ob.pov.hf_filename - data += '"%s"' % filename - gamma = ' gamma %.4f' % ob.pov.hf_gamma - data += gamma - if ob.pov.hf_premultiplied: - data += ' premultiplied on' - if ob.pov.hf_smooth: - data += ' smooth' - if ob.pov.hf_water > 0: - data += ' water_level %.4f' % ob.pov.hf_water - # hierarchy = ob.pov.hf_hierarchy - tab_write('#declare %s = height_field { %s\n' % (povdataname, data)) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - tab_write("rotate x*90\n") - tab_write("translate <-0.5,0.5,0>\n") - tab_write("scale <0,-1,0>\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'SPHERE': - - tab_write( - "#declare %s = sphere { 0,%6f\n" % (povdataname, ob.pov.sphere_radius) - ) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - # tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'TORUS': - tab_write( - "#declare %s = torus { %.4f,%.4f\n" - % (povdataname, ob.pov.torus_major_radius, ob.pov.torus_minor_radius) - ) - if ob.active_material: - # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name)) - try: - material = ob.active_material - write_object_material_interior(material, ob, tab_write) - except IndexError: - print(me) - # tab_write("texture {%s}\n"%pov_mat_name) - write_object_modifiers(scene, ob, file) - tab_write("rotate x*90\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'PARAMETRIC': - tab_write("#declare %s = parametric {\n" % povdataname) - tab_write("function { %s }\n" % ob.pov.x_eq) - tab_write("function { %s }\n" % ob.pov.y_eq) - tab_write("function { %s }\n" % ob.pov.z_eq) - tab_write( - "<%.4f,%.4f>, <%.4f,%.4f>\n" - % (ob.pov.u_min, ob.pov.v_min, ob.pov.u_max, ob.pov.v_max) - ) - # Previous to 3.8 default max_gradient 1.0 was too slow - tab_write("max_gradient 0.001\n") - if ob.pov.contained_by == "sphere": - tab_write("contained_by { sphere{0, 2} }\n") - else: - tab_write("contained_by { box{-2, 2} }\n") - tab_write("max_gradient %.6f\n" % ob.pov.max_gradient) - tab_write("accuracy %.6f\n" % ob.pov.accuracy) - tab_write("precompute 10 x,y,z\n") - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - if ob.pov.object_as == 'POLYCIRCLE': - # TODO write below macro Once: - # if write_polytocircle_macro_once == 0: - file.write("/****************************\n") - file.write("This macro was written by 'And'.\n") - file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n") - file.write("****************************/\n") - file.write("//from math.inc:\n") - file.write("#macro VPerp_Adjust(V, Axis)\n") - file.write(" vnormalize(vcross(vcross(Axis, V), Axis))\n") - file.write("#end\n") - file.write("//Then for the actual macro\n") - file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n") - file.write("#local p1 = point1 + <0,0,0>;\n") - file.write("#local p2 = point2 + <0,0,0>;\n") - file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n") - file.write("#local direct_v1 = vnormalize(p2 - p1);\n") - file.write("#if(vdot(direct_v1, clip_v) = 1)\n") - file.write(' #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n') - file.write("#end\n\n") - file.write( - "#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n" - ) - file.write("#local d = vdot(norm, p1);\n") - file.write("plane{\n") - file.write("norm, d\n") - file.write("}\n") - file.write("#end\n\n") - file.write("//polygon to circle\n") - file.write( - "#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n" - ) - file.write("#local n = int(_polygon_n);\n") - file.write("#if(n < 3)\n") - file.write(" #error " "\n") - file.write("#end\n\n") - file.write("#local front_v = VPerp_Adjust(_side_face, z);\n") - file.write("#if(vdot(front_v, x) >= 0)\n") - file.write(" #local face_ang = acos(vdot(-y, front_v));\n") - file.write("#else\n") - file.write(" #local face_ang = -acos(vdot(-y, front_v));\n") - file.write("#end\n") - file.write("#local polyg_ext_ang = 2*pi/n;\n") - file.write("#local polyg_outer_r = _polygon_circumscribed_radius;\n") - file.write("#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n") - file.write("#local cycle_r = _circle_radius;\n") - file.write("#local h = _height;\n") - file.write("#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n") - file.write(' #error "error: each side length must be positive"\n') - file.write("#end\n\n") - file.write("#local multi = 1000;\n") - file.write("#local poly_obj =\n") - file.write("polynomial{\n") - file.write("4,\n") - file.write("xyz(0,2,2): multi*1,\n") - file.write("xyz(2,0,1): multi*2*h,\n") - file.write("xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n") - file.write("xyz(2,0,0): multi*(-h*h),\n") - file.write("xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n") - file.write("xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n") - file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n") - file.write("xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n") - file.write("xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n") - file.write("sturm\n") - file.write("}\n\n") - file.write("#local mockup1 =\n") - file.write("difference{\n") - file.write(" cylinder{\n") - file.write(" <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n") - file.write(" }\n\n") - file.write(" #for(i, 0, n-1)\n") - file.write(" object{\n") - file.write(" poly_obj\n") - file.write(" inverse\n") - file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n") - file.write(" }\n") - file.write(" object{\n") - file.write( - " Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n" - ) - file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n") - file.write(" }\n") - file.write(" #end\n") - file.write("}\n\n") - file.write("object{\n") - file.write("mockup1\n") - file.write("rotate <0, 0, degrees(face_ang)>\n") - file.write("}\n") - file.write("#end\n") - # Use the macro - ngon = ob.pov.polytocircle_ngon - ngonR = ob.pov.polytocircle_ngonR - circleR = ob.pov.polytocircle_circleR - tab_write( - "#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n" - % (povdataname, ngon, ngonR, circleR) - ) - tab_write("}\n") - continue # Don't render proxy mesh, skip to next object - - # Implicit else-if (as not skipped by previous "continue") Keep this last. + # Implicit else-if (as not skipped by previous "continue") + # which itself has no "continue" (to combine custom pov code)?, so Keep this last. # For originals, but not their instances, attempt to export mesh: if not ob.is_instancer: # except duplis which should be instances groups for now but all duplis later if ob.type == 'EMPTY': # XXX Should we only write this once and instantiate the same for every - # empty in the final matrix writing, or even no marix and just a comment + # empty in the final matrix writing, or even no matrix and just a comment # with empty object transforms ? tab_write("\n//dummy sphere to represent Empty location\n") tab_write( @@ -730,7 +374,7 @@ def export_meshes( ) continue # Don't render empty object but this is later addition, watch it. - ob_eval = ob # not sure this is needed in case to_mesh_clear could damage ob ? + ob_eval = ob # not sure this is needed in case to_mesh_clear could damage obj ? try: me = ob_eval.to_mesh() @@ -886,7 +530,7 @@ def export_meshes( print('An exception occurred: {}'.format(e)) material = None if ( - material + material ): # and material.use_vertex_color_paint: #Always use vertex color when there is some for now cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops] @@ -953,7 +597,7 @@ def export_meshes( cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops] if ( - not me_materials or me_materials[material_index] is None + not me_materials or me_materials[material_index] is None ): # No materials if linebreaksinlists: file.write(",\n") @@ -1085,21 +729,7 @@ def export_meshes( tab_write("}\n") # XXX BOOLEAN - onceCSG = 0 - for mod in ob.modifiers: - if onceCSG == 0: - if mod: - if mod.type == 'BOOLEAN': - if 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], - ) - ) - onceCSG = 1 + write_object_csg_inside_vector(ob, file) if me.materials: try: @@ -1110,7 +740,7 @@ def export_meshes( # POV object modifiers such as # hollow / sturm / double_illuminate etc. - write_object_modifiers(scene, ob, file) + write_object_modifiers(ob, file) # Importance for radiosity sampling added here: tab_write("radiosity { \n") @@ -1128,7 +758,7 @@ def export_meshes( for i, material in enumerate(me_materials): if ( - material and material.pov.material_use_nodes is False + material and material.pov.material_use_nodes is False ): # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # Multiply diffuse with SSS Color if material.pov_subsurface_scattering.use: @@ -1157,7 +787,7 @@ def export_meshes( vertCols[key] = [-1] idx = 0 - local_material_names = [] #XXX track and revert + local_material_names = [] # XXX track and revert material_finish = None for col, index in vertCols.items(): # if me_materials: @@ -1194,7 +824,7 @@ def export_meshes( else: file.write(tab_str + "%s" % (len(vertCols))) # vert count - # below "material" alias, added check ob.active_material + # below "material" alias, added check obj.active_material # to avoid variable referenced before assignment error try: material = ob.active_material @@ -1204,9 +834,9 @@ def export_meshes( # WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if ( - material - and ob.active_material is not None - and not material.pov.material_use_nodes + material + and ob.active_material is not None + and not material.pov.material_use_nodes ): if material.pov.replacement_text != "": file.write("\n") @@ -1243,7 +873,7 @@ def export_meshes( cols = [vcol_layer[loop_index].color[:] for loop_index in f.loops] if ( - not me_materials or me_materials[material_index] is None + not me_materials or me_materials[material_index] is None ): # No materials if linebreaksinlists: file.write(",\n") @@ -1377,22 +1007,7 @@ def export_meshes( tab_write("}\n") # XXX BOOLEAN - onceCSG = 0 - for mod in ob.modifiers: - if onceCSG == 0: - if mod: - if mod.type == 'BOOLEAN': - if 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], - ) - ) - onceCSG = 1 - + write_object_csg_inside_vector(ob, file) if me.materials: try: material = me.materials[0] # dodgy @@ -1402,7 +1017,7 @@ def export_meshes( # POV object modifiers such as # hollow / sturm / double_illuminate etc. - write_object_modifiers(scene, ob, file) + write_object_modifiers(ob, file) # Importance for radiosity sampling added here: tab_write("radiosity { \n") @@ -1412,15 +1027,426 @@ def export_meshes( tab_write("}\n") # End of mesh block ob_eval.to_mesh_clear() + continue + # ------------ Povray Primitives ------------ # + # Also implicit elif (continue) clauses and sorted after mesh + # as less often used. + if ob.pov.object_as == 'PLANE': + tab_write("#declare %s = plane{ <0,0,1>,0\n" % povdataname) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + # tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'SPHERE': + + tab_write( + "#declare %s = sphere { 0,%6f\n" % (povdataname, ob.pov.sphere_radius) + ) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + # tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'BOX': + tab_write("#declare %s = box { -1,1\n" % povdataname) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + # tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'CONE': + br = ob.pov.cone_base_radius + cr = ob.pov.cone_cap_radius + bz = ob.pov.cone_base_z + cz = ob.pov.cone_cap_z + tab_write( + "#declare %s = cone { <0,0,%.4f>,%.4f,<0,0,%.4f>,%.4f\n" + % (povdataname, bz, br, cz, cr) + ) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + # tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'CYLINDER': + r = ob.pov.cylinder_radius + x2 = ob.pov.cylinder_location_cap[0] + y2 = ob.pov.cylinder_location_cap[1] + z2 = ob.pov.cylinder_location_cap[2] + tab_write( + "#declare %s = cylinder { <0,0,0>,<%6f,%6f,%6f>,%6f\n" + % (povdataname, x2, y2, z2, r) + ) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + # cylinders written at origin, translated below + write_object_modifiers(ob, file) + # tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'HEIGHT_FIELD': + data = "" + filename = ob.pov.hf_filename + data += '"%s"' % filename + gamma = ' gamma %.4f' % ob.pov.hf_gamma + data += gamma + if ob.pov.hf_premultiplied: + data += ' premultiplied on' + if ob.pov.hf_smooth: + data += ' smooth' + if ob.pov.hf_water > 0: + data += ' water_level %.4f' % ob.pov.hf_water + # hierarchy = obj.pov.hf_hierarchy + tab_write('#declare %s = height_field { %s\n' % (povdataname, data)) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + tab_write("rotate x*90\n") + tab_write("translate <-0.5,0.5,0>\n") + tab_write("scale <0,-1,0>\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'TORUS': + tab_write( + "#declare %s = torus { %.4f,%.4f\n" + % (povdataname, ob.pov.torus_major_radius, ob.pov.torus_minor_radius) + ) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'PARAMETRIC': + tab_write("#declare %s = parametric {\n" % povdataname) + tab_write("function { %s }\n" % ob.pov.x_eq) + tab_write("function { %s }\n" % ob.pov.y_eq) + tab_write("function { %s }\n" % ob.pov.z_eq) + tab_write( + "<%.4f,%.4f>, <%.4f,%.4f>\n" + % (ob.pov.u_min, ob.pov.v_min, ob.pov.u_max, ob.pov.v_max) + ) + # Previous to 3.8 default max_gradient 1.0 was too slow + tab_write("max_gradient 0.001\n") + if ob.pov.contained_by == "sphere": + tab_write("contained_by { sphere{0, 2} }\n") + else: + tab_write("contained_by { box{-2, 2} }\n") + tab_write("max_gradient %.6f\n" % ob.pov.max_gradient) + tab_write("accuracy %.6f\n" % ob.pov.accuracy) + tab_write("precompute 10 x,y,z\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'ISOSURFACE_NODE': + tab_write("#declare %s = isosurface{ \n" % povdataname) + tab_write("function{ \n") + text_name = ob.pov.iso_function_text + if text_name: + node_tree = bpy.context.scene.node_tree + for node in node_tree.nodes: + if node.bl_idname == "IsoPropsNode" and node.label == ob.name: + for inp in node.inputs: + if inp: + tab_write( + "#declare %s = %.6g;\n" % (inp.name, inp.default_value) + ) + + text = bpy.data.texts[text_name] + for line in text.lines: + split = line.body.split() + if split[0] != "#declare": + tab_write("%s\n" % line.body) + else: + tab_write("abs(x) - 2 + y") + tab_write("}\n") + tab_write("threshold %.6g\n" % ob.pov.threshold) + tab_write("max_gradient %.6g\n" % ob.pov.max_gradient) + tab_write("accuracy %.6g\n" % ob.pov.accuracy) + tab_write("contained_by { ") + if ob.pov.contained_by == "sphere": + tab_write("sphere {0,%.6g}}\n" % ob.pov.container_scale) + else: + tab_write( + "box {-%.6g,%.6g}}\n" % (ob.pov.container_scale, ob.pov.container_scale) + ) + if ob.pov.all_intersections: + tab_write("all_intersections\n") + else: + if ob.pov.max_trace > 1: + tab_write("max_trace %.6g\n" % ob.pov.max_trace) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + tab_write("scale %.6g\n" % (1 / ob.pov.container_scale)) + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'ISOSURFACE_VIEW': + simple_isosurface_function = ob.pov.isosurface_eq + if simple_isosurface_function: + tab_write("#declare %s = isosurface{ \n" % povdataname) + tab_write("function{ \n") + tab_write(simple_isosurface_function) + tab_write("}\n") + tab_write("threshold %.6g\n" % ob.pov.threshold) + tab_write("max_gradient %.6g\n" % ob.pov.max_gradient) + tab_write("accuracy %.6g\n" % ob.pov.accuracy) + tab_write("contained_by { ") + if ob.pov.contained_by == "sphere": + tab_write("sphere {0,%.6g}}\n" % ob.pov.container_scale) + else: + tab_write( + "box {-%.6g,%.6g}}\n" % (ob.pov.container_scale, ob.pov.container_scale) + ) + if ob.pov.all_intersections: + tab_write("all_intersections\n") + else: + if ob.pov.max_trace > 1: + tab_write("max_trace %.6g\n" % ob.pov.max_trace) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + tab_write("scale %.6g\n" % (1 / ob.pov.container_scale)) + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'SUPERELLIPSOID': + tab_write( + "#declare %s = superellipsoid{ <%.4f,%.4f>\n" + % (povdataname, ob.pov.se_n2, ob.pov.se_n1) + ) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'SUPERTORUS': + rad_maj = ob.pov.st_major_radius + rad_min = ob.pov.st_minor_radius + ring = ob.pov.st_ring + cross = ob.pov.st_cross + accuracy = ob.pov.st_accuracy + gradient = ob.pov.st_max_gradient + # --- Inline Supertorus macro + file.write( + "#macro Supertorus(RMj, RMn, MajorControl, MinorControl, Accuracy, MaxGradient)\n" + ) + file.write(" #local CP = 2/MinorControl;\n") + file.write(" #local RP = 2/MajorControl;\n") + file.write(" isosurface {\n") + file.write( + " function { pow( pow(abs(pow(pow(abs(x),RP) + pow(abs(z),RP), 1/RP) - RMj),CP) + pow(abs(y),CP) ,1/CP) - RMn }\n" + ) + file.write(" threshold 0\n") + file.write( + " contained_by {box {<-RMj-RMn,-RMn,-RMj-RMn>, < RMj+RMn, RMn, RMj+RMn>}}\n" + ) + file.write(" #if(MaxGradient >= 1)\n") + file.write(" max_gradient MaxGradient\n") + file.write(" #else\n") + file.write(" evaluate 1, 10, 0.1\n") + file.write(" #end\n") + file.write(" accuracy Accuracy\n") + file.write(" }\n") + file.write("#end\n") + # --- + tab_write( + "#declare %s = object{ Supertorus( %.4g,%.4g,%.4g,%.4g,%.4g,%.4g)\n" + % (povdataname, rad_maj, rad_min, ring, cross, accuracy, gradient) + ) + if ob.active_material: + # pov_mat_name = string_strip_hyphen(bpy.path.clean_name(obj.active_material.name)) + try: + material = ob.active_material + write_object_material_interior(material, ob, tab_write) + except IndexError: + print(me) + # tab_write("texture {%s}\n"%pov_mat_name) + write_object_modifiers(ob, file) + tab_write("rotate x*90\n") + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object + + if ob.pov.object_as == 'POLYCIRCLE': + # TODO write below macro Once: + # if write_polytocircle_macro_once == 0: + file.write("/****************************\n") + file.write("This macro was written by 'And'.\n") + file.write("Link:(http://news.povray.org/povray.binaries.scene-files/)\n") + file.write("****************************/\n") + file.write("//from math.inc:\n") + file.write("#macro VPerp_Adjust(V, Axis)\n") + file.write(" vnormalize(vcross(vcross(Axis, V), Axis))\n") + file.write("#end\n") + file.write("//Then for the actual macro\n") + file.write("#macro Shape_Slice_Plane_2P_1V(point1, point2, clip_direct)\n") + file.write("#local p1 = point1 + <0,0,0>;\n") + file.write("#local p2 = point2 + <0,0,0>;\n") + file.write("#local clip_v = vnormalize(clip_direct + <0,0,0>);\n") + file.write("#local direct_v1 = vnormalize(p2 - p1);\n") + file.write("#if(vdot(direct_v1, clip_v) = 1)\n") + file.write(' #error "Shape_Slice_Plane_2P_1V error: Can\'t decide plane"\n') + file.write("#end\n\n") + file.write( + "#local norm = -vnormalize(clip_v - direct_v1*vdot(direct_v1,clip_v));\n" + ) + file.write("#local d = vdot(norm, p1);\n") + file.write("plane{\n") + file.write("norm, d\n") + file.write("}\n") + file.write("#end\n\n") + file.write("//polygon to circle\n") + file.write( + "#macro Shape_Polygon_To_Circle_Blending(_polygon_n, _side_face, _polygon_circumscribed_radius, _circle_radius, _height)\n" + ) + file.write("#local n = int(_polygon_n);\n") + file.write("#if(n < 3)\n") + file.write(" #error " "\n") + file.write("#end\n\n") + file.write("#local front_v = VPerp_Adjust(_side_face, z);\n") + file.write("#if(vdot(front_v, x) >= 0)\n") + file.write(" #local face_ang = acos(vdot(-y, front_v));\n") + file.write("#else\n") + file.write(" #local face_ang = -acos(vdot(-y, front_v));\n") + file.write("#end\n") + file.write("#local polyg_ext_ang = 2*pi/n;\n") + file.write("#local polyg_outer_r = _polygon_circumscribed_radius;\n") + file.write("#local polyg_inner_r = polyg_outer_r*cos(polyg_ext_ang/2);\n") + file.write("#local cycle_r = _circle_radius;\n") + file.write("#local h = _height;\n") + file.write("#if(polyg_outer_r < 0 | cycle_r < 0 | h <= 0)\n") + file.write(' #error "error: each side length must be positive"\n') + file.write("#end\n\n") + file.write("#local multi = 1000;\n") + file.write("#local poly_obj =\n") + file.write("polynomial{\n") + file.write("4,\n") + file.write("xyz(0,2,2): multi*1,\n") + file.write("xyz(2,0,1): multi*2*h,\n") + file.write("xyz(1,0,2): multi*2*(polyg_inner_r-cycle_r),\n") + file.write("xyz(2,0,0): multi*(-h*h),\n") + file.write("xyz(0,0,2): multi*(-pow(cycle_r - polyg_inner_r, 2)),\n") + file.write("xyz(1,0,1): multi*2*h*(-2*polyg_inner_r + cycle_r),\n") + file.write("xyz(1,0,0): multi*2*h*h*polyg_inner_r,\n") + file.write("xyz(0,0,1): multi*2*h*polyg_inner_r*(polyg_inner_r - cycle_r),\n") + file.write("xyz(0,0,0): multi*(-pow(polyg_inner_r*h, 2))\n") + file.write("sturm\n") + file.write("}\n\n") + file.write("#local mockup1 =\n") + file.write("difference{\n") + file.write(" cylinder{\n") + file.write(" <0,0,0.0>,<0,0,h>, max(polyg_outer_r, cycle_r)\n") + file.write(" }\n\n") + file.write(" #for(i, 0, n-1)\n") + file.write(" object{\n") + file.write(" poly_obj\n") + file.write(" inverse\n") + file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n") + file.write(" }\n") + file.write(" object{\n") + file.write( + " Shape_Slice_Plane_2P_1V(<polyg_inner_r,0,0>,<cycle_r,0,h>,x)\n" + ) + file.write(" rotate <0, 0, -90 + degrees(polyg_ext_ang*i)>\n") + file.write(" }\n") + file.write(" #end\n") + file.write("}\n\n") + file.write("object{\n") + file.write("mockup1\n") + file.write("rotate <0, 0, degrees(face_ang)>\n") + file.write("}\n") + file.write("#end\n") + # Use the macro + ngon = ob.pov.polytocircle_ngon + ngonR = ob.pov.polytocircle_ngonR + circleR = ob.pov.polytocircle_circleR + tab_write( + "#declare %s = object { Shape_Polygon_To_Circle_Blending(%s, z, %.4f, %.4f, 2) rotate x*180 translate z*1\n" + % (povdataname, ngon, ngonR, circleR) + ) + tab_write("}\n") + continue # Don't render proxy mesh, skip to next object if csg: duplidata_ref = [] _dupnames_seen = dict() # avoid duplicate output during introspection for ob in sel: - # matrix = global_matrix @ ob.matrix_world + # matrix = global_matrix @ obj.matrix_world if ob.is_instancer: tab_write("\n//--DupliObjects in %s--\n\n" % ob.name) - # ob.dupli_list_create(scene) #deprecated in 2.8 + # obj.dupli_list_create(scene) #deprecated in 2.8 dup = "" if ob.is_modified(scene, 'RENDER'): # modified object always unique so using object name rather than data name @@ -1433,7 +1459,7 @@ def export_meshes( ) for eachduplicate in depsgraph.object_instances: if ( - eachduplicate.is_instance + eachduplicate.is_instance ): # Real dupli instance filtered because original included in list since 2.8 _dupname = eachduplicate.object.name _dupobj = bpy.data.objects[_dupname] @@ -1450,7 +1476,7 @@ def export_meshes( % (_dupname, _thing, getattr(_dupobj, _thing)) ) _dupnames_seen[_dupname] = 1 - print("''=> Unparseable objects so far: %s" % (_dupnames_seen)) + print("''=> Unparseable objects so far: %s" % _dupnames_seen) else: _dupnames_seen[_dupname] += 1 continue # don't try to parse data objects with no name attribute @@ -1467,19 +1493,21 @@ def export_meshes( ) # add object to a list so that it is not rendered for some instance_types if ( - ob.instance_type not in {'COLLECTION'} - and duplidataname not in duplidata_ref + ob.instance_type not in {'COLLECTION'} + and duplidataname not in duplidata_ref ): duplidata_ref.append( duplidataname - ) # older key [string_strip_hyphen(bpy.path.clean_name("OB"+ob.name))] + ) # older key [string_strip_hyphen(bpy.path.clean_name("OB"+obj.name))] dup += "}\n" - # ob.dupli_list_clear()# just do not store any reference to instance since 2.8 + # obj.dupli_list_clear()# just do not store any reference to instance since 2.8 tab_write(dup) else: continue - print("WARNING: Unparseable objects in current .blend file:\n''=> %s" % (_dupnames_seen)) - print("duplidata_ref = %s" % (duplidata_ref)) + if _dupnames_seen: + print("WARNING: Unparseable objects in current .blend file:\n''--> %s" % _dupnames_seen) + if duplidata_ref: + print("duplidata_ref = %s" % duplidata_ref) for data_name, inst in data_ref.items(): for ob_name, matrix_str in inst: if ob_name not in duplidata_ref: # .items() for a dictionary |