Я написал очень простой скрипт, который импортирует множество файлов 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, и это не помогает.
Кто-нибудь знает, что я могу делать неправильно? Я очень смущен ...