Browse Source

show xray errors in solid view

Tim Kuipers 5 years ago
parent
commit
fc4c66b62a

+ 2 - 1
plugins/XRayView/XRayPass.py → cura/XRayPass.py

@@ -3,6 +3,7 @@
 
 import os.path
 
+from UM.Resources import Resources
 from UM.Application import Application
 from UM.PluginRegistry import PluginRegistry
 
@@ -23,7 +24,7 @@ class XRayPass(RenderPass):
 
     def render(self):
         if not self._shader:
-            self._shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray.shader"))
+            self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "xray.shader"))
 
         batch = RenderBatch(self._shader, type = RenderBatch.RenderType.NoType, backface_cull = False, blend_mode = RenderBatch.BlendMode.Additive)
         for node in DepthFirstIterator(self._scene.getRoot()):

+ 73 - 1
plugins/SolidView/SolidView.py

@@ -1,17 +1,29 @@
 # Copyright (c) 2019 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 
+import os.path
 from UM.View.View import View
 from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
 from UM.Scene.Selection import Selection
 from UM.Resources import Resources
+from PyQt5.QtGui import QOpenGLContext
+
 from UM.Application import Application
-from UM.View.RenderBatch import RenderBatch
+from UM.Logger import Logger
 from UM.Math.Color import Color
+from UM.PluginRegistry import PluginRegistry
+from UM.Platform import Platform
+from UM.Event import Event
+
+from UM.View.RenderBatch import RenderBatch
 from UM.View.GL.OpenGL import OpenGL
 
+from cura.CuraApplication import CuraApplication
+
 from cura.Settings.ExtruderManager import ExtruderManager
 
+from cura import XRayPass
+
 import math
 
 ## Standard view for mesh models.
@@ -27,12 +39,20 @@ class SolidView(View):
         self._non_printing_shader = None
         self._support_mesh_shader = None
 
+        self._xray_shader = None
+        self._xray_pass = None
+        self._xray_composite_shader = None
+        self._composite_pass = None
+
         self._extruders_model = None
         self._theme = None
         self._support_angle = 90
 
         self._global_stack = None
 
+        self._old_composite_shader = None
+        self._old_layer_bindings = None
+
         Application.getInstance().engineCreatedSignal.connect(self._onGlobalContainerChanged)
 
     def _onGlobalContainerChanged(self) -> None:
@@ -98,6 +118,32 @@ class SolidView(View):
 
         self._checkSetup()
 
+        if not self._xray_shader:
+            self._xray_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "xray.shader"))
+            self._xray_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("xray").getRgb()))
+
+        if not self._xray_composite_shader:
+            self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SolidView"), "xray_composite.shader"))
+            theme = Application.getInstance().getTheme()
+            self._xray_composite_shader.setUniformValue("u_background_color", Color(*theme.getColor("viewport_background").getRgb()))
+            self._xray_composite_shader.setUniformValue("u_error_color", Color(*theme.getColor("xray_error").getRgb()))
+            self._xray_composite_shader.setUniformValue("u_outline_color", Color(*theme.getColor("model_selection_outline").getRgb()))
+
+        if not self.getRenderer().getRenderPass("xray"):
+            # Currently the RenderPass constructor requires a size > 0
+            # This should be fixed in RenderPass's constructor.
+            self._xray_pass = XRayPass.XRayPass(1, 1)
+
+            self.getRenderer().addRenderPass(self._xray_pass)
+
+            if not self._composite_pass:
+                self._composite_pass = self.getRenderer().getRenderPass("composite")
+
+            self._old_layer_bindings = self._composite_pass.getLayerBindings()
+            self._composite_pass.setLayerBindings(["default", "selection", "xray"])
+            self._old_composite_shader = self._composite_pass.getCompositeShader()
+            self._composite_pass.setCompositeShader(self._xray_composite_shader)
+
         global_container_stack = Application.getInstance().getGlobalContainerStack()
         if global_container_stack:
             if Application.getInstance().getPreferences().getValue("view/show_overhang"):
@@ -174,5 +220,31 @@ class SolidView(View):
                 if node.callDecoration("isGroup") and Selection.isSelected(node):
                     renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = RenderBatch.RenderMode.LineLoop)
 
+
     def endRendering(self):
         pass
