def test_getterAndSetters(camera): # Pretty much all of them are super simple, but it doesn't hurt to check them. camera.setAutoAdjustViewPort(False) assert camera.getAutoAdjustViewPort() == False camera.setViewportWidth(12) assert camera.getViewportWidth() == 12 camera.setViewportHeight(12) assert camera.getViewportHeight() == 12 camera.setViewportSize(22, 22) assert camera.getViewportHeight() == 22 assert camera.getViewportWidth() == 22 camera.setWindowSize(9001, 9002) assert camera.getWindowSize() == (9001, 9002) camera.setPerspective(False) assert camera.isPerspective() == False matrix = Matrix() matrix.setPerspective(10, 20, 30, 40) camera.setProjectionMatrix(matrix) assert numpy.array_equal(camera.getProjectionMatrix().getData(), matrix.getData()) camera.setZoomFactor(1) assert camera.getZoomFactor() == 1 assert camera.render(None) # Should always be true, as it's a camera
def test_getterAndSetters(): # Pretty much all of them are super simple, but it doesn't hurt to check them. camera = Camera() camera.setAutoAdjustViewPort(False) assert camera.getAutoAdjustViewPort() == False camera.setViewportWidth(12) assert camera.getViewportWidth() == 12 camera.setViewportHeight(12) assert camera.getViewportHeight() == 12 camera.setViewportSize(22, 22) assert camera.getViewportHeight() == 22 assert camera.getViewportWidth() == 22 camera.setWindowSize(9001, 9002) assert camera.getWindowSize() == (9001, 9002) camera.setPerspective(False) assert camera.isPerspective() == False matrix = Matrix() matrix.setPerspective(10, 20, 30, 40) camera.setProjectionMatrix(matrix) assert numpy.array_equal(camera.getProjectionMatrix().getData(), matrix.getData())
def render_scene(): scene = Application.getInstance().getController().getScene() active_camera = scene.getActiveCamera() render_width, render_height = active_camera.getWindowSize() render_width = int(render_width) render_height = int(render_height) Logger.log("d", f"Found active camera with {render_width=} {render_height=}") QCoreApplication.processEvents() preview_pass = PreviewPass(render_width, render_height) fovy = 30 satisfied = False zooms = 0 while not satisfied and zooms < 5: preview_pass.render() pixel_output = preview_pass.getOutput().convertToFormat( QImage.Format_ARGB32) # pixel_output.save(os.path.expanduser(f"~/Downloads/foo-a-zoom-{zooms}.png"), "PNG") min_x, max_x, min_y, max_y = Snapshot.getImageBoundaries(pixel_output) size = max((max_x - min_x) / render_width, (max_y - min_y) / render_height) if size > 0.5 or satisfied: satisfied = True else: # make it big and allow for some empty space around zooms += 1 fovy *= 0.75 projection_matrix = Matrix() projection_matrix.setPerspective(fovy, render_width / render_height, 1, 500) active_camera.setProjectionMatrix(projection_matrix) Logger.log( "d", f"Rendered thumbnail: {zooms=}, {size=}, {min_x=}, {max_x=}, {min_y=}, {max_y=}, {fovy=}" ) # crop to content pixel_output = pixel_output.copy(min_x, min_y, max_x - min_x, max_y - min_y) Logger.log( "d", f"Cropped thumbnail to {min_x}, {min_y}, {max_x - min_x}, {max_y - min_y}." ) # pixel_output.save(os.path.expanduser("~/Downloads/foo-b-cropped.png"), "PNG") Logger.log("d", "Successfully rendered scene.") return pixel_output
def _updateViewportGeometry(self, width, height): view_w = width * self._viewport_rect.width() view_h = height * self._viewport_rect.height() for camera in self._app.getController().getScene().getAllCameras(): camera.setViewportSize(view_w, view_h) proj = Matrix() if camera.isPerspective(): proj.setPerspective(30, view_w / view_h, 1, 500) else: proj.setOrtho(-view_w / 2, view_w / 2, -view_h / 2, view_h / 2, -500, 500) camera.setProjectionMatrix(proj) self._app.getRenderer().setViewportSize(view_w, view_h) self._app.getRenderer().setWindowSize(width, height)
def resizeEvent(self, event): super().resizeEvent(event) w = event.size().width() * self.devicePixelRatio() h = event.size().height() * self.devicePixelRatio() for camera in self._app.getController().getScene().getAllCameras(): camera.setViewportSize(w, h) proj = Matrix() if camera.isPerspective(): proj.setPerspective(30, w/h, 1, 500) else: proj.setOrtho(-w / 2, w / 2, -h / 2, h / 2, -500, 500) camera.setProjectionMatrix(proj) self._preferences.setValue("general/window_width", event.size().width()) self._preferences.setValue("general/window_height", event.size().height()) self._app.getRenderer().setViewportSize(w, h)
def _updateViewportGeometry(self, width, height): view_w = width * self._viewport_rect.width() view_h = height * self._viewport_rect.height() for camera in self._app.getController().getScene().getAllCameras(): camera.setViewportSize(view_w, view_h) camera.setWindowSize(width, height) proj = Matrix() if camera.isPerspective(): proj.setPerspective(30, view_w / view_h, 1, 500) else: proj.setOrtho(-view_w / 2, view_w / 2, -view_h / 2, view_h / 2, -500, 500) camera.setProjectionMatrix(proj) self._app.getRenderer().setViewportSize(view_w, view_h) self._app.getRenderer().setWindowSize(width, height)
def resizeEvent(self, event): super().resizeEvent(event) w = event.size().width() * self.devicePixelRatio() h = event.size().height() * self.devicePixelRatio() for camera in self._app.getController().getScene().getAllCameras(): camera.setViewportSize(w, h) proj = Matrix() if camera.isPerspective(): proj.setPerspective(30, w/h, 1, 500) else: proj.setOrtho(-w / 2, w / 2, -h / 2, h / 2, -500, 500) camera.setProjectionMatrix(proj) self._app.getRenderer().setViewportSize(w, h) QMetaObject.invokeMethod(self, "_onWindowGeometryChanged", Qt.QueuedConnection);
def _updatePerspectiveMatrix(self): view_width = self._viewport_width view_height = self._viewport_height projection_matrix = Matrix() if self.isPerspective(): if view_width != 0 and view_height != 0: projection_matrix.setPerspective(30, view_width / view_height, 1, 500) else: # Almost no near/far plane, please. if view_width != 0 and view_height != 0: horizontal_zoom = view_width * self._zoom_factor vertical_zoom = view_height * self._zoom_factor projection_matrix.setOrtho(-view_width / 2 - horizontal_zoom, view_width / 2 + horizontal_zoom, -view_height / 2 - vertical_zoom, view_height / 2 + vertical_zoom, -9001, 9001) self.setProjectionMatrix(projection_matrix) self.perspectiveChanged.emit(self)
def _updateViewportGeometry(self, width: int, height: int): view_width = width * self._viewport_rect.width() view_height = height * self._viewport_rect.height() for camera in self._app.getController().getScene().getAllCameras(): camera.setWindowSize(width, height) if camera.getAutoAdjustViewPort(): camera.setViewportSize(view_width, view_height) projection_matrix = Matrix() if camera.isPerspective(): if view_width is not 0: projection_matrix.setPerspective(30, view_width / view_height, 1, 500) else: projection_matrix.setOrtho(-view_width / 2, view_width / 2, -view_height / 2, view_height / 2, -500, 500) camera.setProjectionMatrix(projection_matrix) self._app.getRenderer().setViewportSize(view_width, view_height) self._app.getRenderer().setWindowSize(width, height)
def snapshot(width=300, height=300): scene = Application.getInstance().getController().getScene() active_camera = scene.getActiveCamera() render_width, render_height = active_camera.getWindowSize() render_width = int(render_width) render_height = int(render_height) preview_pass = PreviewPass(render_width, render_height) root = scene.getRoot() camera = Camera("snapshot", root) # determine zoom and look at bbox = None for node in DepthFirstIterator(root): if not getattr(node, "_outside_buildarea", False): if node.callDecoration("isSliceable") and node.getMeshData( ) and node.isVisible( ) and not node.callDecoration("isNonThumbnailVisibleMesh"): if bbox is None: bbox = node.getBoundingBox() else: bbox = bbox + node.getBoundingBox() # If there is no bounding box, it means that there is no model in the buildplate if bbox is None: return None look_at = bbox.center # guessed size so the objects are hopefully big size = max(bbox.width, bbox.height, bbox.depth * 0.5) # Looking from this direction (x, y, z) in OGL coordinates looking_from_offset = Vector(-1, 1, 2) if size > 0: # determine the watch distance depending on the size looking_from_offset = looking_from_offset * size * 1.75 camera.setPosition(look_at + looking_from_offset) camera.lookAt(look_at) satisfied = False size = None fovy = 30 while not satisfied: if size is not None: satisfied = True # always be satisfied after second try projection_matrix = Matrix() # Somehow the aspect ratio is also influenced in reverse by the screen width/height # So you have to set it to render_width/render_height to get 1 projection_matrix.setPerspective(fovy, render_width / render_height, 1, 500) camera.setProjectionMatrix(projection_matrix) preview_pass.setCamera(camera) preview_pass.render() pixel_output = preview_pass.getOutput() min_x, max_x, min_y, max_y = Snapshot.getImageBoundaries( pixel_output) size = max((max_x - min_x) / render_width, (max_y - min_y) / render_height) if size > 0.5 or satisfied: satisfied = True else: # make it big and allow for some empty space around fovy *= 0.5 # strangely enough this messes up the aspect ratio: fovy *= size * 1.1 # make it a square if max_x - min_x >= max_y - min_y: # make y bigger min_y, max_y = int((max_y + min_y) / 2 - (max_x - min_x) / 2), int((max_y + min_y) / 2 + (max_x - min_x) / 2) else: # make x bigger min_x, max_x = int((max_x + min_x) / 2 - (max_y - min_y) / 2), int((max_x + min_x) / 2 + (max_y - min_y) / 2) cropped_image = pixel_output.copy(min_x, min_y, max_x - min_x, max_y - min_y) # Scale it to the correct size scaled_image = cropped_image.scaled( width, height, aspectRatioMode=QtCore.Qt.IgnoreAspectRatio, transformMode=QtCore.Qt.SmoothTransformation) return scaled_image
def snapshot(width = 300, height = 300): scene = Application.getInstance().getController().getScene() active_camera = scene.getActiveCamera() render_width, render_height = active_camera.getWindowSize() render_width = int(render_width) render_height = int(render_height) preview_pass = PreviewPass(render_width, render_height) root = scene.getRoot() camera = Camera("snapshot", root) # determine zoom and look at bbox = None for node in DepthFirstIterator(root): if hasattr(node, "_outside_buildarea") and not node._outside_buildarea: if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible() and not node.callDecoration("isNonThumbnailVisibleMesh"): if bbox is None: bbox = node.getBoundingBox() else: bbox = bbox + node.getBoundingBox() # If there is no bounding box, it means that there is no model in the buildplate if bbox is None: return None look_at = bbox.center # guessed size so the objects are hopefully big size = max(bbox.width, bbox.height, bbox.depth * 0.5) # Looking from this direction (x, y, z) in OGL coordinates looking_from_offset = Vector(-1, 1, 2) if size > 0: # determine the watch distance depending on the size looking_from_offset = looking_from_offset * size * 1.3 camera.setPosition(look_at + looking_from_offset) camera.lookAt(look_at) satisfied = False size = None fovy = 30 while not satisfied: if size is not None: satisfied = True # always be satisfied after second try projection_matrix = Matrix() # Somehow the aspect ratio is also influenced in reverse by the screen width/height # So you have to set it to render_width/render_height to get 1 projection_matrix.setPerspective(fovy, render_width / render_height, 1, 500) camera.setProjectionMatrix(projection_matrix) preview_pass.setCamera(camera) preview_pass.render() pixel_output = preview_pass.getOutput() min_x, max_x, min_y, max_y = Snapshot.getImageBoundaries(pixel_output) size = max((max_x - min_x) / render_width, (max_y - min_y) / render_height) if size > 0.5 or satisfied: satisfied = True else: # make it big and allow for some empty space around fovy *= 0.5 # strangely enough this messes up the aspect ratio: fovy *= size * 1.1 # make it a square if max_x - min_x >= max_y - min_y: # make y bigger min_y, max_y = int((max_y + min_y) / 2 - (max_x - min_x) / 2), int((max_y + min_y) / 2 + (max_x - min_x) / 2) else: # make x bigger min_x, max_x = int((max_x + min_x) / 2 - (max_y - min_y) / 2), int((max_x + min_x) / 2 + (max_y - min_y) / 2) cropped_image = pixel_output.copy(min_x, min_y, max_x - min_x, max_y - min_y) # Scale it to the correct size scaled_image = cropped_image.scaled( width, height, aspectRatioMode = QtCore.Qt.IgnoreAspectRatio, transformMode = QtCore.Qt.SmoothTransformation) return scaled_image