123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- # Copyright (c) 2021 Ultimaker B.V.
- # Cura is released under the terms of the LGPLv3 or higher.
- from typing import Optional, TYPE_CHECKING, cast, List
- from UM.Application import Application
- from UM.Logger import Logger
- from UM.Resources import Resources
- from UM.View.RenderPass import RenderPass
- from UM.View.GL.OpenGL import OpenGL
- from UM.View.RenderBatch import RenderBatch
- from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
- from cura.Scene.CuraSceneNode import CuraSceneNode
- if TYPE_CHECKING:
- from UM.View.GL.ShaderProgram import ShaderProgram
- from UM.Scene.Camera import Camera
- def prettier_color(color_list: List[float]) -> List[float]:
- """Make color brighter by normalizing
- maximum factor 2.5 brighter
- :param color_list: a list of 4 elements: [r, g, b, a], each element is a float 0..1
- :return: a normalized list of 4 elements: [r, g, b, a], each element is a float 0..1
- """
- maximum = max(color_list[:3])
- if maximum > 0:
- factor = min(1 / maximum, 2.5)
- else:
- factor = 1.0
- return [min(i * factor, 1.0) for i in color_list]
- class PreviewPass(RenderPass):
- """A :py:class:`Uranium.UM.View.RenderPass` subclass that renders slicable objects with default parameters.
- It uses the active camera by default, but it can be overridden to use a different camera.
- This is useful to get a preview image of a scene taken from a different location as the active camera.
- """
- def __init__(self, width: int, height: int, *, root: CuraSceneNode = None) -> None:
- super().__init__("preview", width, height, 0)
- self._camera: Optional[Camera] = None
- self._renderer = Application.getInstance().getRenderer()
- self._shader: Optional[ShaderProgram] = None
- self._non_printing_shader: Optional[ShaderProgram] = None
- self._support_mesh_shader: Optional[ShaderProgram] = None
- self._root = Application.getInstance().getController().getScene().getRoot() if root is None else root
- # Set the camera to be used by this render pass
- # if it's None, the active camera is used
- def setCamera(self, camera: Optional["Camera"]):
- self._camera = camera
- def render(self) -> None:
- if not self._shader:
- self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "overhang.shader"))
- if self._shader:
- self._shader.setUniformValue("u_overhangAngle", 1.0)
- self._shader.setUniformValue("u_ambientColor", [0.1, 0.1, 0.1, 1.0])
- self._shader.setUniformValue("u_specularColor", [0.6, 0.6, 0.6, 1.0])
- self._shader.setUniformValue("u_shininess", 20.0)
- self._shader.setUniformValue("u_renderError", 0.0) # We don't want any error markers!.
- self._shader.setUniformValue("u_faceId", -1) # Don't render any selected faces in the preview.
- else:
- Logger.error("Unable to compile shader program: overhang.shader")
- return
- if not self._non_printing_shader:
- self._non_printing_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
- if self._non_printing_shader:
- self._non_printing_shader.setUniformValue("u_diffuseColor", [0.5, 0.5, 0.5, 0.5])
- self._non_printing_shader.setUniformValue("u_opacity", 0.6)
- if not self._support_mesh_shader:
- self._support_mesh_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "striped.shader"))
- if self._support_mesh_shader:
- self._support_mesh_shader.setUniformValue("u_vertical_stripes", True)
- self._support_mesh_shader.setUniformValue("u_width", 5.0)
- self._gl.glClearColor(0.0, 0.0, 0.0, 0.0)
- self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)
- # Create batches to be rendered
- batch = RenderBatch(self._shader)
- batch_support_mesh = RenderBatch(self._support_mesh_shader)
- # Fill up the batch with objects that can be sliced.
- for node in DepthFirstIterator(self._root):
- if hasattr(node, "_outside_buildarea") and not getattr(node, "_outside_buildarea"):
- if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
- per_mesh_stack = node.callDecoration("getStack")
- if node.callDecoration("isNonThumbnailVisibleMesh"):
- # Non printing mesh
- continue
- elif per_mesh_stack is not None and per_mesh_stack.getProperty("support_mesh", "value"):
- # Support mesh
- uniforms = {}
- shade_factor = 0.6
- diffuse_color = cast(CuraSceneNode, node).getDiffuseColor()
- diffuse_color2 = [
- diffuse_color[0] * shade_factor,
- diffuse_color[1] * shade_factor,
- diffuse_color[2] * shade_factor,
- 1.0]
- uniforms["diffuse_color"] = prettier_color(diffuse_color)
- uniforms["diffuse_color_2"] = diffuse_color2
- batch_support_mesh.addItem(node.getWorldTransformation(copy = False), node.getMeshData(), uniforms = uniforms)
- else:
- # Normal scene node
- uniforms = {}
- uniforms["diffuse_color"] = prettier_color(cast(CuraSceneNode, node).getDiffuseColor())
- batch.addItem(node.getWorldTransformation(copy = False), node.getMeshData(), uniforms = uniforms)
- self.bind()
- if self._camera is None:
- render_camera = Application.getInstance().getController().getScene().getActiveCamera()
- else:
- render_camera = self._camera
- batch.render(render_camera)
- batch_support_mesh.render(render_camera)
- self.release()
|