PreviewPass.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import Optional, TYPE_CHECKING
  4. from UM.Application import Application
  5. from UM.Resources import Resources
  6. from UM.View.RenderPass import RenderPass
  7. from UM.View.GL.OpenGL import OpenGL
  8. from UM.View.RenderBatch import RenderBatch
  9. from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
  10. if TYPE_CHECKING:
  11. from UM.View.GL.ShaderProgram import ShaderProgram
  12. MYPY = False
  13. if MYPY:
  14. from UM.Scene.Camera import Camera
  15. # Make color brighter by normalizing it (maximum factor 2.5 brighter)
  16. # color_list is a list of 4 elements: [r, g, b, a], each element is a float 0..1
  17. def prettier_color(color_list):
  18. maximum = max(color_list[:3])
  19. if maximum > 0:
  20. factor = min(1 / maximum, 2.5)
  21. else:
  22. factor = 1.0
  23. return [min(i * factor, 1.0) for i in color_list]
  24. ## A render pass subclass that renders slicable objects with default parameters.
  25. # It uses the active camera by default, but it can be overridden to use a different camera.
  26. #
  27. # This is useful to get a preview image of a scene taken from a different location as the active camera.
  28. class PreviewPass(RenderPass):
  29. def __init__(self, width: int, height: int) -> None:
  30. super().__init__("preview", width, height, 0)
  31. self._camera = None # type: Optional[Camera]
  32. self._renderer = Application.getInstance().getRenderer()
  33. self._shader = None #type: Optional[ShaderProgram]
  34. self._non_printing_shader = None #type: Optional[ShaderProgram]
  35. self._support_mesh_shader = None #type: Optional[ShaderProgram]
  36. self._scene = Application.getInstance().getController().getScene()
  37. # Set the camera to be used by this render pass
  38. # if it's None, the active camera is used
  39. def setCamera(self, camera: Optional["Camera"]):
  40. self._camera = camera
  41. def render(self) -> None:
  42. if not self._shader:
  43. self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
  44. if self._shader:
  45. self._shader.setUniformValue("u_overhangAngle", 1.0)
  46. self._shader.setUniformValue("u_ambientColor", [0.1, 0.1, 0.1, 1.0])
  47. self._shader.setUniformValue("u_specularColor", [0.6, 0.6, 0.6, 1.0])
  48. self._shader.setUniformValue("u_shininess", 20.0)
  49. if not self._non_printing_shader:
  50. if self._non_printing_shader:
  51. self._non_printing_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
  52. self._non_printing_shader.setUniformValue("u_diffuseColor", [0.5, 0.5, 0.5, 0.5])
  53. self._non_printing_shader.setUniformValue("u_opacity", 0.6)
  54. if not self._support_mesh_shader:
  55. self._support_mesh_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
  56. if self._support_mesh_shader:
  57. self._support_mesh_shader.setUniformValue("u_vertical_stripes", True)
  58. self._support_mesh_shader.setUniformValue("u_width", 5.0)
  59. self._gl.glClearColor(0.0, 0.0, 0.0, 0.0)
  60. self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)
  61. # Create batches to be rendered
  62. batch = RenderBatch(self._shader)
  63. batch_support_mesh = RenderBatch(self._support_mesh_shader)
  64. # Fill up the batch with objects that can be sliced.
  65. for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax.
  66. if hasattr(node, "_outside_buildarea") and not node._outside_buildarea:
  67. if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
  68. per_mesh_stack = node.callDecoration("getStack")
  69. if node.callDecoration("isNonThumbnailVisibleMesh"):
  70. # Non printing mesh
  71. continue
  72. elif per_mesh_stack is not None and per_mesh_stack.getProperty("support_mesh", "value"):
  73. # Support mesh
  74. uniforms = {}
  75. shade_factor = 0.6
  76. diffuse_color = node.getDiffuseColor()
  77. diffuse_color2 = [
  78. diffuse_color[0] * shade_factor,
  79. diffuse_color[1] * shade_factor,
  80. diffuse_color[2] * shade_factor,
  81. 1.0]
  82. uniforms["diffuse_color"] = prettier_color(diffuse_color)
  83. uniforms["diffuse_color_2"] = diffuse_color2
  84. batch_support_mesh.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = uniforms)
  85. else:
  86. # Normal scene node
  87. uniforms = {}
  88. uniforms["diffuse_color"] = prettier_color(node.getDiffuseColor())
  89. batch.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = uniforms)
  90. self.bind()
  91. if self._camera is None:
  92. render_camera = Application.getInstance().getController().getScene().getActiveCamera()
  93. else:
  94. render_camera = self._camera
  95. batch.render(render_camera)
  96. batch_support_mesh.render(render_camera)
  97. self.release()