+
+    def event(self, event):
+        if event.type == Event.ViewActivateEvent:
+            # FIX: on Max OS X, somehow QOpenGLContext.currentContext() can become None during View switching.
+            # This can happen when you do the following steps:
+            #   1. Start Cura
+            #   2. Load a model
+            #   3. Switch to Custom mode
+            #   4. Select the model and click on the per-object tool icon
+            #   5. Switch view to Layer view or X-Ray
+            #   6. Cura will very likely crash
+            # It seems to be a timing issue that the currentContext can somehow be empty, but I have no clue why.
+            # This fix tries to reschedule the view changing event call on the Qt thread again if the current OpenGL
+            # context is None.
+            if Platform.isOSX():
+                if QOpenGLContext.currentContext() is None:
+                    Logger.log("d", "current context of OpenGL is empty on Mac OS X, will try to create shaders later")
+                    CuraApplication.getInstance().callLater(lambda e = event: self.event(e))
+                    return
+
+
+        if event.type == Event.ViewDeactivateEvent:
+            self.getRenderer().removeRenderPass(self._xray_pass)
+            self._composite_pass.setLayerBindings(self._old_layer_bindings)
+            self._composite_pass.setCompositeShader(self._old_composite_shader)

+ 166 - 0
plugins/SolidView/xray_composite.shader

@@ -0,0 +1,166 @@
+[shaders]
+vertex =
+    uniform highp mat4 u_modelViewProjectionMatrix;
+    attribute highp vec4 a_vertex;
+    attribute highp vec2 a_uvs;
+
+    varying highp vec2 v_uvs;
+
+    void main()
+    {
+        gl_Position = u_modelViewProjectionMatrix * a_vertex;
+        v_uvs = a_uvs;
+    }
+
+fragment =
+    #ifdef GL_ES
+        #ifdef GL_FRAGMENT_PRECISION_HIGH
+            precision highp float;
+        #else
+            precision mediump float;
+        #endif // GL_FRAGMENT_PRECISION_HIGH
+    #endif // GL_ES
+    uniform sampler2D u_layer0; //Default pass.
+    uniform sampler2D u_layer1; //Selection pass.
+    uniform sampler2D u_layer2; //X-ray pass.
+
+    uniform vec2 u_offset[9];
+
+    uniform float u_outline_strength;
+    uniform vec4 u_outline_color;
+    uniform vec4 u_error_color;
+    uniform vec4 u_background_color;
+
+    const vec3 x_axis = vec3(1.0, 0.0, 0.0);
+    const vec3 y_axis = vec3(0.0, 1.0, 0.0);
+    const vec3 z_axis = vec3(0.0, 0.0, 1.0);
+
+    varying vec2 v_uvs;
+
+    float kernel[9];
+
+    void main()
+    {
+        kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0;
+        kernel[3] = 1.0; kernel[4] = -4.0; kernel[5] = 1.0;
+        kernel[6] = 0.0; kernel[7] = 1.0; kernel[8] = 0.0;
+
+        vec4 result = u_background_color;
+        vec4 layer0 = texture2D(u_layer0, v_uvs);
+
+        result = layer0 * layer0.a + result * (1.0 - layer0.a);
+
+        float intersection_count = (texture2D(u_layer2, v_uvs).r * 255.0) / 5.0;
+        if(mod(intersection_count, 2.0) >= 1.0)
+        {
+            result = u_error_color;
+        }
+
+        vec4 sum = vec4(0.0);
+        for (int i = 0; i < 9; i++)
+        {
+            vec4 color = vec4(texture2D(u_layer1, v_uvs.xy + u_offset[i]).a);
+            sum += color * (kernel[i] / u_outline_strength);
+        }
+
+        vec4 layer1 = texture2D(u_layer1, v_uvs);
+        if((layer1.rgb == x_axis || layer1.rgb == y_axis || layer1.rgb == z_axis))
+        {
+            gl_FragColor = result;
+        }
+        else
+        {
+            gl_FragColor = mix(result, u_outline_color, abs(sum.a));
+        }
+
+        gl_FragColor.a = gl_FragColor.a > 0.5 ? 1.0 : 0.0;
+    }
+
+vertex41core =
+    #version 410
+    uniform highp mat4 u_modelViewProjectionMatrix;
+    in highp vec4 a_vertex;
+    in highp vec2 a_uvs;
+
+    out highp vec2 v_uvs;
+
+    void main()
+    {
+        gl_Position = u_modelViewProjectionMatrix * a_vertex;
+        v_uvs = a_uvs;
+    }
+
+fragment41core =
+    #version 410
+    uniform sampler2D u_layer0; //Default pass.
+    uniform sampler2D u_layer1; //Selection pass.
+    uniform sampler2D u_layer2; //X-ray pass.
+
+    uniform vec2 u_offset[9];
+
+    uniform float u_outline_strength;
+    uniform vec4 u_outline_color;
+    uniform vec4 u_error_color;
+    uniform vec4 u_background_color;
+
+    const vec3 x_axis = vec3(1.0, 0.0, 0.0);
+    const vec3 y_axis = vec3(0.0, 1.0, 0.0);
+    const vec3 z_axis = vec3(0.0, 0.0, 1.0);
+
+    in vec2 v_uvs;
+    out vec4 frag_color;
+
+    float kernel[9];
+
+    void main()
+    {
+        kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0;
+        kernel[3] = 1.0; kernel[4] = -4.0; kernel[5] = 1.0;
+        kernel[6] = 0.0; kernel[7] = 1.0; kernel[8] = 0.0;
+
+        vec4 result = u_background_color;
+        vec4 layer0 = texture(u_layer0, v_uvs);
+
+        result = layer0 * layer0.a + result * (1.0 - layer0.a);
+
+        float intersection_count = (texture(u_layer2, v_uvs).r * 255.0) / 5.0;
+        if(mod(intersection_count, 2.0) >= 1.0)
+        {
+            result = u_error_color;
+        }
+
+        vec4 sum = vec4(0.0);
+        for (int i = 0; i < 9; i++)
+        {
+            vec4 color = vec4(texture(u_layer1, v_uvs.xy + u_offset[i]).a);
+            sum += color * (kernel[i] / u_outline_strength);
+        }
+
+        vec4 layer1 = texture(u_layer1, v_uvs);
+        if((layer1.rgb == x_axis || layer1.rgb == y_axis || layer1.rgb == z_axis))
+        {
+            frag_color = result;
+        }
+        else
+        {
+            frag_color = mix(result, u_outline_color, abs(sum.a));
+        }
+
+        frag_color.a = frag_color.a > 0.5 ? 1.0 : 0.0;
+    }
+
+[defaults]
+u_layer0 = 0
+u_layer1 = 1
+u_layer2 = 2
+u_background_color = [0.965, 0.965, 0.965, 1.0]
+u_outline_strength = 1.0
+u_outline_color = [0.05, 0.66, 0.89, 1.0]
+u_error_color = [1.0, 0.0, 0.0, 1.0]
+
+[bindings]
+
+[attributes]
+a_vertex = vertex
+a_uvs = uv
+

