0
$\begingroup$

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)
```
$\endgroup$
3
  • $\begingroup$ explain what's the idea behind the part of the code that doesn't work, maybe it can be done on a lower level? didn't run it but I see you have mesh and uv operators together, I'm just guessing but don't you need to change context between them? low level seems a better option to me $\endgroup$
    – alambre
    Commented Mar 15, 2022 at 14:43
  • $\begingroup$ So I the work flow is this: 1. import .obj mesh 2. add remesh modifier for voxels 3. add uv data transfer 4. switch to uv editor context and scale down the uv mapping that corresponds to each face on the voxel so that each face has only one color (this is the part that isnt working headlessly) 5. export and save the model $\endgroup$ Commented Mar 16, 2022 at 5:52
  • $\begingroup$ @alambre I do agree that I need to go on a lower level and not switch contexts between the 3d view and the uv editor but I cannot figure out how to do this. $\endgroup$ Commented Mar 16, 2022 at 6:05

1 Answer 1

0
$\begingroup$

if you need to collapse uvs for your faces something like this may work,
but I saw there's an operator also: bmesh.ops.collapse_uvs()

import bpy, bmesh
ob = bpy.context.active_object

bm = bmesh.from_edit_mesh(ob.data)
uv_lay = bm.loops.layers.uv.active

for face in bm.faces:
    coords = [l[uv_lay].uv for l in face.loops]
    x = (sum([uv[0] for uv in coords]) / len(coords))
    y = (sum([uv[1] for uv in coords]) / len(coords))
    for l in face.loops: l[uv_lay].uv = [x,y]

bmesh.update_edit_mesh(ob.data)

hope it helps

$\endgroup$
1
  • $\begingroup$ This did the trick! Thank you so much :) $\endgroup$ Commented Apr 6, 2022 at 8:27

You must log in to answer this question.

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