Scene Manager: named LODs
{lod} in SCENE_MANAGER_LOD_COLLECTION now matches any name (COL_bob_LODhigh
as well as COL_bob_LOD0). SCENE_MANAGER_LODS (high, mid, low) sets the
button order and the LOD shown on load; unlisted LODs follow, numbers in
order, then names A-Z. It replaces SCENE_MANAGER_DEFAULT_LOD. The LOD of
Selected buttons get their own line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bac7a6f5da
commit
6ec2b228ae
8 files changed
+80
-61
No files matched your search
@@ -5,7 +5,7 @@
|
||||
bob: a rig (COL_bob: armature + meshes), v001 has 1 mesh, v002 has 2.
|
||||
tree: COL_tree holding only LOD collections (COL_tree_LOD0, COL_tree_LOD1), plus an
|
||||
unrelated top-level collection. v002 adds a mesh outside the LODs, v003 has no LOD.
|
||||
car: a rig, COL_car: armature + COL_car_LOD0..2.
|
||||
car: a rig, COL_car: armature + named LODs COL_car_LODlow, _LODhigh, _LODmid.
|
||||
rock: a single top-level collection not named after the asset (fallback case), its mesh
|
||||
using a node group linked from Blender's essentials (an indirect library).
|
||||
"""
|
||||
@@ -24,7 +24,7 @@ def mesh_object(name):
|
||||
return bpy.data.objects.new(name, mesh)
|
||||
|
||||
|
||||
def write(path, collection_name, meshes=1, rig=False, extra=False, node_group=False, lods=0):
|
||||
def write(path, collection_name, meshes=1, rig=False, extra=False, node_group=False, lods=()):
|
||||
bpy.ops.wm.read_homefile(use_empty=True)
|
||||
scene = bpy.context.scene
|
||||
collection = bpy.data.collections.new(collection_name)
|
||||
@@ -42,7 +42,7 @@ def write(path, collection_name, meshes=1, rig=False, extra=False, node_group=Fa
|
||||
ob = mesh_object(f"GEO_{collection_name}_{index}")
|
||||
ob.parent = parent
|
||||
collection.objects.link(ob)
|
||||
for lod in range(lods):
|
||||
for lod in lods:
|
||||
lod_collection = bpy.data.collections.new(f"{collection_name}_LOD{lod}")
|
||||
collection.children.link(lod_collection)
|
||||
ob = mesh_object(f"GEO_{collection_name}_LOD{lod}")
|
||||
@@ -62,9 +62,9 @@ def write(path, collection_name, meshes=1, rig=False, extra=False, node_group=Fa
|
||||
lib = os.path.join(WORKDIR, "lib")
|
||||
write(os.path.join(lib, "bob", "v001", "rig.blend"), "COL_bob", meshes=1, rig=True, extra=True)
|
||||
write(os.path.join(lib, "bob", "v002", "rig.blend"), "COL_bob", meshes=2, rig=True, extra=True)
|
||||
write(os.path.join(lib, "tree", "v001", "model.blend"), "COL_tree", meshes=0, extra=True, lods=2)
|
||||
write(os.path.join(lib, "tree", "v002", "model.blend"), "COL_tree", meshes=1, extra=True, lods=2)
|
||||
write(os.path.join(lib, "tree", "v001", "model.blend"), "COL_tree", meshes=0, extra=True, lods=["0", "1"])
|
||||
write(os.path.join(lib, "tree", "v002", "model.blend"), "COL_tree", meshes=1, extra=True, lods=["0", "1"])
|
||||
write(os.path.join(lib, "tree", "v003", "model.blend"), "COL_tree", meshes=1, extra=True)
|
||||
write(os.path.join(lib, "rock", "v001", "rock.blend"), "rock_geo", node_group=True)
|
||||
write(os.path.join(lib, "car", "v001", "car.blend"), "COL_car", meshes=0, rig=True, lods=3)
|
||||
write(os.path.join(lib, "car", "v001", "car.blend"), "COL_car", meshes=0, rig=True, lods=["low", "high", "mid"])
|
||||
print("Test assets written in", lib)
|
||||
+16
-14
@@ -132,40 +132,42 @@ check("car loaded once downloaded", loaded().get("car", (None,))[0] == "v001", m
|
||||
print("LOD")
|
||||
tree_lib, car_lib = bpy.data.libraries["tree"], bpy.data.libraries["car"]
|
||||
tree, car = lib.instances(tree_lib)[0], lib.instances(car_lib)[0]
|
||||
check("instance shows the default LOD", lib.current_lod(tree_lib, tree) == 0 and tree.instance_collection.name == "COL_tree_LOD0")
|
||||
check("override shows the default LOD", lib.current_lod(car_lib, car) == 0)
|
||||
check("numbered LODs: instance shows the first", lib.current_lod(tree_lib, tree) == "0" and tree.instance_collection.name == "COL_tree_LOD0")
|
||||
check("named LODs in config order", list(lib.lods(car_lib, car)) == ["high", "mid", "low"], str(list(lib.lods(car_lib, car))))
|
||||
check("named LODs: override shows the first in config order", lib.current_lod(car_lib, car) == "high")
|
||||
hidden = {c.name: (c.hide_viewport, c.hide_render) for c in lib.lods(car_lib, car).values()}
|
||||
check(
|
||||
"other LODs hidden (viewport and render)",
|
||||
hidden == {"COL_car_LOD0": (False, False), "COL_car_LOD1": (True, True), "COL_car_LOD2": (True, True)},
|
||||
hidden == {"COL_car_LODhigh": (False, False), "COL_car_LODmid": (True, True), "COL_car_LODlow": (True, True)},
|
||||
str(hidden),
|
||||
)
|
||||
evaluated = {ob.name for ob in bpy.context.evaluated_depsgraph_get().objects}
|
||||
check("hidden LODs not evaluated", "GEO_COL_car_LOD0" in evaluated and not evaluated & {"GEO_COL_car_LOD1", "GEO_COL_car_LOD2"})
|
||||
bpy.ops.wtd_scene.set_lod(lod=2, library="car", instance=car.name)
|
||||
check("override switched to LOD 2", lib.current_lod(car_lib, car) == 2)
|
||||
check("hidden LODs not evaluated", "GEO_COL_car_LODhigh" in evaluated and not evaluated & {"GEO_COL_car_LODmid", "GEO_COL_car_LODlow"})
|
||||
bpy.ops.wtd_scene.set_lod(lod="low", library="car", instance=car.name)
|
||||
check("override switched to low", lib.current_lod(car_lib, car) == "low")
|
||||
for ob in bpy.context.view_layer.objects:
|
||||
ob.select_set(ob in (tree, bpy.data.objects["RIG_COL_car"]))
|
||||
check("LOD of selected", bpy.ops.wtd_scene.set_lod(lod=1, selected=True) == {"FINISHED"})
|
||||
check("both switched to LOD 1", (lib.current_lod(tree_lib, tree), lib.current_lod(car_lib, car)) == (1, 1))
|
||||
check("missing LOD refused", bpy.ops.wtd_scene.set_lod(lod=5, library="tree", instance="tree") == {"CANCELLED"})
|
||||
check("LOD of selected", bpy.ops.wtd_scene.set_lod(lod="1", selected=True) == {"FINISHED"})
|
||||
check("only the selected instances having it switched", (lib.current_lod(tree_lib, tree), lib.current_lod(car_lib, car)) == ("1", "low"))
|
||||
check("missing LOD refused", bpy.ops.wtd_scene.set_lod(lod="5", library="tree", instance="tree") == {"CANCELLED"})
|
||||
check("LOD order: list, numbers, names", sorted(["b", "10", "low", "2", "a", "high"], key=lib.lod_order) == ["high", "low", "2", "10", "a", "b"])
|
||||
second = lib.add_instance(scene, bpy.context.view_layer, car_lib)
|
||||
check(
|
||||
"second override: LODs found by their linked names",
|
||||
list(lib.lods(car_lib, second)) == [0, 1, 2] and lib.current_lod(car_lib, second) == 0,
|
||||
list(lib.lods(car_lib, second)) == ["high", "mid", "low"] and lib.current_lod(car_lib, second) == "high",
|
||||
str([c.name for c in second.children]),
|
||||
)
|
||||
lib.remove_instance(second)
|
||||
lib.update("tree", {"name": "v002", "path": os.path.join(WORKDIR, "lib", "tree", "v002", "model.blend")})
|
||||
tree = lib.instances(bpy.data.libraries["tree"])[0]
|
||||
check("LOD kept by an update", lib.current_lod(bpy.data.libraries["tree"], tree) == 1)
|
||||
check("content outside the LODs: instance refused", bpy.ops.wtd_scene.set_lod(lod=0, library="tree", instance="tree") == {"CANCELLED"})
|
||||
check("LOD kept by an update", lib.current_lod(bpy.data.libraries["tree"], tree) == "1")
|
||||
check("content outside the LODs: instance refused", bpy.ops.wtd_scene.set_lod(lod="0", library="tree", instance="tree") == {"CANCELLED"})
|
||||
lib.update("tree", {"name": "v003", "path": os.path.join(WORKDIR, "lib", "tree", "v003", "model.blend")})
|
||||
tree = lib.instances(bpy.data.libraries["tree"])[0]
|
||||
check("LODs gone: whole collection instanced", tree.instance_collection.name == "COL_tree" and not lib.lods(bpy.data.libraries["tree"], tree))
|
||||
lib.update("tree", {"name": "v001", "path": os.path.join(WORKDIR, "lib", "tree", "v001", "model.blend")})
|
||||
tree = lib.instances(bpy.data.libraries["tree"])[0]
|
||||
check("LODs back: default LOD", lib.current_lod(bpy.data.libraries["tree"], tree) == 0)
|
||||
check("LODs back: default LOD", lib.current_lod(bpy.data.libraries["tree"], tree) == "0")
|
||||
|
||||
print("Versions")
|
||||
check("bob is the latest", sm.version_status(bpy.data.libraries["bob"])[0] == "LATEST")
|
||||
@@ -256,7 +258,7 @@ bpy.ops.wm.open_mainfile(filepath=path)
|
||||
sm._on_load_post()
|
||||
check("everything found after reopening", set(loaded()) == {"bob", "car", "lamp", "rock", "tree"})
|
||||
car_lib = bpy.data.libraries["car"]
|
||||
check("LOD kept after reopening", lib.current_lod(car_lib, lib.instances(car_lib)[0]) == 1)
|
||||
check("LOD kept after reopening", lib.current_lod(car_lib, lib.instances(car_lib)[0]) == "low")
|
||||
sm.connect(bpy.context.scene)
|
||||
pump()
|
||||
check("versions checked again", sm.version_status(bpy.data.libraries["bob"])[0] == "UPDATE")
|
||||
|
||||
Reference in new issue
Block a user