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
    Oct 27 '21 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
    Oct 27 '21 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
    Oct 27 '21 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$ Nov 1 '21 at 17:22
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
    Jan 16 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.