diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 03ae28e275..02d5ff1c67 100644 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -13,6 +13,7 @@ from UM.Math.Color import Color from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.Polygon import Polygon from UM.Message import Message +from UM.Signal import Signal from UM.View.RenderBatch import RenderBatch from UM.View.GL.OpenGL import OpenGL @@ -49,6 +50,8 @@ def approximatedCircleVertices(r): class BuildVolume(SceneNode): VolumeOutlineColor = Color(12, 169, 227, 255) + raftThicknessChanged = Signal() + def __init__(self, parent = None): super().__init__(parent) @@ -69,7 +72,6 @@ class BuildVolume(SceneNode): self._raft_thickness = 0.0 self._adhesion_type = None - self._raft_mesh = None self._platform = Platform(self) self._active_container_stack = None @@ -103,8 +105,6 @@ class BuildVolume(SceneNode): renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True) if self._disallowed_area_mesh: renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9) - if self._raft_mesh and self._adhesion_type == "raft": - renderer.queueNode(self, mesh=self._raft_mesh, transparent=True, backface_cull=True, sort=-9) return True @@ -153,17 +153,6 @@ class BuildVolume(SceneNode): mb.setVertexUVCoordinates(n, v[0], v[2]) self._grid_mesh = mb.build() - # Build raft mesh: a plane on the height of the raft. - mb = MeshBuilder() - mb.addQuad( - Vector(min_w, self._raft_thickness, min_d), - Vector(max_w, self._raft_thickness, min_d), - Vector(max_w, self._raft_thickness, max_d), - Vector(min_w, self._raft_thickness, max_d), - color=Color(128, 128, 128, 64) - ) - self._raft_mesh = mb.build() - disallowed_area_height = 0.1 disallowed_area_size = 0 if self._disallowed_areas: @@ -221,6 +210,9 @@ class BuildVolume(SceneNode): " \"Print Sequence\" setting to prevent the gantry from colliding" " with printed objects."), lifetime=10).show() + def getRaftThickness(self): + return self._raft_thickness + def _updateRaftThickness(self): old_raft_thickness = self._raft_thickness self._adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value") @@ -232,9 +224,11 @@ class BuildVolume(SceneNode): self._active_container_stack.getProperty("raft_surface_layers", "value") * self._active_container_stack.getProperty("raft_surface_thickness", "value") + self._active_container_stack.getProperty("raft_airgap", "value")) + # Rounding errors do not matter, we check if raft_thickness has changed at all if old_raft_thickness != self._raft_thickness: self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World) + self.raftThicknessChanged.emit() def _onGlobalContainerStackChanged(self): if self._active_container_stack: diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index 3ccb9481f9..348a747f9c 100644 --- a/cura/ConvexHullDecorator.py +++ b/cura/ConvexHullDecorator.py @@ -15,6 +15,11 @@ class ConvexHullDecorator(SceneNodeDecorator): self._convex_hull_node = None self._init2DConvexHullCache() + self._raft_thickness = 0.0 + # For raft thickness, DRY + self._build_volume = Application.getInstance().getBuildVolume() + self._build_volume.raftThicknessChanged.connect(self._onChanged) + self._global_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) Application.getInstance().getController().toolOperationStarted.connect(self._onChanged) @@ -93,14 +98,17 @@ class ConvexHullDecorator(SceneNodeDecorator): convex_hull = self.getConvexHull() if self._convex_hull_node: - if self._convex_hull_node.getHull() == convex_hull: + # Check if convex hull has changed + if (self._convex_hull_node.getHull() == convex_hull and + self._convex_hull_node.getThickness() == self._raft_thickness): + return self._convex_hull_node.setParent(None) - hull_node = ConvexHullNode.ConvexHullNode(self._node, convex_hull, root) + hull_node = ConvexHullNode.ConvexHullNode(self._node, convex_hull, self._raft_thickness, root) self._convex_hull_node = hull_node def _onSettingValueChanged(self, key, property_name): - if key == "print_sequence" and property_name == "value": + if key in self._affected_settings and property_name == "value": self._onChanged() def _init2DConvexHullCache(self): @@ -157,7 +165,8 @@ class ConvexHullDecorator(SceneNodeDecorator): vertex_data = mesh.getConvexHullTransformedVertices(world_transform) # Don't use data below 0. # TODO; We need a better check for this as this gives poor results for meshes with long edges. - vertex_data = vertex_data[vertex_data[:,1] >= -0.01] + # Do not throw away vertices: the convex hull may be too small and objects can collide. + # vertex_data = vertex_data[vertex_data[:,1] >= -0.01] if len(vertex_data) >= 4: # Round the vertex data to 1/10th of a mm, then remove all duplicate vertices @@ -213,6 +222,7 @@ class ConvexHullDecorator(SceneNodeDecorator): return convex_hull.getMinkowskiHull(Polygon(numpy.array([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32))) def _onChanged(self, *args): + self._raft_thickness = self._build_volume.getRaftThickness() self.recomputeConvexHull() def _onGlobalStackChanged(self): @@ -235,3 +245,7 @@ class ConvexHullDecorator(SceneNodeDecorator): if root is node: return True return self.__isDescendant(root, node.getParent()) + + _affected_settings = [ + "adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", + "raft_surface_thickness", "raft_airgap", "print_sequence"] diff --git a/cura/ConvexHullNode.py b/cura/ConvexHullNode.py index be571d111e..53bee40a8e 100644 --- a/cura/ConvexHullNode.py +++ b/cura/ConvexHullNode.py @@ -4,16 +4,16 @@ from UM.Scene.SceneNode import SceneNode from UM.Resources import Resources from UM.Math.Color import Color -from UM.Math.Vector import Vector from UM.Mesh.MeshBuilder import MeshBuilder # To create a mesh to display the convex hull with. from UM.View.GL.OpenGL import OpenGL class ConvexHullNode(SceneNode): - ## Convex hull node is a special type of scene node that is used to display a 2D area, to indicate the + ## Convex hull node is a special type of scene node that is used to display an area, to indicate the # location an object uses on the buildplate. This area (or area's in case of one at a time printing) is - # then displayed as a transparent shadow. - def __init__(self, node, hull, parent = None): + # then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded + # to represent the raft as well. + def __init__(self, node, hull, thickness, parent = None): super().__init__(parent) self.setCalculateBoundingBox(False) @@ -23,7 +23,7 @@ class ConvexHullNode(SceneNode): self._original_parent = parent # Color of the drawn convex hull - self._color = Color(35, 35, 35, 128) + self._color = Color(35, 35, 35, 192) # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting. self._mesh_height = 0.1 @@ -34,11 +34,17 @@ class ConvexHullNode(SceneNode): self._onNodeDecoratorsChanged(self._node) self._convex_hull_head_mesh = None - self._hull = hull + self._hull = hull + self._thickness = thickness if self._hull: - hull_mesh = self.createHullMesh(self._hull.getPoints()) - if hull_mesh: + hull_mesh_builder = MeshBuilder() + + if hull_mesh_builder.addConvexPolygonExtrusion( + self._hull.getPoints()[::-1], # bottom layer is reversed + self._mesh_height-thickness, self._mesh_height, color=self._color): + + hull_mesh = hull_mesh_builder.build() self.setMeshData(hull_mesh) convex_hull_head = self._node.callDecoration("getConvexHullHead") if convex_hull_head: @@ -47,31 +53,17 @@ class ConvexHullNode(SceneNode): def getHull(self): return self._hull - ## Actually create the mesh from the hullpoints - # /param hull_points list of xy values - # /return meshData - def createHullMesh(self, hull_points): - # Input checking. - if len(hull_points) < 3: - return None - - mesh_builder = MeshBuilder() - point_first = Vector(hull_points[0][0], self._mesh_height, hull_points[0][1]) - point_previous = Vector(hull_points[1][0], self._mesh_height, hull_points[1][1]) - for point in hull_points[2:]: # Add the faces in the order of a triangle fan. - point_new = Vector(point[0], self._mesh_height, point[1]) - mesh_builder.addFace(point_first, point_previous, point_new, color = self._color) - point_previous = point_new # Prepare point_previous for the next triangle. - - return mesh_builder.build() + def getThickness(self): + return self._thickness def getWatchedNode(self): return self._node def render(self, renderer): if not self._shader: - self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader")) - self._shader.setUniformValue("u_color", self._color) + self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader")) + self._shader.setUniformValue("u_diffuseColor", self._color) + self._shader.setUniformValue("u_opacity", 0.6) if self.getParent(): if self.getMeshData(): @@ -85,4 +77,5 @@ class ConvexHullNode(SceneNode): self._color = Color(35, 35, 35, 0.5) if not node: - return \ No newline at end of file + return + diff --git a/resources/shaders/transparent_object.shader b/resources/shaders/transparent_object.shader new file mode 100644 index 0000000000..a3790901bc --- /dev/null +++ b/resources/shaders/transparent_object.shader @@ -0,0 +1,74 @@ +[shaders] +vertex = + uniform highp mat4 u_viewProjectionMatrix; + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_normalMatrix; + + attribute highp vec4 a_vertex; + attribute highp vec4 a_normal; + attribute highp vec2 a_uvs; + + varying highp vec3 v_vertex; + varying highp vec3 v_normal; + varying highp vec2 v_uvs; + + void main() + { + vec4 world_space_vert = u_modelMatrix * a_vertex; + gl_Position = u_viewProjectionMatrix * world_space_vert; + + v_vertex = world_space_vert.xyz; + v_normal = (u_normalMatrix * normalize(a_normal)).xyz; + + v_uvs = a_uvs; + } + +fragment = + uniform mediump vec4 u_ambientColor; + uniform mediump vec4 u_diffuseColor; + uniform highp vec3 u_lightPosition; + uniform highp vec3 u_viewPosition; + uniform mediump float u_opacity; + uniform sampler2D u_texture; + + varying highp vec3 v_vertex; + varying highp vec3 v_normal; + varying highp vec2 v_uvs; + + void main() + { + // Copied from platform.shader, removed texture + mediump vec4 final_color = vec4(0.0); + + /* Ambient Component */ + final_color += u_ambientColor; + + highp vec3 normal = normalize(v_normal); + highp vec3 light_dir = normalize(u_lightPosition - v_vertex); + + /* Diffuse Component */ + highp float n_dot_l = clamp(dot(normal, light_dir), 0.0, 1.0); + final_color += (n_dot_l * u_diffuseColor); + + final_color.a = u_opacity; + + gl_FragColor = final_color; + } + +[defaults] +u_ambientColor = [0.3, 0.3, 0.3, 1.0] +u_diffuseColor = [1.0, 1.0, 1.0, 1.0] +u_opacity = 0.5 +u_texture = 0 + +[bindings] +u_viewProjectionMatrix = view_projection_matrix +u_modelMatrix = model_matrix +u_normalMatrix = normal_matrix +u_lightPosition = light_0_position +u_viewPosition = camera_position + +[attributes] +a_vertex = vertex +a_normal = normal +a_uvs = uv0