Последовательный импорт файлов .obj очень быстро становится очень медленным

Я написал очень простой скрипт, который импортирует множество файлов obj один за другим и отображает их. Импортированные сетки имеют от ~10k до ~120k вершин. После рендеринга я полностью удаляю импортированный меш (вместе с его блоками данных) перед импортом следующего. Однако по мере выполнения цикла for процедура импорта становится чрезвычайно медленной. Я заметил, что функция импорта начинает вести себя странно, и импорт объектов занимает много времени. Я не уверен, почему это происходит. Первоначально я думал, что это вызвано проблемами с памятью, но я думаю, что удаление блоков данных должно устранить утечку памяти. Это происходит даже без выполнения какого-либо рендеринга или каких-либо операций с импортированными объектами. Вот пример того, что печатает функция импорта при импорте меша:

(  0.0002 sec |   0.0002 sec) Importing OBJ '/data/e1f2651d55aecd7d8f2b6fca0ec9a39dn7a9/models/model.obj'...
(  0.0308 sec |   0.0306 sec) Parsing OBJ file...
(  1.8534 sec |   1.8511 sec) Done, loading materials and images...
(  2.0450 sec |   2.0426 sec) Done, building geometries (verts:72707 faces:137005 materials: 44 smoothgroups:0) ...
(  5.4944 sec |   5.4921 sec) Done.
(  5.4946 sec |   5.4945 sec) Finished importing: 'data/e1f2651d55aecd7d8f2b6fca0ec9a39dn7a9/models/model.obj'
Progress: 100.00%

По мере импорта большего количества объектов функция импорта работает все медленнее и медленнее, даже для более простых форм (например, ~ 12 тыс. вершин) вы получите что-то вроде этого:

(  0.0002 sec |   0.0002 sec) Importing OBJ '/data/jjgd2e3f46f7cc1e8ba69a5e14689f7b974/models/model.obj'...
  (  0.0266 sec |   0.0263 sec) Parsing OBJ file...
    (  0.7060 sec |   0.6793 sec) Done, loading materials and images...
    (  3.0993 sec |   3.0726 sec) Done, building geometries (verts:12668 faces:43914 materials: 28 smoothgroups:0) ...
    ( 18.6672 sec |  18.6405 sec) Done.
  ( 18.6673 sec |  18.6671 sec) Finished importing: '/data/jjgd2e3f46f7cc1e8ba69a5e14689f7b974/models/model.obj'
Progress: 100.00%

Однако, если сначала импортируется тот же объект с ~ 12 тыс. вершин, я получаю следующее:

(  0.0001 sec |   0.0001 sec) Importing OBJ '/data/jjgd2e3f46f7cc1e8ba69a5e14689f7b974/models/model.obj'...
  (  0.0025 sec |   0.0023 sec) Parsing OBJ file...
    (  0.5541 sec |   0.5516 sec) Done, loading materials and images...
    (  0.5572 sec |   0.5547 sec) Done, building geometries (verts:12668 faces:43914 materials: 28 smoothgroups:0) ...
    (  1.0660 sec |   1.0635 sec) Done.
  (  1.0663 sec |   1.0662 sec) Finished importing: '/data/jjgd2e3f46f7cc1e8ba69a5e14689f7b974/models/model.obj'
Progress: 100.00%

Вот мой код:

#blenderClass.py
import bpy, math, timeit
import numpy as np

