Python script
As promised. After running the script, press Alt + Numpad / to hide/unhide. Everything except the active object, lights and meshes is hidden. Meshes other than the active object have their materials replaced with a temporary material using Alpha Blend and Alpha=0. If there's no material slot, it is created. All data is saved to a textblock, so you can hide other objects, save the file, return to it later, and unhide the objects. However, messing with material slots of "hidden" meshes, or renaming them, will hurt you.
import bpy, json
shortcut_key = "NUMPAD_SLASH"
shortcut_modifiers = {"alt": True}
save_name = "hidden"
C = bpy.context
D = bpy.data
addon_keymaps = [] # store keymaps here to access after registration
class CUSTOM_LOCAL_OT_With_Light(bpy.types.Operator):
"""Make other objects invisible, but still affect light paths
https://blender.stackexchange.com/q/226679/60486 """
bl_idname = "custom_local.with_light"
bl_label = "Local view with light still affected by hidden objects"
def make_invisible_material(self):
name = "Temp.Invisible.Material"
m = D.materials.get(name)
if not m:
m = D.materials.new(name)
m.use_nodes = True
m.blend_method = 'BLEND'
m.node_tree.nodes['Principled BSDF'].inputs['Alpha'].default_value = 0.0
return m
def hide(self):
engine = bpy.context.scene.render.engine
invisible_mat = self.make_invisible_material()
objs = []
mats_with_fake_user = set()
to_hide = (o for o in C.scene.objects
if o.type != 'LIGHT' and not o.hide_get() and o is not C.active_object)
for o in to_hide:
entry = {"name": o.name}
objs.append(entry)
if o.type != 'MESH':
o.hide_set(True)
continue
if o.hide_select:
entry["was_unselectable"] = True
else:
o.hide_select = True
if engine == 'CYCLES':
if o.cycles_visibility.camera:
entry["camera_ray"] = True
o.cycles_visibility.camera = False
continue
entry["materials"] = []
if not o.material_slots: # no slot
entry["slot_added"] = True
bpy.ops.object.material_slot_add({'object': o})
o.material_slots[0].material = invisible_mat
continue
for slot in o.material_slots:
mat = slot.material
slot.material = invisible_mat
if not mat: # empty slot
entry["materials"].append("")
continue
if mat.use_fake_user:
mats_with_fake_user.add(mat.name)
mat.use_fake_user = True
entry["materials"].append(mat.name)
return {"materials_with_fake_user": list(mats_with_fake_user), "objects": objs}
def unhide(self, data):
for entry in data["objects"]:
o = D.objects[entry["name"]]
o.hide_set(False) # hidden objects were ignored, so all objects saved
# are objects hidden by this script
if "was_unselectable" not in entry:
o.hide_select = False
if "camera_ray" in entry:
o.cycles_visibility.camera = True
mats = entry.get("materials")
if mats is None:
continue
if "slot_added" in entry: # remove the added slot
bpy.ops.object.material_slot_remove({'object': o})
for i, name in enumerate(entry["materials"]):
mat = D.materials[name] if name else None
o.material_slots[i].material = mat
if mat and mat not in data["materials_with_fake_user"]:
mat.use_fake_user = False
def execute(self, context):
txt = D.texts.get(save_name)
if txt:
self.unhide(json.loads(txt.as_string()))
D.texts.remove(txt)
else:
txt = D.texts.new(save_name)
txt.from_string(json.dumps(self.hide()))
return {"FINISHED"}
def register():
bpy.utils.register_class(CUSTOM_LOCAL_OT_With_Light)
# handle the keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='3D View Generic', space_type='VIEW_3D')
kmi = km.keymap_items.new(CUSTOM_LOCAL_OT_With_Light.bl_idname, shortcut_key, 'PRESS', **shortcut_modifiers)
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_class(CUSTOM_LOCAL_OT_With_Light)
# handle the keymap
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
# clear the list
del addon_keymaps[:]
if __name__ == "__main__":
register()