'Configuring Blender Python Module to Run Headlessly

I created a script within blender to voxelize an .obj model, uv map it, and reduce the colour of each voxel face to a singular tone. The script runs fine inside blender itself.

When I switch over to the uv_editor within blender to scale down the uv mesh so that the voxel face has a singular colour, this isn't recognized outside of blender because it runs headlessly (no gui) so it has no concept of what uv_editor is.

I have been at this for weeks and I cannot find any workaround for this one portion of the code. Please help me out with any alternative you might have.

import bpy
import os

removeThese = bpy.context.copy()
removeThese['selected_objects'] = list(bpy.context.scene.objects)
bpy.ops.object.delete(removeThese)

sourceDirectory = "model_folder"
model_name = "model.obj"

path = os.path.join(sourceDirectory, model_name)

bpy.ops.import_scene.obj(filepath=path, axis_forward='-Z', axis_up='Y', filter_glob="*.obj;*.mtl")

model_obj = bpy.context.scene.objects[model_name.split(".")[0]]       
bpy.ops.object.select_all(action='DESELECT') 
bpy.context.view_layer.objects.active = model_obj  
model_obj.select_set(True)       


sourceName = bpy.context.object.name
source = bpy.data.objects[sourceName]

#duplicating source model
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'})
duplicate_obj = bpy.context.scene.objects[model_name.split(".")[0]+".001"]     
bpy.ops.object.select_all(action='DESELECT') 
bpy.context.view_layer.objects.active = duplicate_obj   
duplicate_obj.select_set(True)   
bpy.context.object.name = sourceName + "_Voxelized"

bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
bpy.ops.object.convert(target='MESH')

#source.hide_render = True
#source.hide_viewport = True

targetName = bpy.context.object.name
target = bpy.data.objects[targetName]

#converting to blocks
bpy.ops.object.modifier_add(type='REMESH')
bpy.context.object.modifiers["Remesh"].mode = 'BLOCKS'
bpy.context.object.modifiers["Remesh"].octree_depth = 7
bpy.context.object.modifiers["Remesh"].scale = 0.5
bpy.context.object.modifiers["Remesh"].use_remove_disconnected = True
bpy.ops.object.modifier_apply(modifier="Remesh")

#transferring UVs from source to target
bpy.ops.object.modifier_add(type='DATA_TRANSFER')
bpy.context.object.modifiers["DataTransfer"].use_loop_data = True
bpy.context.object.modifiers["DataTransfer"].data_types_loops = {'UV'}
bpy.context.object.modifiers["DataTransfer"].loop_mapping = 'POLYINTERP_NEAREST'
bpy.context.object.modifiers["DataTransfer"].object = source
bpy.ops.object.datalayout_transfer(modifier="DataTransfer")
bpy.ops.object.modifier_apply(modifier="DataTransfer")

#this is the chunk that reduces each voxel face to one colour
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_mode(type='FACE')

bpy.context.area.ui_type = 'UV'
bpy.context.scene.tool_settings.use_uv_select_sync = False
bpy.context.space_data.uv_editor.sticky_select_mode = 'DISABLED'
bpy.context.scene.tool_settings.uv_select_mode = 'FACE'
bpy.context.space_data.pivot_point = 'INDIVIDUAL_ORIGINS'
bpy.ops.mesh.select_all(action='DESELECT')

#singularizing colours on each voxel face
count = 0 
while count < 100:
    bpy.ops.mesh.select_random(ratio=(count/100) + 0.01, seed=count)
    bpy.ops.uv.select_all(action='SELECT')
    bpy.ops.transform.resize(value=(0.01, 0.01, 0.01))
    bpy.ops.mesh.hide(unselected=False)
    count+=1
    
#returning to previous context
bpy.context.area.ui_type = 'VIEW_3D'
bpy.ops.mesh.reveal()
bpy.ops.object.editmode_toggle()
bpy.context.area.ui_type = 'TEXT_EDITOR'

#deleting source and keeping target
bpy.ops.object.select_all(action='DESELECT')
source.select_set(True)
bpy.ops.object.delete()

#selecting target
target.select_set(True)


#exporting voxelized model
output_directory = sourceDirectory
vox_model_name = targetName + '.obj'
output_file = os.path.join(output_directory, vox_model_name)
print(output_file)
bpy.ops.export_scene.obj(filepath=output_file)


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source