Added an extruded convex hull as a raft instead of a grey plane.

- New shader transparent_object.shader
- Raft thickness is calculated in BuildVolume and used in
  ConvexHullDecorator, notified by a Signal.
- Removed old grey plane from BuildVolume.
- Vertex data below build plane is no longer discarded (caused convex
  hulls that are too small).
- Uses new functions in MeshBuilder (update Uranium as well).

CURA-1707
This commit is contained in:
Jack Ha 2016-07-25 16:45:38 +02:00
parent 2d34e2b28e
commit d77f6e86e4
4 changed files with 121 additions and 46 deletions

View file

@ -13,6 +13,7 @@ from UM.Math.Color import Color
from UM.Math.AxisAlignedBox import AxisAlignedBox from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Math.Polygon import Polygon from UM.Math.Polygon import Polygon
from UM.Message import Message from UM.Message import Message
from UM.Signal import Signal
from UM.View.RenderBatch import RenderBatch from UM.View.RenderBatch import RenderBatch
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
@ -49,6 +50,8 @@ def approximatedCircleVertices(r):
class BuildVolume(SceneNode): class BuildVolume(SceneNode):
VolumeOutlineColor = Color(12, 169, 227, 255) VolumeOutlineColor = Color(12, 169, 227, 255)
raftThicknessChanged = Signal()
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
@ -69,7 +72,6 @@ class BuildVolume(SceneNode):
self._raft_thickness = 0.0 self._raft_thickness = 0.0
self._adhesion_type = None self._adhesion_type = None
self._raft_mesh = None
self._platform = Platform(self) self._platform = Platform(self)
self._active_container_stack = None 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) renderer.queueNode(self, mesh = self._grid_mesh, shader = self._grid_shader, backface_cull = True)
if self._disallowed_area_mesh: if self._disallowed_area_mesh:
renderer.queueNode(self, mesh = self._disallowed_area_mesh, shader = self._shader, transparent = True, backface_cull = True, sort = -9) 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 return True
@ -153,17 +153,6 @@ class BuildVolume(SceneNode):
mb.setVertexUVCoordinates(n, v[0], v[2]) mb.setVertexUVCoordinates(n, v[0], v[2])
self._grid_mesh = mb.build() 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_height = 0.1
disallowed_area_size = 0 disallowed_area_size = 0
if self._disallowed_areas: if self._disallowed_areas:
@ -221,6 +210,9 @@ class BuildVolume(SceneNode):
" \"Print Sequence\" setting to prevent the gantry from colliding" " \"Print Sequence\" setting to prevent the gantry from colliding"
" with printed objects."), lifetime=10).show() " with printed objects."), lifetime=10).show()
def getRaftThickness(self):
return self._raft_thickness
def _updateRaftThickness(self): def _updateRaftThickness(self):
old_raft_thickness = self._raft_thickness old_raft_thickness = self._raft_thickness
self._adhesion_type = self._active_container_stack.getProperty("adhesion_type", "value") 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_layers", "value") *
self._active_container_stack.getProperty("raft_surface_thickness", "value") + self._active_container_stack.getProperty("raft_surface_thickness", "value") +
self._active_container_stack.getProperty("raft_airgap", "value")) self._active_container_stack.getProperty("raft_airgap", "value"))
# Rounding errors do not matter, we check if raft_thickness has changed at all # Rounding errors do not matter, we check if raft_thickness has changed at all
if old_raft_thickness != self._raft_thickness: if old_raft_thickness != self._raft_thickness:
self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World) self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World)
self.raftThicknessChanged.emit()
def _onGlobalContainerStackChanged(self): def _onGlobalContainerStackChanged(self):
if self._active_container_stack: if self._active_container_stack:

View file

