1

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!

batFINGER
  • 84,216
  • 10
  • 108
  • 233
Przemek
  • 11
  • 1
  • 1
    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 – Gorgious Oct 27 '21 at 07:50
  • "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

    – Przemek Oct 27 '21 at 09:03
  • 2
    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 https://blender.stackexchange.com/a/233823/15543 – batFINGER Oct 27 '21 at 10:42
  • 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. – Marty Fouts Nov 01 '21 at 17:22

1 Answers1

1

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
    
pyCod3R
  • 1,926
  • 4
  • 15
  • 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. – Gorgious Jan 16 '22 at 17:12