class Blender(object):
    def __init__(self):
        self.bpy = bpy
        self.scene = self.bpy.context.scene
        self.scene.render.use_sequencer = False

        # Some memory management
        self.scene.render.use_free_image_textures = True
        self.bpy.context.user_preferences.edit.undo_steps = 0
        self.bpy.context.user_preferences.edit.undo_memory_limit = 60
        self.bpy.context.user_preferences.edit.use_global_undo = False

    def setupScene(self):
        self.removeCamera()
        self.removeMesh()
        self.bpy.ops.object.camera_add(location=tuple(1, -0.5, 0.3))
        self.pointObjTo(self.scene.objects.active, (0.0, 0.0, 0.0)) # My objects are all centered on (0, 0, 0)

    def render(self, objPath):
        self.bpy.ops.import_scene.obj(filepath=objPath)
        self.removeMesh()
        self.removeDataBlocks()


    def removeDataBlocks(self, removeAll=False):
        # Removes unlinked data blocks and prevents memory leakage

        for block in self.bpy.data.meshes:
            if block.users == 0:
                self.bpy.data.meshes.remove(block)

        for block in self.bpy.data.materials:
            if block.users == 0:
                self.bpy.data.materials.remove(block)

        for block in self.bpy.data.textures:
            if block.users == 0:
                self.bpy.data.textures.remove(block)

        for block in self.bpy.data.images:
            if block.users == 0:
                self.bpy.data.images.remove(block)


    def removeMesh(self, layer = -1):
        for obj in self.scene.objects:
            if obj.type == 'MESH':
                obj.select = True
            else:
                obj.select = False
        self.bpy.ops.object.delete()


    def removeCamera(self):
        for obj in self.scene.objects:
            if obj.type == 'CAMERA':
                obj.select = True
            else:
                obj.select = False
        self.bpy.ops.object.delete()


    def pointObjTo(self, obj, xyzTarget):
        # This function operates directly on the input object (obj)
        from mathutils import Vector
        xyzTarget = Vector(xyzTarget)
        direction = xyzTarget - obj.location
        rot_quat = direction.to_track_quat('-Z', 'Y')
        obj.rotation_euler = rot_quat.to_euler()

И вот как я запускаю код:

#main.py
import blenderClass import Blender
blender = Blender()
blender.setupScene()

objPaths = ['obj1.obj', 'obj2.obj', 'obj3.obj', 'obj4.obj']

for objPath in objPaths:
    blender.render(objPath)

К сожалению, я не могу точно отслеживать системные ресурсы (я запускаю это на сервере), но я боюсь, что функция импорта не отпускает некоторые ресурсы или каким-то образом память заполняется. Я попытался импортировать много фигур в Blender на своем настольном компьютере и выполнил функцию удаления блока данных после удаления мешей вручную. Я предполагаю, что это снижает потребление памяти примерно до 10 МБ, даже если это было 400 МБ, когда я импортирую много 3D-фигур. Если вы хотите попробовать приведенный выше код, возможно, простым решением будет использование примитивных форм, таких как сферы, кубы и т. д., и их подразделение так, чтобы у них было много вершин (возможно, ~ 50-70 тыс. ) и сохраните их как obj. Я думаю, что около 10-15 файлов obj должны работать. Все начинает замедляться довольно быстро после импорта третьего или четвертого объекта для меня.

Я не уверен, связано ли это, но то, как я вызываю функции Blender, не вызывает их в фон. Вместо этого я вручную скомпилировал Blender 2.79 как модуль Python и импортировал его API через import bpy в Python, установленный на моей машине.

Хотя я вполне уверен, что удаление блоков данных освобождает память, но я также пытался использовать сборщик мусора Python, и это не помогает.

Кто-нибудь знает, что я могу делать неправильно? Я очень смущен ...


person Amir    schedule 04.03.2018    source источник
comment
как вручную скомпилировать блендер как пакет python?   -  person bgenchel    schedule 12.05.2019


Ответы (1)


Хотя это странно, но похоже, что функция импорта делает некоторые вещи, которые вызывают замедление в долгосрочной перспективе, если я не импортирую объект с включенным флагом. Таким образом, замена строки импорта объекта на следующую решит проблему:

self.bpy.ops.import_scene.obj(filepath=objPath, split_mode="OFF")

Однако я бы предпочел ввести непересекающийся объект, но на данный момент это решает проблему замедления импорта. Благодаря doublebishop на blenderartists.

person Amir    schedule 05.03.2018