シーン内のすべてのライトを*効率的に*見つける方法は?

Nov 26 2020

カスタムUIリストに現在のシーンにあるすべてのライトを入力したいのですが、これを行うための最良の方法がわかりません。繰り返してbpy.context.scene.objects検証object.type == 'LIGHT'し、フィルターobjects[i].dataをかけて実際の光を取得することもできますが、特にオブジェクトが多数あるシーンでは、不格好でパフォーマンスが悪いと感じます。

理想的にはbpy.data.lights、各ライトが使用されているシーンに基づいて、このはるかに小さなデータセットをドリルダウンしてフィルタリングしたいと思います。しかし、ライトが与えられたbpy.data.lights場合、それを使用しているオブジェクトをどのように見つけ、そこからこのオブジェクトのuser_scene属性を確認できますか?これは、バジリオンのオブジェクトのdata属性をトップダウンで繰り返すよりもはるかに高速であると私は思いますが、ライトからそれを使用しているオブジェクトにボトムアップで移動するメカニズムがある場合、私はできませんAPIで見つけてください。StackExchangeの賢い人、アイデアはありますか?

これがDOHである場合、多くの感謝と謝罪!ある種の質問ですが、私はこれに不慣れで、まだ暗闇の中で自分の道を感じています。

回答

2 batFINGER Nov 27 2020 at 11:28

それらをコレクションに入れる

IMOは、これを行う最も簡単な方法は、提案されているとおりです。

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

1つのライトオブジェクトは、シーン内のライトのいずれかまたはすべてと同じライトデータを持つことができます。ライトが少ない場合でも、データがシーン内のオブジェクトに属していることを確認すると、上記よりも効率が低下する可能性があります。

シーン内にオブジェクトが多すぎて反復処理が非効率的であると思われる場合は、nameまたはIDプロパティを使用してそれらをコレクションにリンクし、コレクションにライトオブジェクト用としてタグを付けることを検討してください。

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)

このコレクション内にコレクションを作成して、ライトタイプでさらに分類することができます

ポーリングされたPointerProperty

@brockmannが述べたように、マテリアルの例である、ポーリングされたポインタプロパティの使用も検討できます。

UILayout.prop_searchへのカスタム検索データ

一方、ライトの場合、ポインタプロパティタイプはbpy.types.Object、であり、pollメソッドはタイプに対してテストします。ライトタイプにも簡単に拡張可能

MohammadHosseinJamshidi Nov 27 2020 at 04:20

以下のスクリプトを使用してください。

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]