+ 50 - 0
plugins/SolidView/xray_overlay.shader

@@ -0,0 +1,50 @@
+[shaders]
+vertex =
+    uniform highp mat4 u_modelViewProjectionMatrix;
+
+    attribute highp vec4 a_vertex;
+
+    void main()
+    {
+        gl_Position = u_modelViewProjectionMatrix * a_vertex;
+    }
+
+fragment =
+    uniform lowp vec4 u_xray_error;
+
+    void main()
+    {
+        gl_FragColor = u_xray_error;
+    }
+
+vertex41core =
+    #version 410
+    uniform highp mat4 u_modelViewProjectionMatrix;
+
+    in highp vec4 a_vertex;
+
+    void main()
+    {
+        gl_Position = u_modelViewProjectionMatrix * a_vertex;
+    }
+
+fragment41core =
+    #version 410
+    uniform lowp vec4 u_xray_error;
+
+    out vec4 frag_color;
+
+    void main()
+    {
+
+        frag_color = u_xray_error;
+    }
+
+[defaults]
+u_xray_error = [1.0, 1.0, 1.0, 1.0]
+
+[bindings]
+u_modelViewProjectionMatrix = model_view_projection_matrix
+
+[attributes]
+a_vertex = vertex

+ 4 - 2
plugins/XRayView/XRayView.py

@@ -8,6 +8,7 @@ from UM.Application import Application
 from UM.Logger import Logger
 from UM.Math.Color import Color
 from UM.PluginRegistry import PluginRegistry
+from UM.Resources import Resources
 from UM.Platform import Platform
 from UM.Event import Event
 from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
@@ -19,7 +20,8 @@ from cura.CuraApplication import CuraApplication
 from cura.CuraView import CuraView
 from cura.Scene.ConvexHullNode import ConvexHullNode
 
-from . import XRayPass
+from cura import XRayPass
+
 
 ## View used to display a see-through version of objects with errors highlighted.
 class XRayView(CuraView):
@@ -38,7 +40,7 @@ class XRayView(CuraView):
         renderer = self.getRenderer()
 
         if not self._xray_shader:
-            self._xray_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray.shader"))
+            self._xray_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "xray.shader"))
             self._xray_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("xray").getRgb()))
 
         for node in BreadthFirstIterator(scene.getRoot()):

+ 0 - 0
plugins/XRayView/xray.shader → resources/shaders/xray.shader