From 0d7421140f496498ae47a21a87a25cee89ceed87 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jan 2020 13:26:39 +0100 Subject: [PATCH 1/3] Recalculate the start / end elements when the layer is changed instead of on render About with larger models, about 30-40% of the time of the render was spent on this. --- plugins/SimulationView/SimulationPass.py | 39 +++++++++--------------- plugins/SimulationView/SimulationView.py | 23 +++++++++++++- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index cd0eda2929..f9bbb808c4 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -93,7 +93,6 @@ class SimulationPass(RenderPass): self.bind() tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay, backface_cull = True) - active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate head_position = None # Indicates the current position of the print head nozzle_node = None @@ -113,29 +112,21 @@ class SimulationPass(RenderPass): # Render all layers below a certain number as line mesh instead of vertices. if self._layer_view._current_layer_num > -1 and ((not self._layer_view._only_show_top_layers) or (not self._layer_view.getCompatibilityMode())): - start = 0 - end = 0 - element_counts = layer_data.getElementCounts() - for layer in sorted(element_counts.keys()): - # In the current layer, we show just the indicated paths - if layer == self._layer_view._current_layer_num: - # We look for the position of the head, searching the point of the current path - index = self._layer_view._current_path_num - offset = 0 - for polygon in layer_data.getLayer(layer).polygons: - # The size indicates all values in the two-dimension array, and the second dimension is - # always size 3 because we have 3D points. - if index >= polygon.data.size // 3 - offset: - index -= polygon.data.size // 3 - offset - offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon - continue - # The head position is calculated and translated - head_position = Vector(polygon.data[index+offset][0], polygon.data[index+offset][1], polygon.data[index+offset][2]) + node.getWorldPosition() - break - break - if self._layer_view._minimum_layer_num > layer: - start += element_counts[layer] - end += element_counts[layer] + start = self._layer_view.start_elements_index + end = self._layer_view.end_elements_index + index = self._layer_view._current_path_num + offset = 0 + for polygon in layer_data.getLayer(self._layer_view._current_layer_num).polygons: + # The size indicates all values in the two-dimension array, and the second dimension is + # always size 3 because we have 3D points. + if index >= polygon.data.size // 3 - offset: + index -= polygon.data.size // 3 - offset + offset = 1 # This is to avoid the first point when there is more than one polygon, since has the same value as the last point in the previous polygon + continue + # The head position is calculated and translated + head_position = Vector(polygon.data[index + offset][0], polygon.data[index + offset][1], + polygon.data[index + offset][2]) + node.getWorldPosition() + break # Calculate the range of paths in the last layer current_layer_start = end diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 4282806ff5..95a3ac3f43 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -71,6 +71,8 @@ class SimulationView(CuraView): self._max_paths = 0 self._current_path_num = 0 self._minimum_path_num = 0 + self.start_elements_index = 0 + self.end_elements_index = 0 self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged) self._busy = False @@ -243,6 +245,7 @@ class SimulationView(CuraView): self._minimum_layer_num = self._current_layer_num self._startUpdateTopLayers() + self.recalculateStartEndElements() self.currentLayerNumChanged.emit() @@ -257,7 +260,7 @@ class SimulationView(CuraView): self._current_layer_num = self._minimum_layer_num self._startUpdateTopLayers() - + self.recalculateStartEndElements() self.currentLayerNumChanged.emit() def setPath(self, value: int) -> None: @@ -359,6 +362,24 @@ class SimulationView(CuraView): return 0.0 # If it's still max-float, there are no measurements. Use 0 then. return self._min_thickness + def recalculateStartEndElements(self): + self.start_elements_index = 0 + self.end_elements_index = 0 + scene = self.getController().getScene() + for node in DepthFirstIterator(scene.getRoot()): # type: ignore + layer_data = node.callDecoration("getLayerData") + if not layer_data: + continue + + # Found a the layer data! + element_counts = layer_data.getElementCounts() + for layer in sorted(element_counts.keys()): + if layer == self._current_layer_num: + break + if self._minimum_layer_num > layer: + self.start_elements_index += element_counts[layer] + self.end_elements_index += element_counts[layer] + def getMaxThickness(self) -> float: return self._max_thickness From 61a605d02be0d0f34893fa5d544111a3b0d49132 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jan 2020 13:34:57 +0100 Subject: [PATCH 2/3] Chop up the render function to make it a bit more readable --- plugins/SimulationView/SimulationPass.py | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index f9bbb808c4..b49d06722e 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -46,19 +46,10 @@ class SimulationPass(RenderPass): self._layer_view = layerview self._compatibility_mode = layerview.getCompatibilityMode() - def render(self): - if not self._layer_shader: - if self._compatibility_mode: - shader_filename = "layers.shader" - shadow_shader_filename = "layers_shadow.shader" - else: - shader_filename = "layers3d.shader" - shadow_shader_filename = "layers3d_shadow.shader" - self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shader_filename)) - self._layer_shadow_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shadow_shader_filename)) - self._current_shader = self._layer_shader + def _updateLayerShaderValues(self): # Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers) - self._layer_shader.setUniformValue("u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex))) + self._layer_shader.setUniformValue("u_active_extruder", + float(max(0, self._extruder_manager.activeExtruderIndex))) if self._layer_view: self._layer_shader.setUniformValue("u_max_feedrate", self._layer_view.getMaxFeedrate()) self._layer_shader.setUniformValue("u_min_feedrate", self._layer_view.getMinFeedrate()) @@ -71,7 +62,7 @@ class SimulationPass(RenderPass): self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin()) self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill()) else: - #defaults + # defaults self._layer_shader.setUniformValue("u_max_feedrate", 1) self._layer_shader.setUniformValue("u_min_feedrate", 0) self._layer_shader.setUniformValue("u_max_thickness", 1) @@ -83,6 +74,20 @@ class SimulationPass(RenderPass): self._layer_shader.setUniformValue("u_show_skin", 1) self._layer_shader.setUniformValue("u_show_infill", 1) + def render(self): + if not self._layer_shader: + if self._compatibility_mode: + shader_filename = "layers.shader" + shadow_shader_filename = "layers_shadow.shader" + else: + shader_filename = "layers3d.shader" + shadow_shader_filename = "layers3d_shadow.shader" + self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shader_filename)) + self._layer_shadow_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("SimulationView"), shadow_shader_filename)) + self._current_shader = self._layer_shader + + self._updateLayerShaderValues() + if not self._tool_handle_shader: self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader")) @@ -97,7 +102,6 @@ class SimulationPass(RenderPass): nozzle_node = None for node in DepthFirstIterator(self._scene.getRoot()): - if isinstance(node, ToolHandle): tool_handle_batch.addItem(node.getWorldTransformation(), mesh = node.getSolidMesh()) From 3ffbdf28880494d0e67a2f910b770cc6df14a61b Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jan 2020 11:28:29 +0100 Subject: [PATCH 3/3] Ensure that after a reslice the nozzle location of re-slice is still correct --- plugins/SimulationView/SimulationView.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 95a3ac3f43..3a860a3055 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -274,7 +274,7 @@ class SimulationView(CuraView): self._minimum_path_num = self._current_path_num self._startUpdateTopLayers() - + self.recalculateStartEndElements() self.currentPathNumChanged.emit() def setMinimumPath(self, value: int) -> None: @@ -599,7 +599,7 @@ class SimulationView(CuraView): def _startUpdateTopLayers(self) -> None: if not self._compatibility_mode: return - + self.recalculateStartEndElements() if self._top_layers_job: self._top_layers_job.finished.disconnect(self._updateCurrentLayerMesh) self._top_layers_job.cancel()