1
$\begingroup$

I'd like to fill a custom UI list with all the lights that are in the current scene, but am unsure of the best way to do this. We could iterate over bpy.context.scene.objects and validate object.type == 'LIGHT' to filter things out and then use objects[i].data to get the actual light, but that strikes me as clunky and non-performant, especially for scenes that have a large number of objects.

Ideally I would like to drill into bpy.data.lights and then filter this much smaller dataset based upon the scene(s) each light is used within. But, given a light in bpy.data.lights, how can I find the object that's using it, and from there check this object's user_scene attribute? This strikes me as being much faster than iterating in a top-down fashion over a bazillion objects' data attributes, but if there's a mechanism for going bottom-up from a light to the object(s) that are using it then I can't find it in the API. Any ideas, smarter people of StackExchange?

Many thanks, and apologies if this is a DOH! kind of question, I'm new to this and still feeling my way around in the dark.

$\endgroup$
3
  • $\begingroup$ In the interactive Python window did you use text completion to find the likely candidate for the light [object name]? $\endgroup$ Commented Nov 26, 2020 at 20:53
  • $\begingroup$ Thanks @brockman, that's very helpful. $\endgroup$ Commented Nov 27, 2020 at 14:55
  • $\begingroup$ Cool, glad I could help @QuentinWalker $\endgroup$
    – brockmann
    Commented Nov 27, 2020 at 19:01

2 Answers 2

2
$\begingroup$

Put them in a collection

IMO the simplest way to do this is, as suggested

scene_lights = [ob for ob in scene.objects if ob.type == 'LIGHT']

One light object could have the same light data as any or all of the lights in a scene. Even if there are few lights, checking that the data belongs to an object in the scene could prove less efficient than above.

If you feel that there are so many objects in the scene that iterating over them is inefficient, consider linking them to a collection(s) using name or ID property to tag the collection as being for light objects.

lightcol = bpy.data.collections.get("Lights")

if not lightcol:
    lightcol =  bpy.data.collections.new("Lights")
    scene.collection.children.link(lightcol) # or wherever
# populate it.
for lt in scene_lights:
    lightcol.objects.link(lt)

Could make collections within this collection to further categorize by light type

Polled PointerProperty

As mentioned by @brockmann can also consider using a polled pointer property, an example for materials

Custom search data to UILayout.prop_search

whereas in the case of lights the pointer property type would be bpy.types.Object, and the poll method would test against type. Could easily be extended to light type

$\endgroup$
1
  • $\begingroup$ Thanks, that really helped clear up my thinking. $\endgroup$ Commented Nov 27, 2020 at 14:53
0
$\begingroup$

use the script below:

import bpy

light_set = set(bpy.data.lights.keys())
obj_set = set(bpy.data.objects.keys())

# light data doesn't update by deleting:
light_set.intersection_update(obj_set)

light_objects = [bpy.data.objects[name] for name in light_set]
$\endgroup$
1
  • 4
    $\begingroup$ If any name is changed, or if objects share light data, code above will not work as expected. [ob for ob in scene.objects if ob.type == 'LIGHT'] $\endgroup$
    – batFINGER
    Commented Nov 27, 2020 at 6:48

You must log in to answer this question.

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