0

I joined multiple meshes with batfingers script here
How to join objects with Python?

#get mesh copies of collection and join into single mesh
col = bpy.data.collections['export']
obs = [o for o in col.objects if o.type == 'MESH']
_obs = [o.copy() for o in obs]

#context override to join them into one obj, with bpy.context.temp_override(active_object=_obs[0], selected_editable_objects=_obs): bpy.ops.object.join() bpy.context.scene.collection.objects.link(_obs[0]) _obs[0].name='single_mesh'

It works, but trying to apply all transformations to the new object,
I get the following warning 'Create new object-data users and apply transformations'.
Clicking 'Ok' will apply the transformation.

What am I doing wrong here and what does Blender do in the background?
.blend file is here, using Blender 3.2.

Tortenrandband
  • 771
  • 6
  • 13

1 Answers1

1

The problem has to do with that the creation of the _obs variable is not copying everything correctly.

It seems like it's still joining the objects with one of the currently existing objects and then linking the joined object to the collection again. Whatever one that was used as the active object in the temp_override winds up as the joined mesh, with the same data as the _export_single_mesh that was linked in.

enter image description here

So you wind up with two of the same objects, sharing the same data.

I'm not entirely sure why this is happening but you can "solve" it be making copies of the data from each object at the outset and reassigning each object to it's original data. It's a bit hacky but it "works".

import bpy
import numpy as np
import bpy
#join objs in collections
#https://blender.stackexchange.com/questions/13986/how-to-join-objects-with-python

#get mesh copies of collection you want to export col = bpy.data.collections['export'] obs = [] _obs = [] _datas = []

do this all in one for loop to make it faster

for obj in col.objects: if obj.type == "MESH": obs.append(obj) _obs.append(obj.copy()) _datas.append(obj.data.copy())

#context override to join them into one obj, #without changing real selection with bpy.context.temp_override(active_object=_obs[0], selected_editable_objects=_obs): bpy.ops.object.join() bpy.context.collection.objects.link(_obs[0]) _obs[0].name='_export_single_mesh'

after the new object is linked relink the original objects to their old data.

for obj, data in zip(obs, _datas): obj.data = data

now each object in the collection has it's own data.

apply transforms should work

Jakemoyo
  • 4,375
  • 10
  • 20
  • Works, but I might not understand how copy() works. Why do you have to relink original objects to their old data in the last step? Original objects and their data stay untouched, don't they? – Tortenrandband Aug 29 '22 at 06:56
  • 1
    Yeah like I said, I'm not sure why it's happening, but the context_override seems like it's using the obs[0] not the _obs[0] variable and so the join is happening on one of the cubes currently in the scene. You could maybe see if the same bug occurs if you create a manual context dictionary like old school and see if it does the same thing, rather than using the context.temp_override(). Just something like ctx = bpy.context.copy(); ctx['active_object'] = _obs[0]; ctx['selected_editable_objects'] = _obs; bpy.ops.objects.join(ctx) and see if that works. – Jakemoyo Aug 30 '22 at 12:27