Example #1
0
    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')
Example #2
0
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
Example #3
0
    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)
Example #4
0
    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)