0
$\begingroup$

I was trying to solve this question and I already have an idea how to do it.

import bpy
import bmesh
import bpy_types

bpy.app.handlers.depsgraph_update_post.clear()

def get_visibility_states():
    states = {obj.name: obj.hide_viewport for obj in bpy.context.scene.objects}
    for s in states:
        print("S: ", s, "=", states[s])
    return states

def check_visibility():
    print("check visibility")
    for s in previous_visible_states:
        print("C: ", s, "=", previous_visible_states[s])
    current_visible_states = get_visibility_states()
    change = False
    for p in previous_visible_states:
        for c in current_visible_states:
            if p == c and previous_visible_states[p] != current_visible_states[c]:
                print(f"{p} visibility has changed")
                change = True
    if not change:
        print("nothing in visibility has changed")
        

def on_depsgraph_update(scene):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    for update in depsgraph.updates:
        o = update.id
        if type(o) is not bpy.types.Scene:
            continue
        check_visibility()
        previous_visible_states = get_visibility_states()
        break

bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update)


bpy.data.objects["Cone"].hide_viewport = True
previous_visible_states = get_visibility_states()
bpy.data.objects["Cone"].hide_viewport = False
check_visibility()
previous_visible_states = get_visibility_states()

But this has been driving me crazy because the last few statements in the script simulating a change in hide_viewport actually works, just not when I click the eye icon in Outliner. The script update is called when I click the eye icon, but nothing happens. I don't know why the visibility states are always False despite the code flow looking proper. No change has been detected despite me clicking the hide_viewport property in the Outliner of every object. What gives? Where is the error in my script?

$\endgroup$
2
  • 1
    $\begingroup$ The eye icon visibility is accessed with hide_get(), hide_viewport is for the monitor icon visibility, see blender.stackexchange.com/a/133470/86891 $\endgroup$
    – Gorgious
    Jan 15, 2023 at 8:51
  • $\begingroup$ @Gorgious hey thank you for your response. i changed it to hide_get() now and i forgot to declare previous_visible_states. It got partially fixed. It only gets triggered when i click the eye icon to hide the object. but when i click the eye icon again to make the object visible, it says nothing has changed. $\endgroup$ Jan 15, 2023 at 9:01

1 Answer 1

2
$\begingroup$

Dictionary previous_visible_states is not updated, it keeps the initial state passed from on_depsgraph_update(scene). Declare dict as global in check_visibility()_ to make it available outside the scope.

The following script was simplified and responds the available visibility settings in Outliner: hide in viewport (icon eye), disable in viewports (icon monitor) and disable in renders (icon camera). Tested in 2.93, 3.3.2 and 3.4.1

import bpy

bpy.app.handlers.depsgraph_update_post.clear()

def get_visibility_states():
    states = {}
    for obj in bpy.context.scene.objects:
        visibility = {
                     'hide_viewport': obj.hide_get(),         # eye
                     'disable_viewports': obj.hide_viewport,  # monitor (filter enabled by default)
                     'disable_renders': obj.hide_render       # camera
                     }  
        states.update({obj.name: visibility})
   #for item in states:
   #print("S:", item, states[item])
    return states

def check_visibility():
   #print("\ncheck visibility")
    global previous_visible_states   ###    
   #for item in previous_visible_states:
   #print("C:", item, previous_visible_states[item])
    current_visible_states = get_visibility_states()

    for item in previous_visible_states:
        if not previous_visible_states[item] == current_visible_states[item]:
            print("\n#", item, "changed:")
            print("previous", previous_visible_states[item])            
            print("current", current_visible_states[item])            

    previous_visible_states = current_visible_states  # refresh

def on_depsgraph_update(scene):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    for update in depsgraph.updates:
        o = update.id
        if type(o) is not bpy.types.Scene:
            continue
        check_visibility()
        previous_visible_states = get_visibility_states()
        break

bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update)
previous_visible_states = get_visibility_states() # get first states
$\endgroup$
1

You must log in to answer this question.

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