1
$\begingroup$

I require a way to select certain cameras in a scene. My plan is to get all camera objects in a scene, and then based on their names get the ones that I need.

Currently I’m selecting all cameras like this:

all_cams = [ob for ob in list(bpy.context.scene.objects) if ob.type == ‘CAMERA’]

But i think there should be a better way to do this, without iterating through all objects in a scene. There is the D.cameras collection and from there I can get all data-block names. But how I can go from data-block names to the object name?

Or at least how do I select the cameras using their data-block name? ( then I can work further based on selected objects)

Do you have any ideas how I can achieve this? Thank you!

$\endgroup$
4
  • 1
    $\begingroup$ Have you identified this operation as a bottleneck in terms of speed ? It should be pretty fast unless you have thousands upon thousands of objects. Otherwise you can use a custom collection property to store camera objects in the scene for instance. Using data block names will be even less efficient because of the lookup : [ob for ob in bpy.context.scene.objects if ob.data.name in camera_names] and even then if 2 cameras use the same data it will fail. Object data don't hold a reference to their object because they can be shared amongst an indefinite number of objects $\endgroup$
    – Gorgious
    Commented Oct 27, 2021 at 7:50
  • $\begingroup$ "Have you identified this operation as a bottleneck in terms of speed ?" Yeah, i was thinking that. Didnt have opportunity to run a test tho. I was just wondering if there is a way to do this. I'll stick to what I have right now, and if it will be a problem I will try to adress it then I guess ;p $\endgroup$
    – Przemek
    Commented Oct 27, 2021 at 9:03
  • 2
    $\begingroup$ Could perhaps get a squeak more with a different test than equality ob.type.startswith('CAM') or via an attribute test hasattr(...) , doubt its worth it. Somewhat related blender.stackexchange.com/a/233823/15543 $\endgroup$
    – batFINGER
    Commented Oct 27, 2021 at 10:42
  • $\begingroup$ Yes there is such a way: [camera for camera in bpy.data.cameras if bpy.context.scene.objects.get(camera.name)]. No guarantee that it will be faster in any given situation though. $\endgroup$ Commented Nov 1, 2021 at 17:22

1 Answer 1

1
$\begingroup$

Don't worry too much, testing all objects in the scene is lightning fast... and the winner is:

[ob for ob in bpy.context.scene.objects if ob.type == 'CAMERA']

Time measurements of a scene with 1000 cameras and 1000 default cubes.

  • Code in question

    cams = [ob for ob in list(bpy.context.scene.objects) if ob.type == 'CAMERA']
    # Time: 0.0026161670684814453
    
  • Regular list comprehension

    cams = [ob for ob in bpy.context.scene.objects if ob.type == 'CAMERA']
    # Time: 0.0021109580993652344
    
  • Generator

    cams = (ob for ob in bpy.context.scene.objects if ob.type == 'CAMERA')
    # Time: 6.222724914550781e-05
    
  • Prefix list comprehension

    cams = [ob for ob in bpy.context.scene.objects if ob.type.startswith('CAM')]
    # Time: 0.0025479793548583984
    
  • Attribute list comprehension

    cams = [ob for ob in bpy.context.scene.objects if hasattr(ob.data, "lens")]
    # Time: 0.002920866012573242
    
$\endgroup$
1
  • $\begingroup$ The test to me illustrates that they are all almost equal apart from the generator operation which is ~30 times faster. Note that the main issue with generators is that you can only iterate over them once and then they're done. $\endgroup$
    – Gorgious
    Commented Jan 16, 2022 at 17:12

You must log in to answer this question.

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