Repository: napari/napari

Issue:
Bad 3D rendering of labels
## 🐛 Bug

I get some bad rendering of labels data in 3D, running the code in this gist:

https://gist.github.com/jni/587d8a946e5e86a8c0d3a7f8bee329cc

with `ipython --gui=qt` then `%run -i rendering.py`

<img width="1200" alt="Screen Shot 2019-10-08 at 12 45 45 pm" src="https://user-images.githubusercontent.com/492549/66361390-59c10b80-e9ca-11e9-9c19-a093758f613c.png">

The issue seems to be that the layer values are interpolated, which causes the crazy fringing with the random colormap. Note that I played around with the interpolation method in the image layers, but the problem does persist after restarting Python.

Additionally, "mip" rendering is a poor choice for labels, because high-value labels appear on top of low-value ones, even when the low labels are in front of the high ones. However, translucent rendering did not fix the fringing problem, so it still looks terrible for me.

## To Reproduce

Steps to reproduce the behavior:

1. Download https://gist.github.com/jni/587d8a946e5e86a8c0d3a7f8bee329cc to a file named `rendering.py`
2. Launch `ipython --gui=qt` in that directory.
3. Run `%run -i rendering.py`

## Expected behavior

<!-- A clear and concise description of what you expected to happen. -->

## Environment

 - napari Version (e.g., 1.0): master
 - OS (e.g., Linux): macOS 10.14.6
 - Python version: 3.7.3
 - Any other relevant information: vispy version 0.6.1



Discussion:
I can reproduce this effect on my laptop - both the fringes and the poor order behavior of `mip`. If I switch to `translucent` the order problems go away, but the fringes are terrible, which is likely due to the interpolation @jni mentioned and problems with our colormap
I think we are probably going to need to mess with the shaders in vispy to fix this one, since as far as I can tell VisPy does not expose the ability to remove interpolation in the Volume Rendering view.

Resolving patch:
diff --git a/napari/_vispy/vispy_image_layer.py b/napari/_vispy/vispy_image_layer.py
--- a/napari/_vispy/vispy_image_layer.py
+++ b/napari/_vispy/vispy_image_layer.py
@@ -5,6 +5,8 @@
 import numpy as np
 from .vispy_base_layer import VispyBaseLayer
 from ..layers.image._constants import Rendering
+from ..layers import Image, Labels
+
 
 texture_dtypes = [
     np.dtype(np.int8),
@@ -101,7 +103,11 @@ def _on_data_change(self):
         self.node.update()
 
     def _on_interpolation_change(self):
-        if self.layer.dims.ndisplay == 2:
+        if self.layer.dims.ndisplay == 3 and isinstance(self.layer, Labels):
+            self.node.interpolation = 'nearest'
+        elif self.layer.dims.ndisplay == 3 and isinstance(self.layer, Image):
+            self.node.interpolation = 'linear'
+        else:
             self.node.interpolation = self.layer.interpolation
 
     def _on_rendering_change(self):
diff --git a/napari/_vispy/volume.py b/napari/_vispy/volume.py
--- a/napari/_vispy/volume.py
+++ b/napari/_vispy/volume.py
@@ -327,7 +327,10 @@
 
 # Custom volume class is needed for better 3D rendering
 class Volume(BaseVolume):
+    _interpolation_names = ['linear', 'nearest']
+
     def __init__(self, *args, **kwargs):
+        self._interpolation = 'linear'
         super().__init__(*args, **kwargs)
 
     @property
@@ -372,3 +375,19 @@ def method(self, method):
             else None
         )
         self.update()
+
+    @property
+    def interpolation(self):
+        return self._interpolation
+
+    @interpolation.setter
+    def interpolation(self, interp):
+        if interp not in self._interpolation_names:
+            raise ValueError(
+                "interpolation must be one of %s"
+                % ', '.join(self._interpolation_names)
+            )
+        if self._interpolation != interp:
+            self._interpolation = interp
+            self._tex.interpolation = self._interpolation
+            self.update()
diff --git a/napari/layers/labels/labels.py b/napari/layers/labels/labels.py
--- a/napari/layers/labels/labels.py
+++ b/napari/layers/labels/labels.py
@@ -138,7 +138,7 @@ def __init__(
             colormap=colormap,
             contrast_limits=[0.0, 1.0],
             interpolation='nearest',
-            rendering='mip',
+            rendering='translucent',
             name=name,
             metadata=metadata,
             scale=scale,


Test patch: