Hey! Here's the shader I used as a starting point: https://github.com/tufourn/Dither3D-Godot
I then modified this for the invisible objects by adding something like this:
void fragment
{
ALBEDO = [call function from Dither3D]
ALPHA = get_alpha_from_spotlight(world_pos)
}(where I got the world_pos using one of the methods from here)
My get_alpha_from_spotlight() function would be passed the position, angle, brightness etc of the most recent light that the camera had created (each time you take a picture, it just moves a spotlight to the player's position). It can then test for whether the vector (world_pos - spotlight_pos) is within the cone that the spotlight lights up, just using maths (testing against cos(spotlight_angle) etc, and using smoothsteps to make it look okay).
I had depth ordering issues, so I placed all the invisible objects on a higher render priority, so they always render first (which is a massive bodge, but it sortof held together for the room layouts I used).
I hope that makes sense, if you'd like any other details let me know and I can share my code / explain other bits.
As for controller support, I'm sorry I didn't add it in. I really should've, as it wouldn't have taken very long at all compared to other features. I'll add it to my template player controller script so I can use it for next time, thanks for pointing it out!
Thanks for playing :)