diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 9e8b82ed43..e259b27e63 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -241,6 +241,7 @@ class CuraApplication(QtApplication): Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True) Preferences.getInstance().addPreference("cura/dialog_on_project_save", True) Preferences.getInstance().addPreference("cura/asked_dialog_on_project_save", False) + Preferences.getInstance().addPreference("view/force_layer_view_compatibility_mode", False) Preferences.getInstance().addPreference("cura/currency", "€") Preferences.getInstance().addPreference("cura/material_settings", "{}") @@ -546,6 +547,7 @@ class CuraApplication(QtApplication): controller = self.getController() controller.setActiveView("SolidView") + controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") diff --git a/cura/Layer.py b/cura/Layer.py index 4e38a6eba9..869b84ed90 100644 --- a/cura/Layer.py +++ b/cura/Layer.py @@ -49,12 +49,12 @@ class Layer: return result - def build(self, vertex_offset, index_offset, vertices, colors, indices): + def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, extruders, line_types, indices): result_vertex_offset = vertex_offset result_index_offset = index_offset self._element_count = 0 for polygon in self._polygons: - polygon.build(result_vertex_offset, result_index_offset, vertices, colors, indices) + polygon.build(result_vertex_offset, result_index_offset, vertices, colors, line_dimensions, extruders, line_types, indices) result_vertex_offset += polygon.lineMeshVertexCount() result_index_offset += polygon.lineMeshElementCount() self._element_count += polygon.elementCount diff --git a/cura/LayerData.py b/cura/LayerData.py index ad5326373e..3fe550c297 100644 --- a/cura/LayerData.py +++ b/cura/LayerData.py @@ -6,9 +6,9 @@ from UM.Mesh.MeshData import MeshData # Immutable, use LayerDataBuilder to create one of these. class LayerData(MeshData): def __init__(self, vertices = None, normals = None, indices = None, colors = None, uvs = None, file_name = None, - center_position = None, layers=None, element_counts=None): + center_position = None, layers=None, element_counts=None, attributes=None): super().__init__(vertices=vertices, normals=normals, indices=indices, colors=colors, uvs=uvs, - file_name=file_name, center_position=center_position) + file_name=file_name, center_position=center_position, attributes=attributes) self._layers = layers self._element_counts = element_counts diff --git a/cura/LayerDataBuilder.py b/cura/LayerDataBuilder.py index 2215ed5f27..428ad4a210 100644 --- a/cura/LayerDataBuilder.py +++ b/cura/LayerDataBuilder.py @@ -48,7 +48,11 @@ class LayerDataBuilder(MeshBuilder): self._layers[layer].setThickness(thickness) - def build(self): + ## Return the layer data as LayerData. + # + # \param material_color_map: [r, g, b, a] for each extruder row. + # \param line_type_brightness: compatibility layer view uses line type brightness of 0.5 + def build(self, material_color_map, line_type_brightness = 1.0): vertex_count = 0 index_count = 0 for layer, data in self._layers.items(): @@ -56,20 +60,56 @@ class LayerDataBuilder(MeshBuilder): index_count += data.lineMeshElementCount() vertices = numpy.empty((vertex_count, 3), numpy.float32) + line_dimensions = numpy.empty((vertex_count, 2), numpy.float32) colors = numpy.empty((vertex_count, 4), numpy.float32) indices = numpy.empty((index_count, 2), numpy.int32) + extruders = numpy.empty((vertex_count), numpy.float32) + line_types = numpy.empty((vertex_count), numpy.float32) vertex_offset = 0 index_offset = 0 for layer, data in self._layers.items(): - ( vertex_offset, index_offset ) = data.build( vertex_offset, index_offset, vertices, colors, indices) + ( vertex_offset, index_offset ) = data.build( vertex_offset, index_offset, vertices, colors, line_dimensions, extruders, line_types, indices) self._element_counts[layer] = data.elementCount self.addVertices(vertices) + colors[:, 0:3] *= line_type_brightness self.addColors(colors) self.addIndices(indices.flatten()) + # Note: we're using numpy indexing here. + # See also: https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html + material_colors = numpy.zeros((line_dimensions.shape[0], 4), dtype=numpy.float32) + for extruder_nr in range(material_color_map.shape[0]): + material_colors[extruders == extruder_nr] = material_color_map[extruder_nr] + # Set material_colors with indices where line_types (also numpy array) == MoveCombingType + material_colors[line_types == LayerPolygon.MoveCombingType] = colors[line_types == LayerPolygon.MoveCombingType] + material_colors[line_types == LayerPolygon.MoveRetractionType] = colors[line_types == LayerPolygon.MoveRetractionType] + + attributes = { + "line_dimensions": { + "value": line_dimensions, + "opengl_name": "a_line_dim", + "opengl_type": "vector2f" + }, + "extruders": { + "value": extruders, + "opengl_name": "a_extruder", + "opengl_type": "float" + }, + "colors": { + "value": material_colors, + "opengl_name": "a_material_color", + "opengl_type": "vector4f" + }, + "line_types": { + "value": line_types, + "opengl_name": "a_line_type", + "opengl_type": "float" + } + } + return LayerData(vertices=self.getVertices(), normals=self.getNormals(), indices=self.getIndices(), colors=self.getColors(), uvs=self.getUVCoordinates(), file_name=self.getFileName(), center_position=self.getCenterPosition(), layers=self._layers, - element_counts=self._element_counts) + element_counts=self._element_counts, attributes=attributes) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index 81fe66a80d..2c527c7c7e 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -19,13 +19,19 @@ class LayerPolygon: __jump_map = numpy.logical_or(numpy.logical_or(numpy.arange(11) == NoneType, numpy.arange(11) == MoveCombingType), numpy.arange(11) == MoveRetractionType) - def __init__(self, mesh, extruder, line_types, data, line_widths): - self._mesh = mesh + ## LayerPolygon, used in ProcessSlicedLayersJob + # \param extruder + # \param line_types array with line_types + # \param data new_points + # \param line_widths array with line widths + # \param line_thicknesses: array with type as index and thickness as value + def __init__(self, extruder, line_types, data, line_widths, line_thicknesses): self._extruder = extruder self._types = line_types self._data = data self._line_widths = line_widths - + self._line_thicknesses = line_thicknesses + self._vertex_begin = 0 self._vertex_end = 0 self._index_begin = 0 @@ -38,7 +44,7 @@ class LayerPolygon: # Buffering the colors shouldn't be necessary as it is not # re-used and can save alot of memory usage. - self._color_map = LayerPolygon.getColorMap() * [1, 1, 1, self._extruder] # The alpha component is used to store the extruder nr + self._color_map = LayerPolygon.getColorMap() self._colors = self._color_map[self._types] # When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType @@ -50,7 +56,7 @@ class LayerPolygon: def buildCache(self): # For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out. - self._build_cache_line_mesh_mask = numpy.logical_not(numpy.logical_or(self._jump_mask, self._types == LayerPolygon.InfillType )) + self._build_cache_line_mesh_mask = numpy.ones(self._jump_mask.shape, dtype=bool) mesh_line_count = numpy.sum(self._build_cache_line_mesh_mask) self._index_begin = 0 self._index_end = mesh_line_count @@ -60,13 +66,23 @@ class LayerPolygon: self._build_cache_needed_points[1:, 0][:, numpy.newaxis] = self._types[1:] != self._types[:-1] # Mark points as unneeded if they are of types we don't want in the line mesh according to the calculated mask numpy.logical_and(self._build_cache_needed_points, self._build_cache_line_mesh_mask, self._build_cache_needed_points ) - + self._vertex_begin = 0 self._vertex_end = numpy.sum( self._build_cache_needed_points ) - - def build(self, vertex_offset, index_offset, vertices, colors, indices): - if (self._build_cache_line_mesh_mask is None) or (self._build_cache_needed_points is None ): + ## Set all the arrays provided by the function caller, representing the LayerPolygon + # The arrays are either by vertex or by indices. + # + # \param vertex_offset : determines where to start and end filling the arrays + # \param index_offset : determines where to start and end filling the arrays + # \param vertices : vertex numpy array to be filled + # \param colors : vertex numpy array to be filled + # \param line_dimensions : vertex numpy array to be filled + # \param extruders : vertex numpy array to be filled + # \param line_types : vertex numpy array to be filled + # \param indices : index numpy array to be filled + def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, extruders, line_types, indices): + if self._build_cache_line_mesh_mask is None or self._build_cache_needed_points is None: self.buildCache() line_mesh_mask = self._build_cache_line_mesh_mask @@ -83,9 +99,18 @@ class LayerPolygon: # Points are picked based on the index list to get the vertices needed. vertices[self._vertex_begin:self._vertex_end, :] = self._data[index_list, :] + # Create an array with colors for each vertex and remove the color data for the points that has been thrown away. - colors[self._vertex_begin:self._vertex_end, :] = numpy.tile(self._colors, (1, 2)).reshape((-1, 4))[needed_points_list.ravel()] - colors[self._vertex_begin:self._vertex_end, :] *= numpy.array([[0.5, 0.5, 0.5, 1.0]], numpy.float32) + colors[self._vertex_begin:self._vertex_end, :] = numpy.tile(self._colors, (1, 2)).reshape((-1, 4))[needed_points_list.ravel()] + + # Create an array with line widths for each vertex. + line_dimensions[self._vertex_begin:self._vertex_end, 0] = numpy.tile(self._line_widths, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0] + line_dimensions[self._vertex_begin:self._vertex_end, 1] = numpy.tile(self._line_thicknesses, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0] + + extruders[self._vertex_begin:self._vertex_end] = self._extruder + + # Convert type per vertex to type per line + line_types[self._vertex_begin:self._vertex_end] = numpy.tile(self._types, (1, 2)).reshape((-1, 1))[needed_points_list.ravel()][:, 0] # The relative values of begin and end indices have already been set in buildCache, so we only need to offset them to the parents offset. self._index_begin += index_offset diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 479bd89ed2..14106d5804 100644 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -53,6 +53,7 @@ class ExtruderManager(QObject): except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. return None + ## Return extruder count according to extruder trains. @pyqtProperty(int, notify = extrudersChanged) def extruderCount(self): if not Application.getInstance().getGlobalContainerStack(): diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index c4e9554b2c..0d706f59b8 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -8,6 +8,8 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode from UM.Application import Application from UM.Mesh.MeshData import MeshData +from UM.Preferences import Preferences +from UM.View.GL.OpenGLContext import OpenGLContext from UM.Message import Message from UM.i18n import i18nCatalog @@ -15,6 +17,7 @@ from UM.Logger import Logger from UM.Math.Vector import Vector +from cura.Settings.ExtruderManager import ExtruderManager from cura import LayerDataBuilder from cura import LayerDataDecorator from cura import LayerPolygon @@ -24,6 +27,17 @@ from time import time catalog = i18nCatalog("cura") +## Return a 4-tuple with floats 0-1 representing the html color code +# +# \param color_code html color code, i.e. "#FF0000" -> red +def colorCodeToRGBA(color_code): + return [ + int(color_code[1:3], 16) / 255, + int(color_code[3:5], 16) / 255, + int(color_code[5:7], 16) / 255, + 1.0] + + class ProcessSlicedLayersJob(Job): def __init__(self, layers): super().__init__() @@ -92,7 +106,6 @@ class ProcessSlicedLayersJob(Job): layer_data.addLayer(abs_layer_number) this_layer = layer_data.getLayer(abs_layer_number) layer_data.setLayerHeight(abs_layer_number, layer.height) - layer_data.setLayerThickness(abs_layer_number, layer.thickness) for p in range(layer.repeatedMessageCount("path_segment")): polygon = layer.getRepeatedMessage("path_segment", p) @@ -110,23 +123,28 @@ class ProcessSlicedLayersJob(Job): line_widths = numpy.fromstring(polygon.line_width, dtype="f4") # Convert bytearray to numpy array line_widths = line_widths.reshape((-1,1)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. - + + # In the future, line_thicknesses should be given by CuraEngine as well. + # Currently the infill layer thickness also translates to line width + line_thicknesses = numpy.zeros(line_widths.shape, dtype="f4") + line_thicknesses[:] = layer.thickness / 1000 # from micrometer to millimeter + # Create a new 3D-array, copy the 2D points over and insert the right height. # This uses manual array creation + copy rather than numpy.insert since this is # faster. new_points = numpy.empty((len(points), 3), numpy.float32) if polygon.point_type == 0: # Point2D new_points[:, 0] = points[:, 0] - new_points[:, 1] = layer.height / 1000 # layer height value is in backend representation + new_points[:, 1] = layer.height / 1000 # layer height value is in backend representation new_points[:, 2] = -points[:, 1] else: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] - this_poly = LayerPolygon.LayerPolygon(layer_data, extruder, line_types, new_points, line_widths) + this_poly = LayerPolygon.LayerPolygon(extruder, line_types, new_points, line_widths, line_thicknesses) this_poly.buildCache() - + this_layer.polygons.append(this_poly) Job.yieldThread() @@ -144,7 +162,35 @@ class ProcessSlicedLayersJob(Job): self._progress.setProgress(progress) # We are done processing all the layers we got from the engine, now create a mesh out of the data - layer_mesh = layer_data.build() + + # Find out colors per extruder + global_container_stack = Application.getInstance().getGlobalContainerStack() + manager = ExtruderManager.getInstance() + extruders = list(manager.getMachineExtruders(global_container_stack.getId())) + if extruders: + material_color_map = numpy.zeros((len(extruders), 4), dtype=numpy.float32) + for extruder in extruders: + material = extruder.findContainer({"type": "material"}) + position = int(extruder.getMetaDataEntry("position", default="0")) # Get the position + color_code = material.getMetaDataEntry("color_code") + color = colorCodeToRGBA(color_code) + material_color_map[position, :] = color + else: + # Single extruder via global stack. + material_color_map = numpy.zeros((1, 4), dtype=numpy.float32) + material = global_container_stack.findContainer({"type": "material"}) + color_code = material.getMetaDataEntry("color_code") + if color_code is None: # not all stacks have a material color + color_code = "#e0e000" + color = colorCodeToRGBA(color_code) + material_color_map[0, :] = color + + # We have to scale the colors for compatibility mode + if OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")): + line_type_brightness = 0.5 # for compatibility mode + else: + line_type_brightness = 1.0 + layer_mesh = layer_data.build(material_color_map, line_type_brightness) if self._abort_requested: if self._progress: diff --git a/plugins/GCodeReader/GCodeReader.py b/plugins/GCodeReader/GCodeReader.py index 34ea91a727..290b66343e 100644 --- a/plugins/GCodeReader/GCodeReader.py +++ b/plugins/GCodeReader/GCodeReader.py @@ -99,8 +99,11 @@ class GCodeReader(MeshReader): count = len(path) line_types = numpy.empty((count - 1, 1), numpy.int32) line_widths = numpy.empty((count - 1, 1), numpy.float32) + line_thicknesses = numpy.empty((count - 1, 1), numpy.float32) # TODO: need to calculate actual line width based on E values line_widths[:, 0] = 0.4 + # TODO: need to calculate actual line heights + line_thicknesses[:, 0] = 0.2 points = numpy.empty((count, 3), numpy.float32) i = 0 for point in path: @@ -113,7 +116,7 @@ class GCodeReader(MeshReader): line_widths[i - 1] = 0.2 i += 1 - this_poly = LayerPolygon(self._layer_data_builder, self._extruder, line_types, points, line_widths) + this_poly = LayerPolygon(self._extruder, line_types, points, line_widths, line_thicknesses) this_poly.buildCache() this_layer.polygons.append(this_poly) @@ -276,7 +279,10 @@ class GCodeReader(MeshReader): self._layer += 1 current_path.clear() - layer_mesh = self._layer_data_builder.build() + material_color_map = numpy.zeros((10, 4), dtype = numpy.float32) + material_color_map[0, :] = [0.0, 0.7, 0.9, 1.0] + material_color_map[1, :] = [0.7, 0.9, 0.0, 1.0] + layer_mesh = self._layer_data_builder.build(material_color_map) decorator = LayerDataDecorator.LayerDataDecorator() decorator.setLayerData(layer_mesh) scene_node.addDecorator(decorator) diff --git a/plugins/LayerView/LayerPass.py b/plugins/LayerView/LayerPass.py index 9bc67efc58..9ba245489a 100644 --- a/plugins/LayerView/LayerPass.py +++ b/plugins/LayerView/LayerPass.py @@ -14,6 +14,7 @@ from UM.View.GL.OpenGL import OpenGL from cura.Settings.ExtruderManager import ExtruderManager + import os.path ## RenderPass used to display g-code paths. @@ -28,15 +29,39 @@ class LayerPass(RenderPass): self._extruder_manager = ExtruderManager.getInstance() self._layer_view = None + self._compatibility_mode = None def setLayerView(self, layerview): - self._layerview = layerview + self._layer_view = layerview + self._compatibility_mode = layerview.getCompatibilityMode() def render(self): if not self._layer_shader: - self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), "layers.shader")) + if self._compatibility_mode: + shader_filename = "layers.shader" + else: + shader_filename = "layers3d.shader" + self._layer_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("LayerView"), shader_filename)) # 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))) + if self._layer_view: + self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getLayerViewType()) + self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities()) + self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves()) + self._layer_shader.setUniformValue("u_show_support", self._layer_view.getShowSupport()) + self._layer_shader.setUniformValue("u_show_adhesion", self._layer_view.getShowAdhesion()) + self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin()) + self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill()) + else: + #defaults + self._layer_shader.setUniformValue("u_layer_view_type", 1) + self._layer_shader.setUniformValue("u_extruder_opacity", [1, 1, 1, 1]) + self._layer_shader.setUniformValue("u_show_travel_moves", 0) + self._layer_shader.setUniformValue("u_show_support", 1) + self._layer_shader.setUniformValue("u_show_adhesion", 1) + self._layer_shader.setUniformValue("u_show_skin", 1) + self._layer_shader.setUniformValue("u_show_infill", 1) + if not self._tool_handle_shader: self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader")) @@ -55,13 +80,15 @@ class LayerPass(RenderPass): continue # Render all layers below a certain number as line mesh instead of vertices. - if self._layerview._current_layer_num - self._layerview._solid_layers > -1 and not self._layerview._only_show_top_layers: + 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, counts in element_counts.items(): - if layer + self._layerview._solid_layers > self._layerview._current_layer_num: + if layer > self._layer_view._current_layer_num: break + if self._layer_view._minimum_layer_num > layer: + start += counts end += counts # This uses glDrawRangeElements internally to only draw a certain range of lines. @@ -72,11 +99,11 @@ class LayerPass(RenderPass): # Create a new batch that is not range-limited batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid) - if self._layerview._current_layer_mesh: - batch.addItem(node.getWorldTransformation(), self._layerview._current_layer_mesh) + if self._layer_view._current_layer_mesh: + batch.addItem(node.getWorldTransformation(), self._layer_view._current_layer_mesh) - if self._layerview._current_layer_jumps: - batch.addItem(node.getWorldTransformation(), self._layerview._current_layer_jumps) + if self._layer_view._current_layer_jumps: + batch.addItem(node.getWorldTransformation(), self._layer_view._current_layer_jumps) if len(batch.items) > 0: batch.render(self._scene.getActiveCamera()) diff --git a/plugins/LayerView/LayerView.py b/plugins/LayerView/LayerView.py index df0c92f87e..77c17a0aea 100644 --- a/plugins/LayerView/LayerView.py +++ b/plugins/LayerView/LayerView.py @@ -13,15 +13,15 @@ from UM.Mesh.MeshBuilder import MeshBuilder from UM.Job import Job from UM.Preferences import Preferences from UM.Logger import Logger -from UM.Scene.SceneNode import SceneNode -from UM.View.RenderBatch import RenderBatch from UM.View.GL.OpenGL import OpenGL from UM.Message import Message from UM.Application import Application +from UM.View.GL.OpenGLContext import OpenGLContext from cura.ConvexHullNode import ConvexHullNode +from cura.Settings.ExtruderManager import ExtruderManager -from PyQt5.QtCore import Qt, QTimer +from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication from . import LayerViewProxy @@ -36,11 +36,16 @@ import os.path ## View used to display g-code paths. class LayerView(View): + # Must match LayerView.qml + LAYER_VIEW_TYPE_MATERIAL_TYPE = 0 + LAYER_VIEW_TYPE_LINE_TYPE = 1 + def __init__(self): super().__init__() self._max_layers = 0 self._current_layer_num = 0 + self._minimum_layer_num = 0 self._current_layer_mesh = None self._current_layer_jumps = None self._top_layers_job = None @@ -60,17 +65,30 @@ class LayerView(View): self._proxy = LayerViewProxy.LayerViewProxy() self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged) + self._resetSettings() self._legend_items = None Preferences.getInstance().addPreference("view/top_layer_count", 5) Preferences.getInstance().addPreference("view/only_show_top_layers", False) + Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count")) self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers")) + self._compatibility_mode = True # for safety self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled")) + def _resetSettings(self): + self._layer_view_type = 0 # 0 is material color, 1 is color by linetype, 2 is speed + self._extruder_count = 0 + self._extruder_opacity = [1.0, 1.0, 1.0, 1.0] + self._show_travel_moves = 0 + self._show_support = 1 + self._show_adhesion = 1 + self._show_skin = 1 + self._show_infill = 1 + def getActivity(self): return self._activity @@ -79,6 +97,7 @@ class LayerView(View): # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. self._layer_pass = LayerPass.LayerPass(1, 1) + self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self._layer_pass.setLayerView(self) self.getRenderer().addRenderPass(self._layer_pass) return self._layer_pass @@ -86,6 +105,9 @@ class LayerView(View): def getCurrentLayer(self): return self._current_layer_num + def getMinimumLayer(self): + return self._minimum_layer_num + def _onSceneChanged(self, node): self.calculateMaxLayers() @@ -136,6 +158,79 @@ class LayerView(View): self.currentLayerNumChanged.emit() + def setMinimumLayer(self, value): + if self._minimum_layer_num != value: + self._minimum_layer_num = value + if self._minimum_layer_num < 0: + self._minimum_layer_num = 0 + + self._startUpdateTopLayers() + + self.currentLayerNumChanged.emit() + + ## Set the layer view type + # + # \param layer_view_type integer as in LayerView.qml and this class + def setLayerViewType(self, layer_view_type): + self._layer_view_type = layer_view_type + self.currentLayerNumChanged.emit() + + ## Return the layer view type, integer as in LayerView.qml and this class + def getLayerViewType(self): + return self._layer_view_type + + ## Set the extruder opacity + # + # \param extruder_nr 0..3 + # \param opacity 0.0 .. 1.0 + def setExtruderOpacity(self, extruder_nr, opacity): + self._extruder_opacity[extruder_nr] = opacity + self.currentLayerNumChanged.emit() + + def getExtruderOpacities(self): + return self._extruder_opacity + + def setShowTravelMoves(self, show): + self._show_travel_moves = show + self.currentLayerNumChanged.emit() + + def getShowTravelMoves(self): + return self._show_travel_moves + + def setShowSupport(self, show): + self._show_support = show + self.currentLayerNumChanged.emit() + + def getShowSupport(self): + return self._show_support + + def setShowAdhesion(self, show): + self._show_adhesion = show + self.currentLayerNumChanged.emit() + + def getShowAdhesion(self): + return self._show_adhesion + + def setShowSkin(self, show): + self._show_skin = show + self.currentLayerNumChanged.emit() + + def getShowSkin(self): + return self._show_skin + + def setShowInfill(self, show): + self._show_infill = show + self.currentLayerNumChanged.emit() + + def getShowInfill(self): + return self._show_infill + + def getCompatibilityMode(self): + return self._compatibility_mode + + def getExtruderCount(self): + return self._extruder_count + def calculateMaxLayers(self): scene = self.getController().getScene() self._activity = True @@ -167,6 +262,8 @@ class LayerView(View): maxLayersChanged = Signal() currentLayerNumChanged = Signal() + globalStackChanged = Signal() + preferencesChanged = Signal() ## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created # as this caused some issues. @@ -176,6 +273,12 @@ class LayerView(View): def endRendering(self): pass + def enableLegend(self): + Application.getInstance().setViewLegendItems(self._getLegendItems()) + + def disableLegend(self): + Application.getInstance().setViewLegendItems([]) + def event(self, event): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers == Qt.ControlModifier @@ -208,7 +311,8 @@ class LayerView(View): self._old_composite_shader = self._composite_pass.getCompositeShader() self._composite_pass.setCompositeShader(self._layerview_composite_shader) - Application.getInstance().setViewLegendItems(self._getLegendItems()) + if self.getLayerViewType() == self.LAYER_VIEW_TYPE_LINE_TYPE: + self.enableLegend() elif event.type == Event.ViewDeactivateEvent: self._wireprint_warning_message.hide() @@ -219,7 +323,7 @@ class LayerView(View): self._composite_pass.setLayerBindings(self._old_layer_bindings) self._composite_pass.setCompositeShader(self._old_composite_shader) - Application.getInstance().setViewLegendItems([]) + self.disableLegend() def _onGlobalStackChanged(self): if self._global_container_stack: @@ -227,7 +331,9 @@ class LayerView(View): self._global_container_stack = Application.getInstance().getGlobalContainerStack() if self._global_container_stack: self._global_container_stack.propertyChanged.connect(self._onPropertyChanged) + self._extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") self._onPropertyChanged("wireframe_enabled", "value") + self.globalStackChanged.emit() else: self._wireprint_warning_message.hide() @@ -239,6 +345,9 @@ class LayerView(View): self._wireprint_warning_message.hide() def _startUpdateTopLayers(self): + if not self._compatibility_mode: + return + if self._top_layers_job: self._top_layers_job.finished.disconnect(self._updateCurrentLayerMesh) self._top_layers_job.cancel() @@ -262,13 +371,16 @@ class LayerView(View): self._top_layers_job = None def _onPreferencesChanged(self, preference): - if preference != "view/top_layer_count" and preference != "view/only_show_top_layers": + if preference not in {"view/top_layer_count", "view/only_show_top_layers", "view/force_layer_view_compatibility_mode"}: return self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count")) self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers")) + self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool( + Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self._startUpdateTopLayers() + self.preferencesChanged.emit() def _getLegendItems(self): if self._legend_items is None: diff --git a/plugins/LayerView/LayerView.qml b/plugins/LayerView/LayerView.qml index 82728d2a1e..7713b796a9 100644 --- a/plugins/LayerView/LayerView.qml +++ b/plugins/LayerView/LayerView.qml @@ -13,13 +13,38 @@ Item width: UM.Theme.getSize("button").width height: UM.Theme.getSize("slider_layerview_size").height + Slider + { + id: sliderMinimumLayer + width: UM.Theme.getSize("slider_layerview_size").width + height: UM.Theme.getSize("slider_layerview_size").height + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("slider_layerview_margin").width * 0.2 + orientation: Qt.Vertical + minimumValue: 0; + maximumValue: UM.LayerView.numLayers-1; + stepSize: 1 + + property real pixelsPerStep: ((height - UM.Theme.getSize("slider_handle").height) / (maximumValue - minimumValue)) * stepSize; + + value: UM.LayerView.minimumLayer + onValueChanged: { + UM.LayerView.setMinimumLayer(value) + if (value > UM.LayerView.currentLayer) { + UM.LayerView.setCurrentLayer(value); + } + } + + style: UM.Theme.styles.slider; + } + Slider { id: slider width: UM.Theme.getSize("slider_layerview_size").width height: UM.Theme.getSize("slider_layerview_size").height anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("slider_layerview_margin").width/2 + anchors.leftMargin: UM.Theme.getSize("slider_layerview_margin").width * 0.8 orientation: Qt.Vertical minimumValue: 0; maximumValue: UM.LayerView.numLayers; @@ -28,7 +53,12 @@ Item property real pixelsPerStep: ((height - UM.Theme.getSize("slider_handle").height) / (maximumValue - minimumValue)) * stepSize; value: UM.LayerView.currentLayer - onValueChanged: UM.LayerView.setCurrentLayer(value) + onValueChanged: { + UM.LayerView.setCurrentLayer(value); + if (value < UM.LayerView.minimumLayer) { + UM.LayerView.setMinimumLayer(value); + } + } style: UM.Theme.styles.slider; @@ -96,6 +126,7 @@ Item } Rectangle { + id: slider_background anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter z: slider.z - 1 @@ -114,4 +145,139 @@ Item } } } + + Rectangle { + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.top: slider_background.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + width: UM.Theme.getSize("slider_layerview_background").width * 3 + height: slider.height + UM.Theme.getSize("default_margin").height * 2 + color: UM.Theme.getColor("tool_panel_background"); + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + + ListModel // matches LayerView.py + { + id: layerViewTypes + ListElement { + text: "Material color" + type_id: 0 + } + ListElement { + text: "Line type" + type_id: 1 // these ids match the switching in the shader + } + } + + ComboBox + { + id: layerTypeCombobox + anchors.top: parent.top + anchors.left: parent.left + model: layerViewTypes + visible: !UM.LayerView.compatibilityMode + onActivated: { + var type_id = layerViewTypes.get(index).type_id; + UM.LayerView.setLayerViewType(type_id); + if (type_id == 1) { + // Line type + UM.LayerView.enableLegend(); + } else { + UM.LayerView.disableLegend(); + } + } + onModelChanged: { + currentIndex = UM.LayerView.getLayerViewType(); + } + } + + Label + { + id: compatibilityModeLabel + anchors.top: parent.top + anchors.left: parent.left + text: catalog.i18nc("@label","Compatibility mode") + visible: UM.LayerView.compatibilityMode + } + + ColumnLayout { + id: view_settings + anchors.top: UM.LayerView.compatibilityMode ? compatibilityModeLabel.bottom : layerTypeCombobox.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + + CheckBox { + checked: true + onClicked: { + UM.LayerView.setExtruderOpacity(0, checked ? 1.0 : 0.0); + } + text: "Extruder 1" + visible: !UM.LayerView.compatibilityMode && (UM.LayerView.getExtruderCount >= 1) + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setExtruderOpacity(1, checked ? 1.0 : 0.0); + } + text: "Extruder 2" + visible: !UM.LayerView.compatibilityMode && (UM.LayerView.getExtruderCount >= 2) + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setExtruderOpacity(2, checked ? 1.0 : 0.0); + } + text: "Extruder 3" + visible: !UM.LayerView.compatibilityMode && (UM.LayerView.getExtruderCount >= 3) + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setExtruderOpacity(3, checked ? 1.0 : 0.0); + } + text: "Extruder 4" + visible: !UM.LayerView.compatibilityMode && (UM.LayerView.getExtruderCount >= 4) + } + Label { + text: "Other extruders always visible" + visible: !UM.LayerView.compatibilityMode && (UM.LayerView.getExtruderCount >= 5) + } + CheckBox { + onClicked: { + UM.LayerView.setShowTravelMoves(checked ? 1 : 0); + } + text: "Show travel moves" + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setShowSupport(checked ? 1 : 0); + } + text: "Show support" + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setShowAdhesion(checked ? 1 : 0); + } + text: "Show adhesion" + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setShowSkin(checked ? 1 : 0); + } + text: "Show skin" + } + CheckBox { + checked: true + onClicked: { + UM.LayerView.setShowInfill(checked ? 1 : 0); + } + text: "Show infill" + } + } + } } diff --git a/plugins/LayerView/LayerViewProxy.py b/plugins/LayerView/LayerViewProxy.py index dd5ba5e2e0..b3a1cca87d 100644 --- a/plugins/LayerView/LayerViewProxy.py +++ b/plugins/LayerView/LayerViewProxy.py @@ -16,6 +16,8 @@ class LayerViewProxy(QObject): currentLayerChanged = pyqtSignal() maxLayersChanged = pyqtSignal() activityChanged = pyqtSignal() + globalStackChanged = pyqtSignal() + preferencesChanged = pyqtSignal() @pyqtProperty(bool, notify = activityChanged) def getLayerActivity(self): @@ -36,6 +38,12 @@ class LayerViewProxy(QObject): if type(active_view) == LayerView.LayerView.LayerView: return active_view.getCurrentLayer() + @pyqtProperty(int, notify = currentLayerChanged) + def minimumLayer(self): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + return active_view.getMinimumLayer() + busyChanged = pyqtSignal() @pyqtProperty(bool, notify = busyChanged) def busy(self): @@ -44,13 +52,96 @@ class LayerViewProxy(QObject): return active_view.isBusy() return False - + + @pyqtProperty(bool, notify = preferencesChanged) + def compatibilityMode(self): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + return active_view.getCompatibilityMode() + + return False + @pyqtSlot(int) def setCurrentLayer(self, layer_num): active_view = self._controller.getActiveView() if type(active_view) == LayerView.LayerView.LayerView: active_view.setLayer(layer_num) + @pyqtSlot(int) + def setMinimumLayer(self, layer_num): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setMinimumLayer(layer_num) + + @pyqtSlot(int) + def setLayerViewType(self, layer_view_type): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setLayerViewType(layer_view_type) + + @pyqtProperty(bool) + def getLayerViewType(self): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + return active_view.getLayerViewType() + return 0 + + # Opacity 0..1 + @pyqtSlot(int, float) + def setExtruderOpacity(self, extruder_nr, opacity): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setExtruderOpacity(extruder_nr, opacity) + + @pyqtSlot(int) + def setShowTravelMoves(self, show): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setShowTravelMoves(show) + + @pyqtSlot(int) + def setShowSupport(self, show): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setShowSupport(show) + + @pyqtSlot(int) + def setShowAdhesion(self, show): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setShowAdhesion(show) + + @pyqtSlot(int) + def setShowSkin(self, show): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setShowSkin(show) + + @pyqtSlot(int) + def setShowInfill(self, show): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.setShowInfill(show) + + @pyqtProperty(int, notify = globalStackChanged) + def getExtruderCount(self): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + return active_view.getExtruderCount() + return 0 + + @pyqtSlot() + def enableLegend(self): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.enableLegend() + + @pyqtSlot() + def disableLegend(self): + active_view = self._controller.getActiveView() + if type(active_view) == LayerView.LayerView.LayerView: + active_view.disableLegend() + def _layerActivityChanged(self): self.activityChanged.emit() @@ -63,10 +154,18 @@ class LayerViewProxy(QObject): def _onBusyChanged(self): self.busyChanged.emit() - + + def _onGlobalStackChanged(self): + self.globalStackChanged.emit() + + def _onPreferencesChanged(self): + self.preferencesChanged.emit() + def _onActiveViewChanged(self): active_view = self._controller.getActiveView() if type(active_view) == LayerView.LayerView.LayerView: active_view.currentLayerNumChanged.connect(self._onLayerChanged) active_view.maxLayersChanged.connect(self._onMaxLayersChanged) active_view.busyChanged.connect(self._onBusyChanged) + active_view.globalStackChanged.connect(self._onGlobalStackChanged) + active_view.preferencesChanged.connect(self._onPreferencesChanged) diff --git a/plugins/LayerView/layers.shader b/plugins/LayerView/layers.shader index 0e1f767e23..840c3f25ba 100644 --- a/plugins/LayerView/layers.shader +++ b/plugins/LayerView/layers.shader @@ -3,29 +3,158 @@ vertex = uniform highp mat4 u_modelViewProjectionMatrix; uniform lowp float u_active_extruder; uniform lowp float u_shade_factor; + uniform highp int u_layer_view_type; + attribute highp float a_extruder; + attribute highp float a_line_type; attribute highp vec4 a_vertex; attribute lowp vec4 a_color; + attribute lowp vec4 a_material_color; + varying lowp vec4 v_color; + varying float v_line_type; + void main() { gl_Position = u_modelViewProjectionMatrix * a_vertex; - // shade the color depending on the extruder index stored in the alpha component of the color - v_color = (a_color.a == u_active_extruder) ? a_color : a_color * u_shade_factor; - v_color.a = 1.0; + // shade the color depending on the extruder index + v_color = a_color; + // 8 and 9 are travel moves + if ((a_line_type != 8.0) && (a_line_type != 9.0)) { + v_color = (a_extruder == u_active_extruder) ? v_color : vec4(u_shade_factor * v_color.rgb, v_color.a); + } + + v_line_type = a_line_type; } fragment = varying lowp vec4 v_color; + varying float v_line_type; + + uniform int u_show_travel_moves; + uniform int u_show_support; + uniform int u_show_adhesion; + uniform int u_show_skin; + uniform int u_show_infill; void main() { + if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9 + // discard movements + discard; + } + // support: 4, 7, 10 + if ((u_show_support == 0) && ( + ((v_line_type >= 3.5) && (v_line_type <= 4.5)) || + ((v_line_type >= 6.5) && (v_line_type <= 7.5)) || + ((v_line_type >= 9.5) && (v_line_type <= 10.5)) + )) { + discard; + } + // skin: 1, 2, 3 + if ((u_show_skin == 0) && ( + (v_line_type >= 0.5) && (v_line_type <= 3.5) + )) { + discard; + } + // adhesion: + if ((u_show_adhesion == 0) && (v_line_type >= 4.5) && (v_line_type <= 5.5)) { + // discard movements + discard; + } + // infill: + if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) { + // discard movements + discard; + } + gl_FragColor = v_color; } +vertex41core = + #version 410 + uniform highp mat4 u_modelViewProjectionMatrix; + uniform lowp float u_active_extruder; + uniform lowp float u_shade_factor; + uniform highp int u_layer_view_type; + + in highp float a_extruder; + in highp float a_line_type; + in highp vec4 a_vertex; + in lowp vec4 a_color; + in lowp vec4 a_material_color; + + out lowp vec4 v_color; + out float v_line_type; + + void main() + { + gl_Position = u_modelViewProjectionMatrix * a_vertex; + v_color = a_color; + if ((a_line_type != 8) && (a_line_type != 9)) { + v_color = (a_extruder == u_active_extruder) ? v_color : vec4(u_shade_factor * v_color.rgb, v_color.a); + } + + v_line_type = a_line_type; + } + +fragment41core = + #version 410 + in lowp vec4 v_color; + in float v_line_type; + out vec4 frag_color; + + uniform int u_show_travel_moves; + uniform int u_show_support; + uniform int u_show_adhesion; + uniform int u_show_skin; + uniform int u_show_infill; + + void main() + { + if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9 + // discard movements + discard; + } + // support: 4, 7, 10 + if ((u_show_support == 0) && ( + ((v_line_type >= 3.5) && (v_line_type <= 4.5)) || + ((v_line_type >= 6.5) && (v_line_type <= 7.5)) || + ((v_line_type >= 9.5) && (v_line_type <= 10.5)) + )) { + discard; + } + // skin: 1, 2, 3 + if ((u_show_skin == 0) && ( + (v_line_type >= 0.5) && (v_line_type <= 3.5) + )) { + discard; + } + // adhesion: + if ((u_show_adhesion == 0) && (v_line_type >= 4.5) && (v_line_type <= 5.5)) { + // discard movements + discard; + } + // infill: + if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) { + // discard movements + discard; + } + + frag_color = v_color; + } + [defaults] u_active_extruder = 0.0 u_shade_factor = 0.60 +u_layer_view_type = 0 +u_extruder_opacity = [1.0, 1.0, 1.0, 1.0] + +u_show_travel_moves = 0 +u_show_support = 1 +u_show_adhesion = 1 +u_show_skin = 1 +u_show_infill = 1 [bindings] u_modelViewProjectionMatrix = model_view_projection_matrix @@ -33,3 +162,6 @@ u_modelViewProjectionMatrix = model_view_projection_matrix [attributes] a_vertex = vertex a_color = color +a_extruder = extruder +a_line_type = line_type +a_material_color = material_color diff --git a/plugins/LayerView/layers3d.shader b/plugins/LayerView/layers3d.shader new file mode 100644 index 0000000000..c63bdac7d9 --- /dev/null +++ b/plugins/LayerView/layers3d.shader @@ -0,0 +1,256 @@ +[shaders] +vertex41core = + #version 410 + uniform highp mat4 u_modelViewProjectionMatrix; + + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_viewProjectionMatrix; + uniform lowp float u_active_extruder; + uniform lowp int u_layer_view_type; + uniform lowp vec4 u_extruder_opacity; // currently only for max 4 extruders, others always visible + + uniform highp mat4 u_normalMatrix; + + in highp vec4 a_vertex; + in lowp vec4 a_color; + in lowp vec4 a_material_color; + in highp vec4 a_normal; + in highp vec2 a_line_dim; // line width and thickness + in highp int a_extruder; + in highp int a_line_type; + + out lowp vec4 v_color; + + out highp vec3 v_vertex; + out highp vec3 v_normal; + out lowp vec2 v_line_dim; + out highp int v_extruder; + out highp vec4 v_extruder_opacity; + out int v_line_type; + + out lowp vec4 f_color; + out highp vec3 f_vertex; + out highp vec3 f_normal; + + void main() + { + vec4 v1_vertex = a_vertex; + v1_vertex.y -= a_line_dim.y / 2; // half layer down + + vec4 world_space_vert = u_modelMatrix * v1_vertex; + gl_Position = world_space_vert; + // shade the color depending on the extruder index stored in the alpha component of the color + + switch (u_layer_view_type) { + case 0: // "Material color" + v_color = a_material_color; + break; + case 1: // "Line type" + v_color = a_color; + break; + } + + v_vertex = world_space_vert.xyz; + v_normal = (u_normalMatrix * normalize(a_normal)).xyz; + v_line_dim = a_line_dim; + v_extruder = a_extruder; + v_line_type = a_line_type; + v_extruder_opacity = u_extruder_opacity; + + // for testing without geometry shader + f_color = v_color; + f_vertex = v_vertex; + f_normal = v_normal; + } + +geometry41core = + #version 410 + + uniform highp mat4 u_viewProjectionMatrix; + uniform int u_show_travel_moves; + uniform int u_show_support; + uniform int u_show_adhesion; + uniform int u_show_skin; + uniform int u_show_infill; + + layout(lines) in; + layout(triangle_strip, max_vertices = 26) out; + + in vec4 v_color[]; + in vec3 v_vertex[]; + in vec3 v_normal[]; + in vec2 v_line_dim[]; + in int v_extruder[]; + in vec4 v_extruder_opacity[]; + in int v_line_type[]; + + out vec4 f_color; + out vec3 f_normal; + out vec3 f_vertex; + + // Set the set of variables and EmitVertex + void myEmitVertex(vec3 vertex, vec4 color, vec3 normal, vec4 pos) { + f_vertex = vertex; + f_color = color; + f_normal = normal; + gl_Position = pos; + EmitVertex(); + } + + void main() + { + vec4 g_vertex_delta; + vec3 g_vertex_normal_horz; // horizontal and vertical in respect to layers + vec4 g_vertex_offset_horz; // vec4 to match gl_in[x].gl_Position + vec3 g_vertex_normal_vert; + vec4 g_vertex_offset_vert; + vec3 g_vertex_normal_horz_head; + vec4 g_vertex_offset_horz_head; + + float size_x; + float size_y; + + if ((v_extruder_opacity[0][v_extruder[0]] == 0.0) && (v_line_type[0] != 8) && (v_line_type[0] != 9)) { + return; + } + // See LayerPolygon; 8 is MoveCombingType, 9 is RetractionType + if ((u_show_travel_moves == 0) && ((v_line_type[0] == 8) || (v_line_type[0] == 9))) { + return; + } + if ((u_show_support == 0) && ((v_line_type[0] == 4) || (v_line_type[0] == 7) || (v_line_type[0] == 10))) { + return; + } + if ((u_show_adhesion == 0) && (v_line_type[0] == 5)) { + return; + } + if ((u_show_skin == 0) && ((v_line_type[0] == 1) || (v_line_type[0] == 2) || (v_line_type[0] == 3))) { + return; + } + if ((u_show_infill == 0) && (v_line_type[0] == 6)) { + return; + } + + if ((v_line_type[0] == 8) || (v_line_type[0] == 9)) { + // fixed size for movements + size_x = 0.1; + size_y = 0.1; + } else { + size_x = v_line_dim[0].x / 2 + 0.01; // radius, and make it nicely overlapping + size_y = v_line_dim[0].y / 2 + 0.01; + } + + g_vertex_delta = gl_in[1].gl_Position - gl_in[0].gl_Position; + g_vertex_normal_horz_head = normalize(vec3(-g_vertex_delta.x, -g_vertex_delta.y, -g_vertex_delta.z)); + g_vertex_offset_horz_head = vec4(g_vertex_normal_horz_head * size_x, 0.0); + + g_vertex_normal_horz = normalize(vec3(g_vertex_delta.z, g_vertex_delta.y, -g_vertex_delta.x)); + + g_vertex_offset_horz = vec4(g_vertex_normal_horz * size_x, 0.0); //size * g_vertex_normal_horz; + g_vertex_normal_vert = vec3(0.0, 1.0, 0.0); + g_vertex_offset_vert = vec4(g_vertex_normal_vert * size_y, 0.0); + + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); + myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz)); + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert)); + myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert)); + myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz)); + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz)); + myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert)); + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert)); + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); + myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz)); + + EndPrimitive(); + + // left side + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head)); + myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz)); + + EndPrimitive(); + + myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz)); + myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert)); + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head)); + myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz)); + + EndPrimitive(); + + // right side + myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz)); + myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert)); + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head)); + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz)); + + EndPrimitive(); + + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz)); + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert)); + myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz_head, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head)); + myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz)); + + EndPrimitive(); + } + +fragment41core = + #version 410 + in lowp vec4 f_color; + in lowp vec3 f_normal; + in lowp vec3 f_vertex; + + out vec4 frag_color; + + uniform mediump vec4 u_ambientColor; + uniform highp vec3 u_lightPosition; + + void main() + { + mediump vec4 finalColor = vec4(0.0); + float alpha = f_color.a; + + finalColor.rgb += f_color.rgb * 0.3; + + highp vec3 normal = normalize(f_normal); + highp vec3 light_dir = normalize(u_lightPosition - f_vertex); + + // Diffuse Component + highp float NdotL = clamp(dot(normal, light_dir), 0.0, 1.0); + finalColor += (NdotL * f_color); + finalColor.a = alpha; // Do not change alpha in any way + + frag_color = finalColor; + } + + +[defaults] +u_active_extruder = 0.0 +u_layer_view_type = 0 +u_extruder_opacity = [1.0, 1.0, 1.0, 1.0] + +u_specularColor = [0.4, 0.4, 0.4, 1.0] +u_ambientColor = [0.3, 0.3, 0.3, 0.0] +u_diffuseColor = [1.0, 0.79, 0.14, 1.0] +u_shininess = 20.0 + +u_show_travel_moves = 0 +u_show_support = 1 +u_show_adhesion = 1 +u_show_skin = 1 +u_show_infill = 1 + +[bindings] +u_modelViewProjectionMatrix = model_view_projection_matrix +u_modelMatrix = model_matrix +u_viewProjectionMatrix = view_projection_matrix +u_normalMatrix = normal_matrix +u_lightPosition = light_0_position + +[attributes] +a_vertex = vertex +a_color = color +a_normal = normal +a_line_dim = line_dim +a_extruder = extruder +a_material_color = material_color +a_line_type = line_type diff --git a/plugins/LayerView/layerview_composite.shader b/plugins/LayerView/layerview_composite.shader index 61d61bb901..dcc02acc84 100644 --- a/plugins/LayerView/layerview_composite.shader +++ b/plugins/LayerView/layerview_composite.shader @@ -33,6 +33,7 @@ fragment = void main() { + // blur kernel 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; @@ -63,6 +64,75 @@ fragment = } } +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; + uniform sampler2D u_layer1; + uniform sampler2D u_layer2; + + uniform vec2 u_offset[9]; + + uniform vec4 u_background_color; + uniform float u_outline_strength; + uniform vec4 u_outline_color; + + in vec2 v_uvs; + + float kernel[9]; + + 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); + + out vec4 frag_color; + + void main() + { + // blur kernel + 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 main_layer = texture(u_layer0, v_uvs); + vec4 selection_layer = texture(u_layer1, v_uvs); + vec4 layerview_layer = texture(u_layer2, v_uvs); + + result = main_layer * main_layer.a + result * (1.0 - main_layer.a); + result = layerview_layer * layerview_layer.a + result * (1.0 - layerview_layer.a); + + 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); + } + + if((selection_layer.rgb == x_axis || selection_layer.rgb == y_axis || selection_layer.rgb == z_axis)) + { + frag_color = result; + } + else + { + frag_color = mix(result, u_outline_color, abs(sum.a)); + } + } + [defaults] u_layer0 = 0 u_layer1 = 1 diff --git a/plugins/XRayView/xray.shader b/plugins/XRayView/xray.shader index b42b3e056a..41b00154ea 100644 --- a/plugins/XRayView/xray.shader +++ b/plugins/XRayView/xray.shader @@ -17,6 +17,28 @@ fragment = gl_FragColor = u_color; } +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_color; + + out vec4 frag_color; + + void main() + { + frag_color = u_color; + } + [defaults] u_color = [0.02, 0.02, 0.02, 1.0] diff --git a/plugins/XRayView/xray_composite.shader b/plugins/XRayView/xray_composite.shader index e7a38950bf..82dca52cf9 100644 --- a/plugins/XRayView/xray_composite.shader +++ b/plugins/XRayView/xray_composite.shader @@ -67,6 +67,77 @@ fragment = } } +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; + uniform sampler2D u_layer1; + uniform sampler2D u_layer2; + + 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, vec4(abs(sum.a)) * u_outline_color, abs(sum.a)); + } + } + [defaults] u_layer0 = 0 u_layer1 = 1 diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index 6d3cc9c1e7..9b6f32f114 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -235,7 +235,7 @@ UM.PreferencesPage CheckBox { id: topLayerCountCheckbox - text: catalog.i18nc("@action:button","Display five top layers in layer view"); + text: catalog.i18nc("@action:button","Display five top layers in layer view compatibility mode"); checked: UM.Preferences.getValue("view/top_layer_count") == 5 onClicked: { @@ -250,6 +250,7 @@ UM.PreferencesPage } } } + UM.TooltipArea { width: childrenRect.width height: childrenRect.height @@ -258,12 +259,26 @@ UM.PreferencesPage CheckBox { id: topLayersOnlyCheckbox - text: catalog.i18nc("@option:check", "Only display top layer(s) in layer view") + text: catalog.i18nc("@option:check", "Only display top layer(s) in layer view compatibility mode") checked: boolCheck(UM.Preferences.getValue("view/only_show_top_layers")) onCheckedChanged: UM.Preferences.setValue("view/only_show_top_layers", checked) } } + UM.TooltipArea { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "Should layer be forced into compatibility mode?") + + CheckBox + { + id: forceLayerViewCompatibilityModeCheckbox + text: catalog.i18nc("@option:check", "Force layer view compatibility mode (restart required)") + checked: boolCheck(UM.Preferences.getValue("view/force_layer_view_compatibility_mode")) + onCheckedChanged: UM.Preferences.setValue("view/force_layer_view_compatibility_mode", checked) + } + } + Item { //: Spacer diff --git a/resources/shaders/grid.shader b/resources/shaders/grid.shader index c05b9ba15c..74eed544fd 100644 --- a/resources/shaders/grid.shader +++ b/resources/shaders/grid.shader @@ -27,6 +27,37 @@ fragment = gl_FragColor = u_gridColor1; } +vertex41core = + #version 410 + uniform highp mat4 u_modelViewProjectionMatrix; + + in highp vec4 a_vertex; + in lowp vec2 a_uvs; + + out lowp vec2 v_uvs; + + void main() + { + gl_Position = u_modelViewProjectionMatrix * a_vertex; + v_uvs = a_uvs; + } + +fragment41core = + #version 410 + uniform lowp vec4 u_gridColor0; + uniform lowp vec4 u_gridColor1; + + in lowp vec2 v_uvs; + out vec4 frag_color; + + void main() + { + if (mod(floor(v_uvs.x / 10.0) - floor(v_uvs.y / 10.0), 2.0) < 1.0) + frag_color = u_gridColor0; + else + frag_color = u_gridColor1; + } + [defaults] u_gridColor0 = [0.96, 0.96, 0.96, 1.0] u_gridColor1 = [0.8, 0.8, 0.8, 1.0] diff --git a/resources/shaders/overhang.shader b/resources/shaders/overhang.shader index 99cbdf913d..b9cf53f8b7 100644 --- a/resources/shaders/overhang.shader +++ b/resources/shaders/overhang.shader @@ -8,16 +8,16 @@ vertex = attribute highp vec4 a_normal; attribute highp vec2 a_uvs; - varying highp vec3 v_vertex; - varying highp vec3 v_normal; + varying highp vec3 f_vertex; + varying highp vec3 f_normal; 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; + f_vertex = world_space_vert.xyz; + f_normal = (u_normalMatrix * normalize(a_normal)).xyz; } fragment = @@ -31,27 +31,28 @@ fragment = uniform lowp float u_overhangAngle; uniform lowp vec4 u_overhangColor; - varying highp vec3 v_vertex; - varying highp vec3 v_normal; + varying highp vec3 f_vertex; + varying highp vec3 f_normal; void main() { + mediump vec4 finalColor = vec4(0.0); - /* Ambient Component */ + // Ambient Component finalColor += u_ambientColor; - highp vec3 normal = normalize(v_normal); - highp vec3 lightDir = normalize(u_lightPosition - v_vertex); + highp vec3 normal = normalize(f_normal); + highp vec3 lightDir = normalize(u_lightPosition - f_vertex); - /* Diffuse Component */ + // Diffuse Component highp float NdotL = clamp(abs(dot(normal, lightDir)), 0.0, 1.0); finalColor += (NdotL * u_diffuseColor); - /* Specular Component */ - /* TODO: We should not do specularity for fragments facing away from the light.*/ + // Specular Component + // TODO: We should not do specularity for fragments facing away from the light. highp vec3 reflectedLight = reflect(-lightDir, normal); - highp vec3 viewVector = normalize(u_viewPosition - v_vertex); + highp vec3 viewVector = normalize(u_viewPosition - f_vertex); highp float NdotR = clamp(dot(viewVector, reflectedLight), 0.0, 1.0); finalColor += pow(NdotR, u_shininess) * u_specularColor; @@ -61,6 +62,73 @@ fragment = gl_FragColor.a = 1.0; } +vertex41core = + #version 410 + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_viewProjectionMatrix; + uniform highp mat4 u_normalMatrix; + + in highp vec4 a_vertex; + in highp vec4 a_normal; + in highp vec2 a_uvs; + + out highp vec3 f_vertex; + out highp vec3 f_normal; + + void main() + { + vec4 world_space_vert = u_modelMatrix * a_vertex; + gl_Position = u_viewProjectionMatrix * world_space_vert; + + f_vertex = world_space_vert.xyz; + f_normal = (u_normalMatrix * normalize(a_normal)).xyz; + } + +fragment41core = + #version 410 + uniform mediump vec4 u_ambientColor; + uniform mediump vec4 u_diffuseColor; + uniform mediump vec4 u_specularColor; + uniform highp vec3 u_lightPosition; + uniform mediump float u_shininess; + uniform highp vec3 u_viewPosition; + + uniform lowp float u_overhangAngle; + uniform lowp vec4 u_overhangColor; + + in highp vec3 f_vertex; + in highp vec3 f_normal; + + out vec4 frag_color; + + void main() + { + + mediump vec4 finalColor = vec4(0.0); + + // Ambient Component + finalColor += u_ambientColor; + + highp vec3 normal = normalize(f_normal); + highp vec3 lightDir = normalize(u_lightPosition - f_vertex); + + // Diffuse Component + highp float NdotL = clamp(abs(dot(normal, lightDir)), 0.0, 1.0); + finalColor += (NdotL * u_diffuseColor); + + // Specular Component + // TODO: We should not do specularity for fragments facing away from the light. + highp vec3 reflectedLight = reflect(-lightDir, normal); + highp vec3 viewVector = normalize(u_viewPosition - f_vertex); + highp float NdotR = clamp(dot(viewVector, reflectedLight), 0.0, 1.0); + finalColor += pow(NdotR, u_shininess) * u_specularColor; + + finalColor = (-normal.y > u_overhangAngle) ? u_overhangColor : finalColor; + + frag_color = finalColor; + frag_color.a = 1.0; + } + [defaults] u_ambientColor = [0.3, 0.3, 0.3, 1.0] u_diffuseColor = [1.0, 0.79, 0.14, 1.0] diff --git a/resources/shaders/striped.shader b/resources/shaders/striped.shader index 0114f0b2cb..ce7d14e39e 100644 --- a/resources/shaders/striped.shader +++ b/resources/shaders/striped.shader @@ -63,6 +63,74 @@ fragment = gl_FragColor.a = 1.0; } +vertex41core = + #version 410 + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_viewProjectionMatrix; + uniform highp mat4 u_normalMatrix; + + in highp vec4 a_vertex; + in highp vec4 a_normal; + in highp vec2 a_uvs; + + out highp vec3 v_position; + out highp vec3 v_vertex; + out highp vec3 v_normal; + + void main() + { + vec4 world_space_vert = u_modelMatrix * a_vertex; + gl_Position = u_viewProjectionMatrix * world_space_vert; + + v_position = gl_Position.xyz; + v_vertex = world_space_vert.xyz; + v_normal = (u_normalMatrix * normalize(a_normal)).xyz; + } + +fragment41core = + #version 410 + uniform mediump vec4 u_ambientColor; + uniform mediump vec4 u_diffuseColor1; + uniform mediump vec4 u_diffuseColor2; + uniform mediump vec4 u_specularColor; + uniform highp vec3 u_lightPosition; + uniform mediump float u_shininess; + uniform highp vec3 u_viewPosition; + + uniform mediump float u_width; + + in highp vec3 v_position; + in highp vec3 v_vertex; + in highp vec3 v_normal; + + out vec4 frag_color; + + void main() + { + mediump vec4 finalColor = vec4(0.0); + mediump vec4 diffuseColor = (mod((-v_position.x + v_position.y), u_width) < (u_width / 2.)) ? u_diffuseColor1 : u_diffuseColor2; + + /* Ambient Component */ + finalColor += u_ambientColor; + + highp vec3 normal = normalize(v_normal); + highp vec3 lightDir = normalize(u_lightPosition - v_vertex); + + /* Diffuse Component */ + highp float NdotL = clamp(abs(dot(normal, lightDir)), 0.0, 1.0); + finalColor += (NdotL * diffuseColor); + + /* Specular Component */ + /* TODO: We should not do specularity for fragments facing away from the light.*/ + highp vec3 reflectedLight = reflect(-lightDir, normal); + highp vec3 viewVector = normalize(u_viewPosition - v_vertex); + highp float NdotR = clamp(dot(viewVector, reflectedLight), 0.0, 1.0); + finalColor += pow(NdotR, u_shininess) * u_specularColor; + + frag_color = finalColor; + frag_color.a = 1.0; + } + [defaults] u_ambientColor = [0.3, 0.3, 0.3, 1.0] u_diffuseColor1 = [1.0, 0.5, 0.5, 1.0] diff --git a/resources/shaders/transparent_object.shader b/resources/shaders/transparent_object.shader index cd27a40769..faa43bb46c 100644 --- a/resources/shaders/transparent_object.shader +++ b/resources/shaders/transparent_object.shader @@ -48,6 +48,59 @@ fragment = gl_FragColor.a = u_opacity; } +vertex41core = + #version 410 + uniform highp mat4 u_modelMatrix; + uniform highp mat4 u_viewProjectionMatrix; + uniform highp mat4 u_normalMatrix; + + in highp vec4 a_vertex; + in highp vec4 a_normal; + in highp vec2 a_uvs; + + out highp vec3 v_vertex; + out highp vec3 v_normal; + + 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; + } + +fragment41core = + #version 410 + uniform mediump vec4 u_ambientColor; + uniform mediump vec4 u_diffuseColor; + uniform highp vec3 u_lightPosition; + + uniform mediump float u_opacity; + + in highp vec3 v_vertex; + in highp vec3 v_normal; + + out vec4 frag_color; + + void main() + { + mediump vec4 finalColor = vec4(0.0); + + /* Ambient Component */ + finalColor += u_ambientColor; + + highp vec3 normal = normalize(v_normal); + highp vec3 lightDir = normalize(u_lightPosition - v_vertex); + + /* Diffuse Component */ + highp float NdotL = clamp(abs(dot(normal, lightDir)), 0.0, 1.0); + finalColor += (NdotL * u_diffuseColor); + + frag_color = finalColor; + frag_color.a = u_opacity; + } + [defaults] u_ambientColor = [0.1, 0.1, 0.1, 1.0] u_diffuseColor = [0.4, 0.4, 0.4, 1.0]