def write_image_texture(image): image_id = unique_name(image, IM_ + image.name, uuid_cache_image, clean_func=slugify, sep='_') if image.tag: fw('texture USE %s\n' % (image_id)) else: image.tag = True fw('texture ') fw('DEF %s ' % image_id) fw('ImageTexture {\n') # Collect image paths, can load multiple [relative, name-only, absolute] filepath = image.filepath filepath_full = bpy.path.abspath(filepath, library=image.library) filepath_ref = bpy_extras.io_utils.path_reference(filepath_full, base_src, base_dst, path_mode, 'textures', copy_set, image.library) filepath_base = os.path.basename(filepath_full) images = [ filepath_ref, filepath_base, ] if path_mode != 'RELATIVE': images.append(filepath_full) images = [f.replace('\\', '/') for f in images] images = [f for i, f in enumerate(images) if f not in images[:i]] fw('url [ "%s" ]\n' % ' '.join(['"%s"' % escape(f) for f in images])) fw('}\n')
def make_unique_name(obj, name, sep="."): """ Takes any object of target type and a name and returns its unique name. :param obj: :param name: :param sep: :return: """ from bpy_extras.io_utils import unique_name # CUSTOM FUNCTION FOR UNIQUE NAMES new_name = really_make_the_unique_name(name, sep) # NOTE: Blender's "unique_name" function doesn't make the names unique # for a reason unknown to me, but it can make the names without # unwanted characters and restrict it to the correct length. new_name = unique_name( obj, new_name, {}, name_max=-1, clean_func=None, sep=sep, ) return new_name
def export_object(obj_main_parent, obj_main, obj_children): """Export Object Hierarchy (recursively called).""" matrix_fallback = mathutils.Matrix() world = scene.world free, derived = create_derived_objects(scene, obj_main) obj_main_matrix_world = obj_main.matrix_world if obj_main_parent: obj_main_matrix = obj_main_parent.matrix_world.inverted(matrix_fallback) * obj_main_matrix_world else: obj_main_matrix = obj_main_matrix_world obj_main_matrix_world_invert = obj_main_matrix_world.inverted(matrix_fallback) obj_main_id = unique_name(obj_main, obj_main.name, uuid_cache_object, clean_func=slugify, sep='_') (skipUselessTransform, supplementaryCurvyBracket) = write_transform_begin(obj_main, obj_main_matrix if obj_main_parent else global_matrix * obj_main_matrix, obj_main_id) for obj, obj_matrix in (() if derived is None else derived): obj_type = obj.type obj_matrix = obj_main_matrix_world_invert * obj_matrix # Make transform node relative. if obj_type in {'MESH', 'CURVE', 'SURFACE', 'FONT'}: if (obj_type != 'MESH') or (use_mesh_modifiers and obj.is_modified(scene, 'PREVIEW')): me = obj.to_mesh(scene, use_mesh_modifiers, 'PREVIEW') do_remove = True else: me = obj.data do_remove = False if me is not None: # ensure unique name, we could also do this by # postponing mesh removal, but clearing data - TODO if do_remove: me.name = obj.name.rstrip('1234567890').rstrip('.') me_name_new = me_name_org = me.name count = 0 while me_name_new in mesh_name_set: me.name = '%.17s.%03d' % (me_name_org, count) me_name_new = me.name count += 1 mesh_name_set.add(me_name_new) del me_name_new, me_name_org, count write_indexed_face_set(obj, me, obj_matrix, world) # Rree mesh created with create_mesh() if do_remove: bpy.data.meshes.remove(me) else: # print('Info: Ignoring [%s], object type [%s] not handle yet' % (object.name,object.getType)) pass if free: free_derived_objects(obj_main) # Write out children recursively for obj_child, obj_child_children in obj_children: export_object(obj_main, obj_child, obj_child_children) if not skipUselessTransform: write_transform_end(supplementaryCurvyBracket)
def write_indexed_face_set(obj, mesh, matrix, world): obj_id = unique_name(obj, OB_ + obj.name, uuid_cache_object, clean_func=slugify, sep='_') mesh_id = unique_name(mesh, ME_ + mesh.name, uuid_cache_mesh, clean_func=slugify, sep='_') mesh_id_group = GROUP_ + mesh_id mesh_id_coords = COORDS_ + mesh_id # Tessellation faces may not exist. if not mesh.tessfaces and mesh.polygons: mesh.update(calc_tessface=True) if not mesh.tessfaces: return # Use _IFS_TRANSFORM suffix so we dont collide with transform node when hierarchys are used. (skipUselessTransform, supplementaryCurvyBracket) = write_transform_begin(obj, matrix, obj_id + _IFS + _TRANSFORM) if mesh.tag: fw('USE %s\n' % (mesh_id_group)) else: mesh.tag = True is_uv = bool(mesh.tessface_uv_textures.active) is_coords_written = False mesh_materials = mesh.materials[:] if not mesh_materials: mesh_materials = [None] mesh_material_tex = [None] * len(mesh_materials) mesh_material_mtex = [None] * len(mesh_materials) mesh_material_images = [None] * len(mesh_materials) for i, material in enumerate(mesh_materials): if material: for mtex in material.texture_slots: if mtex: tex = mtex.texture if tex and tex.type == 'IMAGE': image = tex.image if image: mesh_material_tex[i] = tex mesh_material_mtex[i] = mtex mesh_material_images[i] = image break mesh_materials_use_face_texture = [getattr(material, 'use_face_texture', True) for material in mesh_materials] mesh_faces = mesh.tessfaces[:] mesh_faces_materials = [f.material_index for f in mesh_faces] mesh_faces_vertices = [f.vertices[:] for f in mesh_faces] if is_uv and True in mesh_materials_use_face_texture: mesh_faces_image = [ (fuv.image if mesh_materials_use_face_texture[mesh_faces_materials[i]] else mesh_material_images[mesh_faces_materials[i]]) for i, fuv in enumerate(mesh.tessface_uv_textures.active.data) ] mesh_faces_image_unique = set(mesh_faces_image) elif len(set(mesh_material_images) | {None}) > 1: # Make sure there is at least one image mesh_faces_image = [mesh_material_images[material_index] for material_index in mesh_faces_materials] mesh_faces_image_unique = set(mesh_faces_image) else: mesh_faces_image = [None] * len(mesh_faces) mesh_faces_image_unique = {None} # Group faces. face_groups = {} for material_index in range(len(mesh_materials)): for image in mesh_faces_image_unique: face_groups[material_index, image] = [] del mesh_faces_image_unique for i, (material_index, image) in enumerate(zip(mesh_faces_materials, mesh_faces_image)): face_groups[material_index, image].append(i) # Same as face_groups.items() but sorted so we can get predictable output. face_groups_items = list(face_groups.items()) face_groups_items.sort(key=lambda m: (m[0][0], getattr(m[0][1], 'name', ''))) for (material_index, image), face_group in face_groups_items: # face_groups.items() if face_group: material = mesh_materials[material_index] fw('Shape {\n') is_smooth = False for i in face_group: if mesh_faces[i].use_smooth: is_smooth = True break material_def_name = slugify(material.name) if material_def_name in conversion_data and 'target node' in conversion_data[material_def_name]: fw('appearance %s {\n' % (conversion_data[material_def_name]['target node'])) fw('}\n') else: fw('appearance DEF %s PBRAppearance {\n' % (material_def_name)) if image: write_image_texture(image) if material: diffuse = material.diffuse_color[:] ambient = ((material.ambient * 2.0) * world.ambient_color)[:] if world else [0.0, 0.0, 0.0] emissive = tuple(((c * material.emit) + ambient[i]) / 2.0 for i, c in enumerate(diffuse)) fw('baseColor %.6g %.6g %.6g\n' % clamp_color(diffuse)) fw('emissiveColor %.6g %.6g %.6g\n' % clamp_color(emissive)) fw('metalness 0\n') fw('roughness 0.5\n') fw('}\n') # -- PBRAppearance mesh_faces_uv = mesh.tessface_uv_textures.active.data if is_uv else None fw('geometry IndexedFaceSet {\n') if is_smooth: # use Auto-Smooth angle, if enabled. Otherwise make # the mesh perfectly smooth by creaseAngle > pi. fw('creaseAngle %.6g\n' % (mesh.auto_smooth_angle if mesh.use_auto_smooth else 1.0)) # for IndexedTriangleSet we use a uv per vertex so this isnt needed. if is_uv: fw('texCoordIndex [\n') j = 0 for i in face_group: if len(mesh_faces_vertices[i]) == 4: fw('%d %d %d %d -1 ' % (j, j + 1, j + 2, j + 3)) j += 4 else: fw('%d %d %d -1 ' % (j, j + 1, j + 2)) j += 3 fw('\n') fw(']\n') if True: fw('coordIndex [\n') for i in face_group: fv = mesh_faces_vertices[i] if len(fv) == 3: fw('%i %i %i -1 ' % fv) else: fw('%i %i %i %i -1 ' % fv) fw('\n') fw(']\n') if True: if is_coords_written: fw('coord USE %s\n' % (mesh_id_coords)) else: fw('coord ') fw('DEF %s ' % mesh_id_coords) fw('Coordinate {\n') fw('point [\n') for v in mesh.vertices: fw('%.6g %.6g %.6g ' % v.co[:]) fw('\n') fw(']\n') fw('}\n') is_coords_written = True if is_uv: fw('texCoord TextureCoordinate {\n') fw('point [\n') for i in face_group: for uv in mesh_faces_uv[i].uv: fw('%.6g %.6g ' % uv[:]) del mesh_faces_uv fw('\n') fw(']\n') fw('}\n') fw('}\n') # --- IndexedFaceSet fw('}\n') # --- Shape if not skipUselessTransform: write_transform_end(supplementaryCurvyBracket)