@ -15,6 +15,11 @@ class ConvexHullDecorator(SceneNodeDecorator):
self._convex_hull_node = None self._convex_hull_node = None
self._init2DConvexHullCache() 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 self._global_stack = None
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
Application.getInstance().getController().toolOperationStarted.connect(self._onChanged) Application.getInstance().getController().toolOperationStarted.connect(self._onChanged)
@ -93,14 +98,17 @@ class ConvexHullDecorator(SceneNodeDecorator):
convex_hull = self.getConvexHull() convex_hull = self.getConvexHull()
if self._convex_hull_node: 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 return
self._convex_hull_node.setParent(None) 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 self._convex_hull_node = hull_node
def _onSettingValueChanged(self, key, property_name): 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() self._onChanged()
def _init2DConvexHullCache(self): def _init2DConvexHullCache(self):
@ -157,7 +165,8 @@ class ConvexHullDecorator(SceneNodeDecorator):
vertex_data = mesh.getConvexHullTransformedVertices(world_transform) vertex_data = mesh.getConvexHullTransformedVertices(world_transform)
# Don't use data below 0. # Don't use data below 0.
# TODO; We need a better check for this as this gives poor results for meshes with long edges. # 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: if len(vertex_data) >= 4:
# Round the vertex data to 1/10th of a mm, then remove all duplicate vertices # 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))) 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): def _onChanged(self, *args):
self._raft_thickness = self._build_volume.getRaftThickness()
self.recomputeConvexHull() self.recomputeConvexHull()
def _onGlobalStackChanged(self): def _onGlobalStackChanged(self):
@ -235,3 +245,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
if root is node: if root is node:
return True return True
return self.__isDescendant(root, node.getParent()) 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"]

View file

@ -4,16 +4,16 @@
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Resources import Resources from UM.Resources import Resources
from UM.Math.Color import Color 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.Mesh.MeshBuilder import MeshBuilder # To create a mesh to display the convex hull with.
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
class ConvexHullNode(SceneNode): 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 # 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. # then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded
def __init__(self, node, hull, parent = None): # to represent the raft as well.
def __init__(self, node, hull, thickness, parent = None):
super().__init__(parent) super().__init__(parent)
self.setCalculateBoundingBox(False) self.setCalculateBoundingBox(False)
@ -23,7 +23,7 @@ class ConvexHullNode(SceneNode):
self._original_parent = parent self._original_parent = parent
# Color of the drawn convex hull # 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. # The y-coordinate of the convex hull mesh. Must not be 0, to prevent z-fighting.
self._mesh_height = 0.1 self._mesh_height = 0.1
@ -34,11 +34,17 @@ class ConvexHullNode(SceneNode):
self._onNodeDecoratorsChanged(self._node) self._onNodeDecoratorsChanged(self._node)
self._convex_hull_head_mesh = None self._convex_hull_head_mesh = None
self._hull = hull
self._hull = hull
self._thickness = thickness
if self._hull: if self._hull:
hull_mesh = self.createHullMesh(self._hull.getPoints()) hull_mesh_builder = MeshBuilder()
if hull_mesh:
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) self.setMeshData(hull_mesh)
convex_hull_head = self._node.callDecoration("getConvexHullHead") convex_hull_head = self._node.callDecoration("getConvexHullHead")
if convex_hull_head: if convex_hull_head:
@ -47,31 +53,17 @@ class ConvexHullNode(SceneNode):
def getHull(self): def getHull(self):
return self._hull return self._hull
## Actually create the mesh from the hullpoints def getThickness(self):
# /param hull_points list of xy values return self._thickness
# /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 getWatchedNode(self): def getWatchedNode(self):
return self._node return self._node
def render(self, renderer): def render(self, renderer):
if not self._shader: if not self._shader:
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader")) self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
self._shader.setUniformValue("u_color", self._color) self._shader.setUniformValue("u_diffuseColor", self._color)
self._shader.setUniformValue("u_opacity", 0.6)
if self.getParent(): if self.getParent():
if self.getMeshData(): if self.getMeshData():
@ -85,4 +77,5 @@ class ConvexHullNode(SceneNode):
self._color = Color(35, 35, 35, 0.5) self._color = Color(35, 35, 35, 0.5)
if not node: if not node:
return return

View file

@ -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