SolidView.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import math
  4. from PyQt5.QtCore import Qt #For the extra overhang buffer.
  5. from PyQt5.QtGui import QImage #For the extra overhang buffer.
  6. from typing import Optional
  7. from UM.View.View import View
  8. from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
  9. from UM.Scene.Selection import Selection
  10. from UM.Resources import Resources
  11. from UM.Qt.QtApplication import QtApplication
  12. from UM.View.RenderBatch import RenderBatch
  13. from UM.View.GL.Texture import Texture
  14. from UM.Settings.Validator import ValidatorState
  15. from UM.Math.Color import Color
  16. from UM.View.GL.OpenGL import OpenGL
  17. from cura.Settings.ExtruderManager import ExtruderManager
  18. from cura.Settings.ExtrudersModel import ExtrudersModel
  19. ## Standard view for mesh models.
  20. class SolidView(View):
  21. def __init__(self):
  22. super().__init__()
  23. QtApplication.getInstance().getPreferences().addPreference("view/show_overhang", True)
  24. self._enabled_shader = None
  25. self._disabled_shader = None
  26. self._non_printing_shader = None
  27. self._support_mesh_shader = None
  28. self._extruders_model = ExtrudersModel()
  29. self._theme = None
  30. self._extra_overhang = None #type: Optional[Texture]
  31. def beginRendering(self):
  32. scene = self.getController().getScene()
  33. renderer = self.getRenderer()
  34. if not self._theme:
  35. self._theme = QtApplication.getInstance().getTheme()
  36. if not self._enabled_shader:
  37. self._enabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
  38. self._enabled_shader.setUniformValue("u_overhangColor", Color(*self._theme.getColor("model_overhang").getRgb()))
  39. self._enabled_shader.setUniformValue("u_extraOverhang", 0)
  40. if self._extra_overhang is None:
  41. self.setExtraOverhang(None)
  42. self._enabled_shader.setTexture(0, self._extra_overhang)
  43. self._enabled_shader.setUniformValue("u_windowSize", [QtApplication.getInstance().getMainWindow().width(), QtApplication.getInstance().getMainWindow().height()])
  44. if not self._disabled_shader:
  45. self._disabled_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
  46. self._disabled_shader.setUniformValue("u_diffuseColor1", Color(*self._theme.getColor("model_unslicable").getRgb()))
  47. self._disabled_shader.setUniformValue("u_diffuseColor2", Color(*self._theme.getColor("model_unslicable_alt").getRgb()))
  48. self._disabled_shader.setUniformValue("u_width", 50.0)
  49. if not self._non_printing_shader:
  50. self._non_printing_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
  51. self._non_printing_shader.setUniformValue("u_diffuseColor", Color(*self._theme.getColor("model_non_printing").getRgb()))
  52. self._non_printing_shader.setUniformValue("u_opacity", 0.6)
  53. if not self._support_mesh_shader:
  54. self._support_mesh_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader"))
  55. self._support_mesh_shader.setUniformValue("u_color", Color(1.0, 0.0, 0.0, 1.0))
  56. global_container_stack = QtApplication.getInstance().getGlobalContainerStack()
  57. if global_container_stack:
  58. support_extruder_nr = global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr")
  59. support_angle_stack = QtApplication.getInstance().getExtruderManager().getExtruderStack(support_extruder_nr)
  60. if support_angle_stack is not None and QtApplication.getInstance().getPreferences().getValue("view/show_overhang"):
  61. angle = support_angle_stack.getProperty("support_angle", "value")
  62. # Make sure the overhang angle is valid before passing it to the shader
  63. # Note: if the overhang angle is set to its default value, it does not need to get validated (validationState = None)
  64. if angle is not None and global_container_stack.getProperty("support_angle", "validationState") in [None, ValidatorState.Valid]:
  65. self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle)))
  66. else:
  67. self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang.
  68. else:
  69. self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0)))
  70. for node in DepthFirstIterator(scene.getRoot()):
  71. if not node.render(renderer):
  72. if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"):
  73. uniforms = {}
  74. shade_factor = 1.0
  75. per_mesh_stack = node.callDecoration("getStack")
  76. extruder_index = node.callDecoration("getActiveExtruderPosition")
  77. if extruder_index is None:
  78. extruder_index = "0"
  79. extruder_index = int(extruder_index)
  80. # Use the support extruder instead of the active extruder if this is a support_mesh
  81. if per_mesh_stack:
  82. if per_mesh_stack.getProperty("support_mesh", "value"):
  83. extruder_index = int(global_container_stack.getExtruderPositionValueWithDefault("support_extruder_nr"))
  84. try:
  85. material_color = self._extruders_model.getItem(extruder_index)["color"]
  86. except KeyError:
  87. material_color = self._extruders_model.defaultColors[0]
  88. if extruder_index != ExtruderManager.getInstance().activeExtruderIndex:
  89. # Shade objects that are printed with the non-active extruder 25% darker
  90. shade_factor = 0.6
  91. try:
  92. # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
  93. # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])
  94. uniforms["diffuse_color"] = [
  95. shade_factor * int(material_color[1:3], 16) / 255,
  96. shade_factor * int(material_color[3:5], 16) / 255,
  97. shade_factor * int(material_color[5:7], 16) / 255,
  98. 1.0
  99. ]
  100. except ValueError:
  101. pass
  102. if node.callDecoration("isNonPrintingMesh"):
  103. if per_mesh_stack and (per_mesh_stack.getProperty("infill_mesh", "value") or per_mesh_stack.getProperty("cutting_mesh", "value")):
  104. renderer.queueNode(node, shader = self._non_printing_shader, uniforms = uniforms, transparent = True)
  105. else:
  106. renderer.queueNode(node, shader = self._non_printing_shader, transparent = True)
  107. elif getattr(node, "_outside_buildarea", False):
  108. renderer.queueNode(node, shader = self._disabled_shader)
  109. elif per_mesh_stack and per_mesh_stack.getProperty("support_mesh", "value"):
  110. renderer.queueNode(node, shader = self._support_mesh_shader, uniforms = uniforms)
  111. else:
  112. renderer.queueNode(node, shader = self._enabled_shader, uniforms = uniforms)
  113. if node.callDecoration("isGroup") and Selection.isSelected(node):
  114. renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(), mode = RenderBatch.RenderMode.LineLoop)
  115. def endRendering(self):
  116. pass
  117. ## Change the overlay image that colours extra overhang.
  118. # \param extra_overhang_image A new image where white indicates that there
  119. # should be extra overhang and black indicates that there should not be
  120. # overhang.
  121. def setExtraOverhang(self, extra_overhang_image: Optional[QImage]) -> None:
  122. if extra_overhang_image is None:
  123. extra_overhang_image = QImage(QtApplication.getInstance().getMainWindow().width(), QtApplication.getInstance().getMainWindow().height(), QImage.Format_Grayscale8)
  124. extra_overhang_image.fill(Qt.black)
  125. self._extra_overhang = OpenGL.getInstance().createTexture()
  126. self._extra_overhang.setImage(extra_overhang_image)