0
$\begingroup$

I have a scene with small LEGO bricks in Blender (a photo is attached) and I need to loop over them all, keep only one active and hide the rest at each iteration to rotate them individually by 360 degree and get .png outputs while rotating across an axis (i.e., x). At the end I should have separate folders for each LEGO including .png files of only one type rendered across different angles. I already have the following code but that generates the below error.

Here is the code:

import bpy
import math
import os

for eachOb in bpy.data.collections["LegoCollection"].all_Objects:  
    if eachOb.type == "MESH" and eachOb.name not in ('Light', 'Camera'):       
           def rotate_and_render(output_dir, output_file_pattern_string = 'render%d.png', rotation_steps = 3, rotation_angle = 360.0):
             original_rotation = eachOb.rotation_euler
             for step in range(0, rotation_steps):
               eachOb.rotation_euler[2] = radians(step * (rotation_angle / rotation_steps))
               bpy.context.scene.render.filepath = os.path.join(output_dir, (output_file_pattern_string % step))
               bpy.ops.render.render(write_still = True)
             eachOb.rotation_euler = original_rotation
             
           rotate_and_render('D:/TestBlender1', 'render%d.png', subject = bpy.data.collections[eachOb])

Below is the error:

Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: 'Collection' object is not iterable

Any hind to to improve my code is appreciated

Thank you!

enter image description here

$\endgroup$
9
  • $\begingroup$ did u try for eachOb in bpy.data.collections["LegoCollection"]: rotate_and_render(..,..., eachOb) ? $\endgroup$
    – Chris
    Feb 3, 2023 at 12:45
  • $\begingroup$ Is this a render showing all of the bricks rotating together? $\endgroup$
    – TheLabCat
    Feb 3, 2023 at 15:28
  • $\begingroup$ @TheLabCat No, I want the LEGO stimuli to be rendered separately from different angles and then save them separately as png files. I will use them as hundreds of png files as stimuli with OpenSesame. That is why I am searching for an optimized way to loop over and save some time rendering them $\endgroup$ Feb 6, 2023 at 9:22
  • $\begingroup$ @Chris Actually the procedure I should go through changed a bit in the meantime. I have several bricks of different shapes and colors in my scene and the output I need is .png files of each brick individually rendered about a rotation axis (e.g., x). I thought maybe I should loop over all bricks, make them active one by one and hide the rest but only the active obj while rendering. Unfortunately, I do not know how to do this with code. Any advice or hint is very much appreciated $\endgroup$ Feb 6, 2023 at 9:22
  • 1
    $\begingroup$ then you should edit/improve your question to your new wish you have. Because people shouldn't be forced to read the comments just to answer a question. And i think personally that runnable example code (instead of just a few lines) would attract more people to your question. $\endgroup$
    – Chris
    Feb 6, 2023 at 10:54

1 Answer 1

0
$\begingroup$

I got it to work for me. Here are some things I ran into:

  1. I needed to import radians from math
  2. spacing issues
  3. .all_Objects needed to be .all_objects
  4. I don't see a need to keep redefining the function inside a loop
  5. I needed to enumerate the loop of the legos. I don't know how you want your folders nested, whether it be one main output directory with subfolders for each lego or one main output directory for each lego with only images in each directory. Assuming the first case, I changed the output_dir to D:/TestBlender1/render%d % count, where count is whichever lego is to be rendered. Thus, inside the angle stepping loop, that's where I appended the extra image%d % step to create a unique image per step.

Here is what I got working:

import bpy
from math import radians # <--- need to import radians
import os

def rotate_and_render(output_dir, output_file_pattern_string, rotation_steps, rotation_angle):
    
    original_rotation = eachOb.rotation_euler
    
    for step in range(0, rotation_steps):
        print(step * (rotation_angle / rotation_steps))
        eachOb.rotation_euler.z = radians(step * (rotation_angle / rotation_steps))
        bpy.context.scene.render.filepath = os.path.join(output_dir, output_file_pattern_string % step)
        bpy.ops.render.render(write_still = True)
        
    eachOb.rotation_euler = original_rotation

col = bpy.data.collections["LegoCollection"].all_objects # <--- all_Objects should be all_objects 

for count, eachOb in enumerate(col): 
    valid = (eachOb.type == "MESH" and eachOb.name not in ('Light', 'Camera'))
    if valid:    
        for obToHide in col:       
            valid = (obToHide.type == "MESH" and obToHide.name not in ('Light', 'Camera'))          
            
            # Here I also added the following code to "hide" the objects that weren't to be rendered. I tried to 
            # literally hide them, but Blender kept crashing when I tried using those lines, so I set their z location way off to 999 
            if valid and obToHide != eachOb:
                  
                obToHide.location.z = 999
                # blender crashes doing following:
                # obToHide.hide_render = True      
            
            elif valid and obToHide == eachOb:
         
                obToHide.location.z = 0
                # blender crashes doing following:
                # obToHide.hide_render = False

        rotate_and_render('D:/TestBlender1/render%d' % count, 'image%d.png', 6, 360.0) 
$\endgroup$

You must log in to answer this question.

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