0
$\begingroup$

I'm a Blender & Python newb, so the nuances haven't been all that enjoyable :)

I'm trying to create a 1x2 stack of cubes that joins and rotates each layer by 45 degrees. Below is the code I have, which isn't working. The code as shown will create an aligned stack of cubes (like center example in pic). If I comment the code for joining/rotating the object then it will rotate each object individually (like left example in pic, not what I want).

I would like for each layer of 2 cubes to be joined with object mass center as origin, as in the right-most example in the pic.

Why isn't this working?

import bpy

zRotor = 0.0
xCount = 1
yCount = 2
zCount = 6

for zAxis in range (zCount):
    for xAxis in range (xCount):
        zRotor += 0.5
        for yAxis in range (yCount):
            bpy.ops.mesh.primitive_cube_add( location=(xAxis *3 , yAxis *3, zAxis * 3), scale=(1.2, 1.1, 1))
            bpy.ops.object.select_all()
            bpy.ops.object.join()
            bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_VOLUME', center='MEDIAN')
            bpy.ops.transform.rotate(value= zRotor, orient_axis='Z', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, False, True), mirror=False, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)

screenshot showing problems

$\endgroup$
2
  • $\begingroup$ You need to rotate each cube pair around their midpoint before you join them $\endgroup$ Commented Jan 26, 2022 at 16:31
  • $\begingroup$ Also, your join is failing because the select_all leaves you with no active object $\endgroup$ Commented Jan 26, 2022 at 18:09

1 Answer 1

1
$\begingroup$

A new object created with bpy.ops.mesh.primitive_cube_add() is active and selected but... all other objects are deselected by default. So only the last object is selected when you call bpy.ops.object.select_all().

The default action of this operator is Toggle. With this now the last object is deselected, all others are selected, and you get the error message that the active object, the last one, is not selected when joining.

To select all objects use bpy.ops.object.select_all(action='SELECT') Link

As Marty said, you need to join the objects on each level to rotate this level.

Please note that rotation values are in radians. In your example zRotor = 3.0 when zCount = 6. Radians 3.0 is about 172 degrees rotation.

import bpy

zRotor = 0.0
xCount = 1
yCount = 2
zCount = 6

for zAxis in range (zCount):
    bpy.ops.object.select_all(action='DESELECT')  # deselect all for each z-level
    level_objs = []                               # objs in level to join
    for xAxis in range (xCount):
        zRotor += 0.5
        for yAxis in range (yCount):
            # new obj is set active + selected, but all other objs get unselected by default
            bpy.ops.mesh.primitive_cube_add( location=(xAxis *3 , yAxis *3, zAxis * 3), scale=(1.2, 1.1, 1))
            level_objs.append(bpy.context.active_object)      # set obj in list to select and join level                      

    # one z-level is build , select and join all objs in this level and rotate level
    for obj in level_objs:
        obj.select_set(True)
    bpy.ops.object.join()        
    bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_VOLUME', center='MEDIAN')
    bpy.ops.transform.rotate(value= zRotor, orient_axis='Z', orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), constraint_axis=(False, False, True))

    
# all z-levels build, now select all and join
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.join()
$\endgroup$

You must log in to answer this question.

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