0
$\begingroup$

Before exporting to FBX I modify the object's name, location, parent, etc.

All the exporting happens in a for loop of selected objects.

So I need to restore it after every export.

Example script:

import bpy
from bpy import context
import os
import random


filepath = "C:/Users/karan/Desktop/"

override = context.copy()


for object in context.selected_objects:
    # It's a simple modification, but I will have some complex modifications.
    object.location = (random.random(), random.random(), random.random())
    
    # export
    override['selected_objects'] = [object]
    with context.temp_override(**override):
        bpy.ops.export_scene.fbx(filepath=os.path.join(filepath, f"{object.name}.fbx"), check_existing=False, use_selection=True)
        
    # restore
    bpy.ops.wm.revert_mainfile()

I get this error

ReferenceError: StructRNA of type Object has been removed

How to fix this?

And how to add a progress bar while exporting?

enter image description here

import bpy
import os
import random


class EXPORT_OT_export_fbx(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "export.fbx"
    bl_label = "Export FBX"


    def execute(self, context):
        filepath = "C:/Users/karan/Desktop/"
        names = [obj.name for obj in context.selected_objects]

        for name in names:
            object = bpy.data.objects[name]
            object.location = (random.random(), random.random(), random.random())

            override = bpy.context.copy()
            override['selected_objects'] = [object]
            with context.temp_override(**override):
                bpy.ops.export_scene.fbx(filepath=os.path.join(filepath, f"{object.name}.fbx"), use_selection=True)

            # restore
            bpy.ops.wm.revert_mainfile()

        return {'FINISHED'}
    

class EXPORT_PT_export_fbx(bpy.types.Panel):
    bl_label = "Export"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Export"

    def draw(self, context):
        layout = self.layout
        
        if context.scene.export_progress >= 0:
            layout.enabled = False
            layout.prop(context.scene, 'export_progress', slider=True)
        else:
            layout.operator("export.fbx")


def register():
    bpy.utils.register_class(EXPORT_OT_export_fbx)
    bpy.utils.register_class(EXPORT_PT_export_fbx)
    
    bpy.types.Scene.export_progress = bpy.props.IntProperty(name = 'Exporting...', subtype = 'PERCENTAGE', min = -1, soft_min = 0, soft_max = 100, max = 100, default = -1)


def unregister():
    bpy.utils.unregister_class(EXPORT_OT_export_fbx)
    bpy.utils.unregister_class(EXPORT_PT_export_fbx)
    
    del bpy.types.Scene.export_progress


if __name__ == "__main__":
    register()
$\endgroup$
9
  • $\begingroup$ After restore, you will get ReferenceError on some pointer, see: blender.stackexchange.com/questions/268787/… $\endgroup$
    – X Y
    Commented Jul 1, 2023 at 2:51
  • $\begingroup$ I don't want to use the undo system. $\endgroup$
    – Karan
    Commented Jul 1, 2023 at 3:01
  • $\begingroup$ This post can explain why the ReferneceError occurs, so just put object = bpy.data.objects.get('Cube') in the forloop to fix that. override also need. $\endgroup$
    – X Y
    Commented Jul 1, 2023 at 3:18
  • $\begingroup$ I want to loop over context.selected_objects, I updated my question. $\endgroup$
    – Karan
    Commented Jul 1, 2023 at 3:31
  • $\begingroup$ @XY how to add progress bar while exporting? $\endgroup$
    – Karan
    Commented Jul 1, 2023 at 5:04

1 Answer 1

2
$\begingroup$

This should work, if not tell me I'll fix it

import bpy
from bpy import context
import os
import random


filepath = "C:/Users/karan/Desktop/"
names = [obj.name for obj in context.selected_objects]

for name in names:
    object = bpy.data.objects[name]
    object.name += ".fbx"
    object.location = (random.random(), random.random(), random.random())

    override = bpy.context.copy()
    override['selected_objects'] = [object]
    with context.temp_override(**override):
        bpy.ops.export_scene.fbx(filepath=os.path.join(filepath, object.name), check_existing=False, use_selection=True)

    # restore
    bpy.ops.wm.revert_mainfile()

To show the progress after reloading the blend file, you can refer to this

import bpy
import os
import random
from bpy.app.handlers import persistent

is_button_press = [False]
data = {}

@persistent
def when_new_file(dummy):
    print("new file detected")
    do_job()

def init_job():
    print("init job")
    data["job_ind"] = 0
    data["job_ind_end"] = 100
    bpy.context.scene.export_progress = 0
    bpy.app.handlers.load_post.append(when_new_file)
    bpy.ops.wm.revert_mainfile()

def do_job():
    print("do_job, ind= ", data["job_ind"])
    # do something you want here

    if data["job_ind"] == data["job_ind_end"]:
        end_job()
    else:
        bpy.app.timers.register(next_job)

def next_job():
    data["job_ind"] += 1
    bpy.ops.wm.revert_mainfile()
    if "job_ind" in data:
        bpy.context.scene.export_progress = data["job_ind"] * 100 // (data["job_ind_end"] + 1)

def end_job():
    print("job done")
    bpy.app.handlers.load_post.remove(when_new_file)
    is_button_press[0] = False
    data.clear()
    bpy.context.scene.export_progress = -1
    bpy.ops.wm.revert_mainfile()
    

class Progress_test(bpy.types.Operator):
    bl_idname = "wm.test"
    bl_label = "Progress_test"

    # not possible running in operator using forloop
    # because after running bpy.ops.wm.revert_mainfile(), operator cannot access, blender will crash
    def execute(self, context):
        if not is_button_press[0]:
            is_button_press[0] = True
            bpy.app.timers.register(init_job)
        return {'FINISHED'}


class TEST_PT_PANEL(bpy.types.Panel):
    bl_label = "Test Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Item"

    def draw(self, context):
        layout = self.layout

        if is_button_press[0]:
            layout.enabled = False
            layout.prop(context.scene, 'export_progress', slider=True)
        else:
            layout.operator("wm.test")


def register():
    bpy.utils.register_class(Progress_test)
    bpy.utils.register_class(TEST_PT_PANEL)
    
    bpy.types.Scene.export_progress = bpy.props.IntProperty(name = 'Exporting...', subtype = 'PERCENTAGE', min = -1, soft_min = 0, soft_max = 100, max = 100, default = -1)


def unregister():
    bpy.utils.unregister_class(Progress_test)
    bpy.utils.unregister_class(TEST_PT_PANEL)
    
    del bpy.types.Scene.export_progress


if __name__ == "__main__":
    register()

enter image description here

After you testing above script, change the init_job and do_job function

filepath = "..."

def init_job():
    print("init job")
    data["job_ind"] = 0
    data["names"] = [obj.name for obj in bpy.context.selected_objects]
    data["job_ind_end"] = len(data["names"]) - 1
    bpy.context.scene.export_progress = 0
    bpy.app.handlers.load_post.append(when_new_file)
    bpy.ops.wm.revert_mainfile()

def do_job():
    print("do_job, ind= ", data["job_ind"])
    
    name = data["names"][data["job_ind"]]
    object = bpy.data.objects[name]
    object.location = (random.random(), random.random(), random.random())

    override = bpy.context.copy()
    override['selected_objects'] = [object]
    with bpy.context.temp_override(**override):
        bpy.ops.export_scene.fbx(filepath=os.path.join(filepath, f"{object.name}.fbx"), use_selection=True)

    if data["job_ind"] == data["job_ind_end"]:
        end_job()
    else:
        bpy.app.timers.register(next_job)
$\endgroup$
17
  • $\begingroup$ It works but will it work in a background instance? $\endgroup$
    – Karan
    Commented Jul 1, 2023 at 4:01
  • $\begingroup$ background instance? Do you mean allow the user modify the scene when exporting? $\endgroup$
    – X Y
    Commented Jul 1, 2023 at 4:07
  • $\begingroup$ No, I will run the blender instance in the background using subprocess.Popon(). In the background this exporting will happen. $\endgroup$
    – Karan
    Commented Jul 1, 2023 at 4:09
  • 1
    $\begingroup$ Not sure, you need test it. I guess it can't because you need wait to restore the file. $\endgroup$
    – X Y
    Commented Jul 1, 2023 at 4:16
  • $\begingroup$ Can you implement the wait to restore the file in your answer? $\endgroup$
    – Karan
    Commented Jul 1, 2023 at 4:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .