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)
class Camera(SceneNode.SceneNode): class PerspectiveMode(enum.Enum): PERSPECTIVE = "perspective" ORTHOGRAPHIC = "orthographic" @staticmethod def getDefaultZoomFactor() -> float: return -0.3334 def __init__(self, name: str = "", parent: Optional[SceneNode.SceneNode] = None) -> None: super().__init__(parent) self._name = name # type: str self._projection_matrix = Matrix() # type: Matrix self._projection_matrix.setOrtho(-5, 5, -5, 5, -100, 100) self._perspective = True # type: bool self._viewport_width = 0 # type: int self._viewport_height = 0 # type: int self._window_width = 0 # type: int self._window_height = 0 # type: int self._auto_adjust_view_port_size = True # type: bool self.setCalculateBoundingBox(False) self._cached_view_projection_matrix = None # type: Optional[Matrix] self._zoom_factor = Camera.getDefaultZoomFactor() from UM.Application import Application Application.getInstance().getPreferences().addPreference( "general/camera_perspective_mode", default_value=self.PerspectiveMode.PERSPECTIVE.value) Application.getInstance().getPreferences().preferenceChanged.connect( self._preferencesChanged) self._preferencesChanged("general/camera_perspective_mode") def __deepcopy__(self, memo: Dict[int, object]) -> "Camera": copy = cast(Camera, super().__deepcopy__(memo)) copy._projection_matrix = self._projection_matrix copy._window_height = self._window_height copy._window_width = self._window_width copy._viewport_height = self._viewport_height copy._viewport_width = self._viewport_width return copy def getZoomFactor(self): return self._zoom_factor def setZoomFactor(self, zoom_factor: float) -> None: # Only an orthographic camera has a zoom at the moment. if not self.isPerspective(): if self._zoom_factor != zoom_factor: self._zoom_factor = zoom_factor self._updatePerspectiveMatrix() def setMeshData(self, mesh_data: Optional["MeshData"]) -> None: assert mesh_data is None, "Camera's can't have mesh data" def getAutoAdjustViewPort(self) -> bool: return self._auto_adjust_view_port_size def setAutoAdjustViewPort(self, auto_adjust: bool) -> None: self._auto_adjust_view_port_size = auto_adjust ## Get the projection matrix of this camera. def getProjectionMatrix(self) -> Matrix: return self._projection_matrix def getViewportWidth(self) -> int: return self._viewport_width def setViewportWidth(self, width: int) -> None: self._viewport_width = width self._updatePerspectiveMatrix() def setViewportHeight(self, height: int) -> None: self._viewport_height = height self._updatePerspectiveMatrix() def setViewportSize(self, width: int, height: int) -> None: self._viewport_width = width self._viewport_height = height self._updatePerspectiveMatrix() def _updatePerspectiveMatrix(self) -> None: 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 getViewProjectionMatrix(self) -> Matrix: if self._cached_view_projection_matrix is None: inverted_transformation = self.getWorldTransformation() inverted_transformation.invert() self._cached_view_projection_matrix = self._projection_matrix.multiply( inverted_transformation, copy=True) return self._cached_view_projection_matrix def _updateWorldTransformation(self) -> None: self._cached_view_projection_matrix = None super()._updateWorldTransformation() def getViewportHeight(self) -> int: return self._viewport_height def setWindowSize(self, width: int, height: int) -> None: self._window_width = width self._window_height = height def getWindowSize(self) -> Tuple[int, int]: return self._window_width, self._window_height def render(self, renderer) -> bool: # It's a camera. It doesn't need rendering. return True ## Set the projection matrix of this camera. # \param matrix The projection matrix to use for this camera. def setProjectionMatrix(self, matrix: Matrix) -> None: self._projection_matrix = matrix self._cached_view_projection_matrix = None def isPerspective(self) -> bool: return self._perspective def setPerspective(self, perspective: bool) -> None: if self._perspective != perspective: self._perspective = perspective self._updatePerspectiveMatrix() perspectiveChanged = Signal() ## Get a ray from the camera into the world. # # This will create a ray from the camera's origin, passing through (x, y) # on the near plane and continuing based on the projection matrix. # # \param x The X coordinate on the near plane this ray should pass through. # \param y The Y coordinate on the near plane this ray should pass through. # # \return A Ray object representing a ray from the camera origin through X, Y. # # \note The near-plane coordinates should be in normalized form, that is within (-1, 1). def getRay(self, x: float, y: float) -> Ray: window_x = ((x + 1) / 2) * self._window_width window_y = ((y + 1) / 2) * self._window_height view_x = (window_x / self._viewport_width) * 2 - 1 view_y = (window_y / self._viewport_height) * 2 - 1 inverted_projection = numpy.linalg.inv( self._projection_matrix.getData().copy()) transformation = self.getWorldTransformation().getData() near = numpy.array([view_x, -view_y, -1.0, 1.0], dtype=numpy.float32) near = numpy.dot(inverted_projection, near) near = numpy.dot(transformation, near) near = near[0:3] / near[3] far = numpy.array([view_x, -view_y, 1.0, 1.0], dtype=numpy.float32) far = numpy.dot(inverted_projection, far) far = numpy.dot(transformation, far) far = far[0:3] / far[3] direction = far - near direction /= numpy.linalg.norm(direction) if self.isPerspective(): origin = self.getWorldPosition() direction = -direction else: # In orthographic mode, the origin is the click position on the plane where the camera resides, and that # plane is parallel to the near and the far planes. projection = numpy.array([view_x, -view_y, 0.0, 1.0], dtype=numpy.float32) projection = numpy.dot(inverted_projection, projection) projection = numpy.dot(transformation, projection) projection = projection[0:3] / projection[3] origin = Vector(data=projection) return Ray(origin, Vector(direction[0], direction[1], direction[2])) ## Project a 3D position onto the 2D view plane. def project(self, position: Vector) -> Tuple[float, float]: projection = self._projection_matrix view = self.getWorldTransformation() view.invert() position = position.preMultiply(view) position = position.preMultiply(projection) return position.x / position.z / 2.0, position.y / position.z / 2.0 ## Updates the _perspective field if the preference was modified. def _preferencesChanged(self, key: str) -> None: if key != "general/camera_perspective_mode": # Only listen to camera_perspective_mode. return from UM.Application import Application new_mode = str(Application.getInstance().getPreferences().getValue( "general/camera_perspective_mode")) # Translate the selected mode to the camera state. if new_mode == str(self.PerspectiveMode.ORTHOGRAPHIC.value): Logger.log("d", "Changing perspective mode to orthographic.") self.setPerspective(False) elif new_mode == str(self.PerspectiveMode.PERSPECTIVE.value): Logger.log("d", "Changing perspective mode to perspective.") self.setPerspective(True) else: Logger.log( "w", "Unknown perspective mode {new_mode}".format( new_mode=new_mode))
class Camera(SceneNode.SceneNode): def __init__(self, name: str = "", parent: SceneNode.SceneNode = None) -> None: super().__init__(parent) self._name = name # type: str self._projection_matrix = Matrix() # type: Matrix self._projection_matrix.setOrtho(-5, 5, 5, -5, -100, 100) self._perspective = True # type: bool self._viewport_width = 0 # type: int self._viewport_height = 0 # type: int self._window_width = 0 # type: int self._window_height = 0 # type: int self._auto_adjust_view_port_size = True # type: bool self.setCalculateBoundingBox(False) def __deepcopy__(self, memo: Dict[int, object]) -> "Camera": copy = cast(Camera, super().__deepcopy__(memo)) copy._projection_matrix = self._projection_matrix copy._window_height = self._window_height copy._window_width = self._window_width copy._viewport_height = self._viewport_height copy._viewport_width = self._viewport_width return copy def setMeshData(self, mesh_data: Optional["MeshData"]) -> None: assert mesh_data is None, "Camera's can't have mesh data" def getAutoAdjustViewPort(self) -> bool: return self._auto_adjust_view_port_size def setAutoAdjustViewPort(self, auto_adjust: bool) -> None: self._auto_adjust_view_port_size = auto_adjust ## Get the projection matrix of this camera. def getProjectionMatrix(self) -> Matrix: return Matrix(self._projection_matrix.getData()) def getViewportWidth(self) -> int: return self._viewport_width def setViewportWidth(self, width: int) -> None: self._viewport_width = width def setViewPortHeight(self, height: int) -> None: self._viewport_height = height def setViewportSize(self, width: int, height: int) -> None: self._viewport_width = width self._viewport_height = height def getViewportHeight(self) -> int: return self._viewport_height def setWindowSize(self, width: int, height: int) -> None: self._window_width = width self._window_height = height def getWindowSize(self) -> Tuple[int, int]: return self._window_width, self._window_height ## Set the projection matrix of this camera. # \param matrix The projection matrix to use for this camera. def setProjectionMatrix(self, matrix: Matrix) -> None: self._projection_matrix = matrix def isPerspective(self) -> bool: return self._perspective def setPerspective(self, perspective: bool) -> None: self._perspective = perspective ## Get a ray from the camera into the world. # # This will create a ray from the camera's origin, passing through (x, y) # on the near plane and continuing based on the projection matrix. # # \param x The X coordinate on the near plane this ray should pass through. # \param y The Y coordinate on the near plane this ray should pass through. # # \return A Ray object representing a ray from the camera origin through X, Y. # # \note The near-plane coordinates should be in normalized form, that is within (-1, 1). def getRay(self, x: float, y: float) -> Ray: window_x = ((x + 1) / 2) * self._window_width window_y = ((y + 1) / 2) * self._window_height view_x = (window_x / self._viewport_width) * 2 - 1 view_y = (window_y / self._viewport_height) * 2 - 1 inverted_projection = numpy.linalg.inv( self._projection_matrix.getData().copy()) transformation = self.getWorldTransformation().getData() near = numpy.array([view_x, -view_y, -1.0, 1.0], dtype=numpy.float32) near = numpy.dot(inverted_projection, near) near = numpy.dot(transformation, near) near = near[0:3] / near[3] far = numpy.array([view_x, -view_y, 1.0, 1.0], dtype=numpy.float32) far = numpy.dot(inverted_projection, far) far = numpy.dot(transformation, far) far = far[0:3] / far[3] direction = far - near direction /= numpy.linalg.norm(direction) return Ray(self.getWorldPosition(), Vector(-direction[0], -direction[1], -direction[2])) ## Project a 3D position onto the 2D view plane. def project(self, position: Vector) -> Tuple[float, float]: projection = self._projection_matrix view = self.getWorldTransformation().getInverse() position = position.preMultiply(view) position = position.preMultiply(projection) return position.x / position.z / 2.0, position.y / position.z / 2.0
class Camera(SceneNode.SceneNode): def __init__(self, name, parent=None): super().__init__(parent) self._name = name self._projection_matrix = Matrix() self._projection_matrix.setOrtho(-5, 5, 5, -5, -100, 100) self._perspective = False self._viewport_width = 0 self._viewport_height = 0 self._window_width = 0 self._window_height = 0 self.setCalculateBoundingBox(False) ## Get the projection matrix of this camera. def getProjectionMatrix(self): return copy.deepcopy(self._projection_matrix) def getViewportWidth(self): return self._viewport_width def setViewportWidth(self, width): self._viewport_width = width def setViewPortHeight(self, height): self._viewport_height = height def setViewportSize(self, width, height): self._viewport_width = width self._viewport_height = height def getViewportHeight(self): return self._viewport_height def setWindowSize(self, w, h): self._window_width = w self._window_height = h ## Set the projection matrix of this camera. # \param matrix The projection matrix to use for this camera. def setProjectionMatrix(self, matrix): self._projection_matrix = matrix def isPerspective(self): return self._perspective def setPerspective(self, pers): self._perspective = pers ## Get a ray from the camera into the world. # # This will create a ray from the camera's origin, passing through (x, y) # on the near plane and continuing based on the projection matrix. # # \param x The X coordinate on the near plane this ray should pass through. # \param y The Y coordinate on the near plane this ray should pass through. # # \return A Ray object representing a ray from the camera origin through X, Y. # # \note The near-plane coordinates should be in normalized form, that is within (-1, 1). def getRay(self, x, y): window_x = ((x + 1) / 2) * self._window_width window_y = ((y + 1) / 2) * self._window_height view_x = (window_x / self._viewport_width) * 2 - 1 view_y = (window_y / self._viewport_height) * 2 - 1 invp = numpy.linalg.inv(self._projection_matrix.getData().copy()) invv = self.getWorldTransformation().getData() near = numpy.array([view_x, -view_y, -1.0, 1.0], dtype=numpy.float32) near = numpy.dot(invp, near) near = numpy.dot(invv, near) near = near[0:3] / near[3] far = numpy.array([view_x, -view_y, 1.0, 1.0], dtype=numpy.float32) far = numpy.dot(invp, far) far = numpy.dot(invv, far) far = far[0:3] / far[3] dir = far - near dir /= numpy.linalg.norm(dir) return Ray(self.getWorldPosition(), Vector(-dir[0], -dir[1], -dir[2])) ## Project a 3D position onto the 2D view plane. def project(self, position): projection = self._projection_matrix view = self.getWorldTransformation().getInverse() position = position.preMultiply(view) position = position.preMultiply(projection) return (position.x / position.z / 2.0, position.y / position.z / 2.0)
class Camera(SceneNode.SceneNode): def __init__(self, name: str = "", parent: SceneNode.SceneNode = None) -> None: super().__init__(parent) self._name = name # type: str self._projection_matrix = Matrix() # type: Matrix self._projection_matrix.setOrtho(-5, 5, 5, -5, -100, 100) self._perspective = True # type: bool self._viewport_width = 0 # type: int self._viewport_height = 0 # type: int self._window_width = 0 # type: int self._window_height = 0 # type: int self._auto_adjust_view_port_size = True # type: bool self.setCalculateBoundingBox(False) self._cached_view_projection_matrix = None # type: Optional[Matrix] def __deepcopy__(self, memo: Dict[int, object]) -> "Camera": copy = cast(Camera, super().__deepcopy__(memo)) copy._projection_matrix = self._projection_matrix copy._window_height = self._window_height copy._window_width = self._window_width copy._viewport_height = self._viewport_height copy._viewport_width = self._viewport_width return copy def setMeshData(self, mesh_data: Optional["MeshData"]) -> None: assert mesh_data is None, "Camera's can't have mesh data" def getAutoAdjustViewPort(self) -> bool: return self._auto_adjust_view_port_size def setAutoAdjustViewPort(self, auto_adjust: bool) -> None: self._auto_adjust_view_port_size = auto_adjust ## Get the projection matrix of this camera. def getProjectionMatrix(self) -> Matrix: return self._projection_matrix def getViewportWidth(self) -> int: return self._viewport_width def setViewportWidth(self, width: int) -> None: self._viewport_width = width def setViewportHeight(self, height: int) -> None: self._viewport_height = height def setViewportSize(self, width: int, height: int) -> None: self._viewport_width = width self._viewport_height = height def getViewProjectionMatrix(self): if self._cached_view_projection_matrix is None: inverted_transformation = self.getWorldTransformation() inverted_transformation.invert() self._cached_view_projection_matrix = self._projection_matrix.multiply(inverted_transformation, copy = True) return self._cached_view_projection_matrix def _updateWorldTransformation(self): self._cached_view_projection_matrix = None super()._updateWorldTransformation() def getViewportHeight(self) -> int: return self._viewport_height def setWindowSize(self, width: int, height: int) -> None: self._window_width = width self._window_height = height def getWindowSize(self) -> Tuple[int, int]: return self._window_width, self._window_height def render(self, renderer) -> bool: # It's a camera. It doesn't need rendering. return True ## Set the projection matrix of this camera. # \param matrix The projection matrix to use for this camera. def setProjectionMatrix(self, matrix: Matrix) -> None: self._projection_matrix = matrix self._cached_view_projection_matrix = None def isPerspective(self) -> bool: return self._perspective def setPerspective(self, perspective: bool) -> None: self._perspective = perspective ## Get a ray from the camera into the world. # # This will create a ray from the camera's origin, passing through (x, y) # on the near plane and continuing based on the projection matrix. # # \param x The X coordinate on the near plane this ray should pass through. # \param y The Y coordinate on the near plane this ray should pass through. # # \return A Ray object representing a ray from the camera origin through X, Y. # # \note The near-plane coordinates should be in normalized form, that is within (-1, 1). def getRay(self, x: float, y: float) -> Ray: window_x = ((x + 1) / 2) * self._window_width window_y = ((y + 1) / 2) * self._window_height view_x = (window_x / self._viewport_width) * 2 - 1 view_y = (window_y / self._viewport_height) * 2 - 1 inverted_projection = numpy.linalg.inv(self._projection_matrix.getData().copy()) transformation = self.getWorldTransformation().getData() near = numpy.array([view_x, -view_y, -1.0, 1.0], dtype = numpy.float32) near = numpy.dot(inverted_projection, near) near = numpy.dot(transformation, near) near = near[0:3] / near[3] far = numpy.array([view_x, -view_y, 1.0, 1.0], dtype = numpy.float32) far = numpy.dot(inverted_projection, far) far = numpy.dot(transformation, far) far = far[0:3] / far[3] direction = far - near direction /= numpy.linalg.norm(direction) return Ray(self.getWorldPosition(), Vector(-direction[0], -direction[1], -direction[2])) ## Project a 3D position onto the 2D view plane. def project(self, position: Vector) -> Tuple[float, float]: projection = self._projection_matrix view = self.getWorldTransformation() view.invert() position = position.preMultiply(view) position = position.preMultiply(projection) return position.x / position.z / 2.0, position.y / position.z / 2.0
class Camera(SceneNode.SceneNode): def __init__(self, name, parent = None): super().__init__(parent) self._name = name self._projection_matrix = Matrix() self._projection_matrix.setOrtho(-5, 5, 5, -5, -100, 100) self._perspective = False self._viewport_width = 0 self._viewport_height = 0 self.setCalculateBoundingBox(False) ## Get the projection matrix of this camera. def getProjectionMatrix(self): return self._projection_matrix def getViewportWidth(self): return self._viewport_width def setViewportWidth(self, width): self._viewport_width = width def setViewPortHeight(self,height): self._viewport_height = height def setViewportSize(self,width,height): self._viewport_width = width self._viewport_height = height def getViewportHeight(self): return self._viewport_height ## Set the projection matrix of this camera. # \param matrix The projection matrix to use for this camera. def setProjectionMatrix(self, matrix): self._projection_matrix = matrix def isPerspective(self): return self._perspective def setPerspective(self, pers): self._perspective = pers ## Get a ray from the camera into the world. # # This will create a ray from the camera's origin, passing through (x, y) # on the near plane and continuing based on the projection matrix. # # \param x The X coordinate on the near plane this ray should pass through. # \param y The Y coordinate on the near plane this ray should pass through. # # \return A Ray object representing a ray from the camera origin through X, Y. # # \note The near-plane coordinates should be in normalized form, that is within (-1, 1). def getRay(self, x, y): invp = numpy.linalg.inv(self._projection_matrix.getData().copy()) invv = self.getWorldTransformation().getData() near = numpy.array([x, -y, -1.0, 1.0], dtype=numpy.float32) near = numpy.dot(invp, near) near = numpy.dot(invv, near) near = near[0:3] / near[3] far = numpy.array([x, -y, 1.0, 1.0], dtype = numpy.float32) far = numpy.dot(invp, far) far = numpy.dot(invv, far) far = far[0:3] / far[3] dir = far - near dir /= numpy.linalg.norm(dir) return Ray(self.getWorldPosition(), Vector(-dir[0], -dir[1], -dir[2]))
class Camera(SceneNode.SceneNode): def __init__(self, name, parent = None): super().__init__(parent) self._name = name self._projection_matrix = Matrix() self._projection_matrix.setOrtho(-5, 5, 5, -5, -100, 100) self._perspective = False self._viewport_width = 0 self._viewport_height = 0 self._window_width = 0 self._window_height = 0 self.setCalculateBoundingBox(False) ## Get the projection matrix of this camera. def getProjectionMatrix(self): return copy.deepcopy(self._projection_matrix) def getViewportWidth(self): return self._viewport_width def setViewportWidth(self, width): self._viewport_width = width def setViewPortHeight(self,height): self._viewport_height = height def setViewportSize(self,width,height): self._viewport_width = width self._viewport_height = height def getViewportHeight(self): return self._viewport_height def setWindowSize(self, w, h): self._window_width = w self._window_height = h ## Set the projection matrix of this camera. # \param matrix The projection matrix to use for this camera. def setProjectionMatrix(self, matrix): self._projection_matrix = matrix def isPerspective(self): return self._perspective def setPerspective(self, pers): self._perspective = pers ## Get a ray from the camera into the world. # # This will create a ray from the camera's origin, passing through (x, y) # on the near plane and continuing based on the projection matrix. # # \param x The X coordinate on the near plane this ray should pass through. # \param y The Y coordinate on the near plane this ray should pass through. # # \return A Ray object representing a ray from the camera origin through X, Y. # # \note The near-plane coordinates should be in normalized form, that is within (-1, 1). def getRay(self, x, y): window_x = ((x + 1) / 2) * self._window_width window_y = ((y + 1) / 2) * self._window_height view_x = (window_x / self._viewport_width) * 2 - 1 view_y = (window_y / self._viewport_height) * 2 - 1 inverted_projection = numpy.linalg.inv(self._projection_matrix.getData().copy()) transformation = self.getWorldTransformation().getData() near = numpy.array([view_x, -view_y, -1.0, 1.0], dtype = numpy.float32) near = numpy.dot(inverted_projection, near) near = numpy.dot(transformation, near) near = near[0:3] / near[3] far = numpy.array([view_x, -view_y, 1.0, 1.0], dtype = numpy.float32) far = numpy.dot(inverted_projection, far) far = numpy.dot(transformation, far) far = far[0:3] / far[3] dir = far - near dir /= numpy.linalg.norm(dir) return Ray(self.getWorldPosition(), Vector(-dir[0], -dir[1], -dir[2])) ## Project a 3D position onto the 2D view plane. def project(self, position): projection = self._projection_matrix view = self.getWorldTransformation().getInverse() position = position.preMultiply(view) position = position.preMultiply(projection) return position.x / position.z / 2.0, position.y / position.z / 2.0