def setup_model_matrix(matrix: QMatrix4x4, rotation: np.ndarray, translation: np.ndarray) -> None: matrix.setToIdentity() # Translate matrix (translation = rotation_center) matrix.translate(*translation) # Rotate matrix matrix.rotate(rotation[0], 1.0, 0.0, 0.0) matrix.rotate(rotation[1], 0.0, 1.0, 0.0) matrix.rotate(rotation[2], 0.0, 0.0, 1.0) # Restore matrix matrix.translate(*-translation)
def __init__(self, parent=None): super().__init__(parent) self.m_window_matrix = QMatrix4x4() self.m_projection = QMatrix4x4() self.m_view = QMatrix4x4() self.m_model = QMatrix4x4() self.m_brush = QBrush() self.m_timer = QTimer() self.m_view.lookAt(QVector3D(3, 1, 1), QVector3D(0, 0, 0), QVector3D(0, 1, 0)) self.m_timer.setInterval(16) self.m_timer.timeout.connect(self.update) self.m_timer.start()
def projectionMatrix(self, region=None): # Xw = (Xnd + 1) * width/2 + X if region is None: region = (0, 0, self.width(), self.height()) x0, y0, w, h = self.getViewport() dist = self.props.distance fov = self.props.fov nearClip = dist * 0.001 farClip = dist * 1000.0 r = nearClip * np.tan(fov * 0.5 * np.pi / 180.0) t = r * h / w # convert screen coordinates (region) to normalized device coordinates # Xnd = (Xw - X0) * 2/width - 1 ## Note that X0 and width in these equations must be the values used in viewport left = r * ((region[0] - x0) * (2.0 / w) - 1) right = r * ((region[0] + region[2] - x0) * (2.0 / w) - 1) bottom = t * ((region[1] - y0) * (2.0 / h) - 1) top = t * ((region[1] + region[3] - y0) * (2.0 / h) - 1) tr = QMatrix4x4() tr.frustum(left, right, bottom, top, nearClip, farClip) return tr
def _setup_text_vertices(self) -> None: text_vertices = [] # Retrieve initial position x, y, z = self.position # Setup text vertices for c in self.text: ch = TextManager.characters[c] w, h = ch.textureSize w = w * self.tex_scale h = h * self.tex_scale text_vertices.append(self._rendering_buffer(x, y, z, w, h)) x += (ch.advance >> 6) * self.tex_scale tvs = np.array(text_vertices).reshape((-1, 3)) # Centered = Position represents center of the whole text, instead of the bottom left. if self.centered: ptp = np.ptp(tvs, axis=0) tvs -= ptp / 2 # Rotate vertices as required matrix = QMatrix4x4() matrix.translate(*self.position) matrix.rotate(self.rotation[0], 1.0, 0.0, 0.0) matrix.rotate(self.rotation[1], 0.0, 1.0, 0.0) matrix.rotate(self.rotation[2], 0.0, 0.0, 1.0) matrix.translate(*-self.position) # PySide2 requires this workaround tvs_response = [] for vec in tvs: vec4 = vec.tolist() + [1.0] temp_matrix = QMatrix4x4(*4 * vec4) response = (matrix * temp_matrix.transposed()).column(0) np_response = np.array([response.x(), response.y(), response.z()], np.float32) tvs_response.append(np_response) tvs = np.array(tvs_response, np.float32).reshape((len(self.text), -1)) self.text_vertices = tvs.reshape((len(self.text), -1))
def scale(self, x, y, z, local=True): """ Scale the object by (*dx*, *dy*, *dz*) in its local coordinate system. If *local* is False, then scale takes place in the parent's coordinates. """ tr = QMatrix4x4() tr.scale(x, y, z) self.applyTransform(tr, local=local)
def translate(self, dx, dy, dz, local=False): """ Translate the object by (*dx*, *dy*, *dz*) in its parent's coordinate system. If *local* is True, then translation takes place in local coordinates. """ tr = QMatrix4x4() # Transform3D() tr.translate(dx, dy, dz) self.applyTransform(tr, local=local)
def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) # Model self.model = Model() # Factory self.factory = DrawableFactory(self.model) # Drawable elements self.drawable_collection = GLDrawableCollection() self.pre_collection = GLPreCollection() self.post_collection = GLPostCollection() # Controllers self.current_controller = None self.controllers = {} # Model/View/Projection matrices self.model_matrix = QMatrix4x4() self.view_matrix = QMatrix4x4() self.proj_matrix = QMatrix4x4() # FPS Counter self.fps_counter = FPSCounter() # Initial positions and rotations self._rotation_center = np.array([0.0, 0.0, 0.0]) self._rotation_angle = np.array([0.0, 0.0, 0.0]) self._camera_position = np.array([0.0, 0.0, 200.0]) # Cross-section data self.last_cross_origin = np.asarray([0.0, 0.0, 0.0]) self.last_cross_normal = np.asarray([1.0, 0.0, 0.0]) self.is_cross_sectioned = False self.is_phantom_enabled = False # Extra information self.is_animated = False self.fov = 45.0 self.smoothness = 2.0 # Bigger => smoother (but slower) rotations self.current_projection = 'Perspective' # 'Perspective'/'Orthographic' # Initialize viewer self.initialize()
def rotate(self, angle, x, y, z, local=False): """ Rotate the object around the axis specified by (x,y,z). *angle* is in degrees. """ tr = QMatrix4x4() tr.rotate(angle, x, y, z) self.applyTransform(tr, local=local)
def paintEvent(self, event): p = QPainter(self) p.fillRect(QRect(0, 0, self.width(), self.height()), Qt.gray) p.setWorldTransform(self.m_window_matrix.toTransform()) mvp = QMatrix4x4(self.m_projection * self.m_view * self.m_model) p.setTransform(mvp.toTransform(), True) p.fillPath(painterPathForTriangle(), self.m_brush) self.m_model.rotate(1, 0, 1, 0)
def unproject(self, x: float, y: float, z: float) -> np.ndarray: # Adapted from http://antongerdelan.net/opengl/raycasting.html # Note: x, y, z must be normalized to [-1.0, +1.0] # We'd use `QVector4D(x, y, -1.0, 1.0)`, but PySide2 # hasn't implemented QMatrix4x4 * QVector4D yet. vector = [x, y, -1.0, 1.0] temp_matrix = QMatrix4x4(*[e for e in vector for _ in range(4)]) ray_eye = (self.proj_matrix.inverted()[0] * temp_matrix).column(0) ray_eye = QVector4D(ray_eye.x(), ray_eye.y(), -1.0, 0.0) # We'd use `ray_eye`, but PySide2 # hasn't implemented QMatrix4x4 * QVector4D yet. vector = [ray_eye.x(), ray_eye.y(), ray_eye.z(), ray_eye.w()] temp_matrix = QMatrix4x4(*[e for e in vector for _ in range(4)]) # Our self.view_matrix and self.model_matrix are altered to simplify rendering. # For ray calculations, that's irrelevant, although we'll still use the correct ones for consistency. ray_world = ((self.view_matrix_math * self.model_matrix_math).inverted()[0] * temp_matrix).column(0).toVector3D() ray = ray_world.normalized() return np.array([ray.x(), ray.y(), ray.z()])
def viewMatrix(self): tr = QMatrix4x4() ntr = np.eye(4, dtype=np.float) tr.translate(0.0, 0.0, -self.props.distance) ntr[0:3, 3] = [0.0, 0.0, -self.props.distance] tr.rotate(self.props.elevation_angle - 90, 1, 0, 0) tr.rotate(self.props.azimuth_angle - 90, 0, 0, -1) center = self.props.center tr.translate(-center[0], -center[1], -center[2]) return tr
def __init__(self, *args, glOptions=DefaultGlOptions.OPAQUE, parentItem=None, **kwargs): super(GLGraphicsItem, self).__init__() self._id = GLGraphicsItem._nextId GLGraphicsItem._nextId += 1 self.__parent = None self.__view = None self.__children = set() self.__transform = QMatrix4x4() self.__visible = True self.setParentItem(parentItem) # self.setDepthValue(0) self.__glOpts = glOptions
def resizeEvent(self, event): if self.width() <= 0: return self.m_window_matrix = QMatrix4x4() self.m_window_matrix.translate(self.width() / 2.0, self.height() / 2.0) self.m_window_matrix.scale(self.width() / 2.0, -self.height() / 2.0) self.m_projection.setToIdentity() self.m_projection.perspective(45.0, self.width() * 1.0 / self.height(), 0.1, 100.0) gradient = QLinearGradient(QPointF(-1, -1), QPointF(1, 1)) gradient.setColorAt(0, Qt.red) gradient.setColorAt(1, Qt.green) self.m_brush = QBrush(gradient)
def v_matrix(self): """The view matrix in use.""" matrix = QMatrix4x4() matrix.lookAt(self.camera_pos, self.camera_look_at, self.camera_normal) return matrix
def p_matrix(self): """Get the perspective matrix.""" matrix = QMatrix4x4() angle, near, far = self.PERSPECTIVE matrix.perspective(angle, self.viewport_proportions, near, far) return matrix
def model_matrix_math(self) -> QMatrix4x4: matrix = QMatrix4x4() self.setup_model_matrix(matrix, self.rotation_angle, self.rotation_center) return matrix
def view_matrix_math(self) -> QMatrix4x4: matrix = QMatrix4x4() self.setup_view_matrix(matrix, self.camera_position) return matrix
def setup_view_matrix(matrix: QMatrix4x4, camera: iter) -> None: matrix.setToIdentity() matrix.translate(*-camera)