1
$\begingroup$

I have a set up like this: enter image description here

Where there are 3 or sometimes more grids of different objects one behind the other. The objects are regularly spaced around 20 units in each axis, tho their origins are not always at a regular point. I need to select an even amount of objects from each of the grids so that I can merge them into a single grid with all the types of objects.

I have these code from another question I made that creates 20x20x80 cells and merges the objects inside of them:

import bpy

# grid layout in space
cell_offset = (-10, -40, -10)
cell_size = (20, 80, 20)

# little helper to snap values to a grid
def snap(val, step):
    return (val//step) * step

objects = bpy.data.collections["Collection"].objects # take from a collection
#objects = bpy.context.selected_objects  # or take selected objects

cells = {}
for obj in objects:
    # snap the object's location to the next lower cell corner
    key = (
        snap(obj.location.x - cell_offset[0], cell_size[0]),
        snap(obj.location.y - cell_offset[1], cell_size[1]),
        snap(obj.location.z - cell_offset[2], cell_size[2])
    )
    # group objects with the same cell
    if key not in cells:
        cells[key] = [obj]
    else:
        cells[key].append(obj)

# select all objects in one cell and join them
for value in cells.values():
    bpy.ops.object.select_all(action='DESELECT')
    
    if len(value) > 1: # joining makes sense
        bpy.context.view_layer.objects.active = value[0]
        for obj in value:
            obj.select_set(True)

        bpy.ops.object.join()
        
        


        
        

Is there a way to tell it to select 1 of the objects in each cell at random instead of merging them?

I assume the code would help but if it has to be done differently that's also fine.

$\endgroup$
7
  • $\begingroup$ At a brief glance, I think all you need to do is delete the join line, and add an if statement with a random chance to the selector line. Python has a built in random module, try ‘if random.randrange(2):’ $\endgroup$
    – TheLabCat
    Commented Jul 11 at 0:14
  • 1
    $\begingroup$ from random import choiceat the top of your file then after bpy.ops.object.select_all(action='DESELECT') simply use choice(value).select_set(True). Btw value is not the best variable name in this case, I would set it to objects or sth like that $\endgroup$
    – Gorgious
    Commented Jul 11 at 7:04
  • $\begingroup$ Also BTW I don't know where you took that code from but FYI every line in the last for loop can be removed if you use an operator override. eg for objects in cells.values(): with bpy.context.temp_override(object=objects[0], selected_editable_objects = objects): bpy.ops.object.join() see blender.stackexchange.com/questions/248274/… $\endgroup$
    – Gorgious
    Commented Jul 11 at 7:09
  • $\begingroup$ @TheLabCat it says random is not defined as a value. Importing Random doesn't help either since it says it doesn't have a range attribute. Wouldn't this just select an object 33% of the time and not check if something else has been selected in the cell? $\endgroup$
    – Cornivius
    Commented Jul 11 at 10:22
  • $\begingroup$ @Gorgious That works, thanks $\endgroup$
    – Cornivius
    Commented Jul 11 at 10:35

1 Answer 1

1
$\begingroup$

Notwithstanding the first part of your script which is irrelevant to your actual question, you can select a random item from a sequence with the standard random.choice function that comes with the python standard random module. This is arguably not really a Blender question but rather a Python question, but here goes :

import random

# The first part of your script...

bpy.ops.object.select_all(action='DESELECT')
for objects in cells.values():
    random.choice(objects).select_set(True)
$\endgroup$

You must log in to answer this question.

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