Repository: napari/napari

Issue:
Mouse interaction affects blending properties of `opaque` layers
## 🐛 Bug

A layer with blending mode `opaque` appears to change blending mode (this is not reflected in the layer properties or the Combobox) when zooming with the mouse.

## To Reproduce


Steps to reproduce the behavior:

Start napari, open the ipython console

Paste 

```
import numpy as np
viewer.add_image(np.random.randint(0,255,(1024,1024)), blending="additive", name="additive layer")
viewer.add_points([[100, 100],[200,200]], face_color='blue', size=100, blending="opaque")
```
You should see somehting like this:

![image](https://user-images.githubusercontent.com/2210044/189910795-95b7e02b-3429-4609-af3c-00517c505f8d.png)


Now if you  change the zoom with the mouse wheel, the points layer becomes translucent, without apparent change to 
the selected blending mode:

![Zoom_opaque_interaction](https://user-images.githubusercontent.com/2210044/189911228-5b62c92e-3da7-4395-bd89-6a571720d114.gif)

The `.blending` and `._blending` properties after zooming still show `opaque`:

![image](https://user-images.githubusercontent.com/2210044/189911826-ddc78136-70db-40ca-9db1-84a9d77f57c6.png)

Note that setting `viewer.camera.zoom` to a different value (and not zooming with the mouse wheel) does not result in this behaviour!

The underlying `vispy` layer also thinks it is using opaque blending:
```
vispy_layer = viewer.window.qt_viewer.layer_to_visual[viewer.layers['Points']]
/tmp/ipykernel_426644/4188339627.py:1: FutureWarning: Public access to Window.qt_viewer is deprecated and will be removed in
v0.5.0. It is considered an "implementation detail" of the napari
application, not part of the napari viewer model. If your use case
requires access to qt_viewer, please open an issue to discuss.!

vispy_layer.layer.blending
Out[6]: 'opaque'
```


## Expected behavior

The opacity of the points should not be affected by zooming.

## Environment

napari: 0.4.16rc2.dev289+gd90a39b8
Platform: Linux-5.15.0-46-generic-x86_64-with-glibc2.17
System: Ubuntu 20.04.5 LTS
Python: 3.8.13 (default, Mar 28 2022, 11:38:47) [GCC 7.5.0]
Qt: 5.15.2
PyQt5: 5.15.6
NumPy: 1.22.4
SciPy: 1.7.3
Dask: 2022.8.0
VisPy: 0.11.0

OpenGL:
- GL version: 4.6.0 NVIDIA 470.141.03
- MAX_TEXTURE_SIZE: 32768

Screens:
- screen 1: resolution 3840x2160, scale 1.0


## Additional context

This started out as a discussion here:
https://napari.zulipchat.com/#narrow/stream/212875-general/topic/Various.20Issues.20With.20Blending
I think many of the effects shown in the Zulip Thread are caused by the issue described here.




Discussion:
I can reproduce this all the way from napari `0.4.13` to the latest master (and using various older vispy versions)
I changed the title. It is sufficient to click into the point layer for the opacity properties to change or to pan, this is not specific to zooming.
Also, toggling the blending mode to a different mode and then back to `opaque` restores the opaqueness of the points until the next mouse interaction. 
Some more detail:
* This only affects the blending mode `opaque`. The behaviour after interaction with the layer seems to be identical as if I had set the layer to blending mode `additive`. Blending modes `min`, `translucent` and `translucent_no_depth` are not affected. 
* Labels layers show similar behaviour as the point layer (see gif below)  but I haven't been able to reproduce this with image layers. Not sure about shape layers.

![labels_opaqueness](https://user-images.githubusercontent.com/2210044/189925587-ba1cb0d3-56d7-4b65-89b9-6b285bc8458a.gif)

* If an opaque image layer is below the affected layer (and above the additive layer), the effect is not visible.
I can confirm this bizarre behavior on main on my arm64 dev env.
You don't need to zoom btw. If you toggle pan/zoom mode and move the camera then the blending changes too—just toggling pan/zoom is not enough.
Edit: for me for points/shapes, the pan/zoom behavior switches the observed behavior to one of the translucent, not additive. Easiest way to check this is with say green image layer and making a red point of shape. 
Plus it affects image layers for me too—e.g. cells3D example, set the top (nuclei) to 50% opacity then change to opaque. Then pan or zoom.
Yes, shape layers are also affected @psobolewskiPhD, but in a slightly different way.

In the screen recording below:

* I add a shape with blending mode `opaque`
* I move the opacity slider back and forth -> nothing happens
* I click into the canvas and either drag or zoom. Nothing obvious is visible here, in contrast to the
points and the labels layer I don't get the noise image shining through as if it was additive. However ...
* ... if I now move the opacity slider back and forth -> the shapes fade in and out, which didn't happen initially.

![shape_blending](https://user-images.githubusercontent.com/2210044/190144740-6284b321-9975-4ce5-a8bc-824306e5da9d.gif)

Wow, lots of bizarre stuff here! Will take a look as soon as I have some time to dive deeper.
Was just reading through some other open issues and wonder whether #5002 might be related.
I don't think it's related; that's a specific issue with how the image shader is implemented, which does not apply here.
After playing around a bit, It seems to me that the real issue here stems from the blending of the image below. If the image is not `additive` everything is fine. Similarly, if the image is set to `minimum`, everything disappears, even points that do not even overlap with the image!!

It's as if the blending mode was being set to the whole canvas, or multiple visuals, or something like that. The code seems all fine to me, though, so I'm a bit at a loss.

Try this code to see what I mean:
```py
import napari
import numpy as np
v = napari.Viewer()
np.random.seed(0)
i = v.add_image(np.random.rand(50, 50), blending='additive')
p = v.add_points(np.random.rand(10, 2) * 70, blending='opaque')
```

If you zoom/click the canvas, the issue happens. If you change the image to `opaque` or `translucent`, all works fine. If you change to `minimum` the points will disappear completely!


Resolving patch:
diff --git a/napari/_vispy/utils/gl.py b/napari/_vispy/utils/gl.py
--- a/napari/_vispy/utils/gl.py
+++ b/napari/_vispy/utils/gl.py
@@ -112,8 +112,20 @@ def fix_data_dtype(data):
 
 
 BLENDING_MODES = {
-    'opaque': dict(preset='opaque'),
-    'translucent': dict(preset='translucent'),
+    'opaque': dict(
+        depth_test=True,
+        cull_face=False,
+        blend=False,
+        blend_func=('one', 'zero'),
+        blend_equation='func_add',
+    ),
+    'translucent': dict(
+        depth_test=True,
+        cull_face=False,
+        blend=True,
+        blend_func=('src_alpha', 'one_minus_src_alpha', 'zero', 'one'),
+        blend_equation='func_add',
+    ),
     'translucent_no_depth': dict(
         depth_test=False,
         cull_face=False,
@@ -121,8 +133,18 @@ def fix_data_dtype(data):
         blend_func=('src_alpha', 'one_minus_src_alpha', 'zero', 'one'),
         blend_equation='func_add',  # see vispy/vispy#2324
     ),
-    'additive': dict(preset='additive'),
+    'additive': dict(
+        depth_test=False,
+        cull_face=False,
+        blend=True,
+        blend_func=('src_alpha', 'one'),
+        blend_equation='func_add',
+    ),
     'minimum': dict(
-        depth_test=False, cull_face=False, blend=True, blend_equation='min'
+        depth_test=False,
+        cull_face=False,
+        blend=True,
+        blend_func=('one', 'one'),
+        blend_equation='min',
     ),
 }


Test patch: