Source code for picogl.backend.legacy.core.camera.unproject

"""
Unproject
"""

from typing import Optional, Tuple

import numpy as np
from OpenGL.GL import glGetDoublev, glGetIntegerv
from OpenGL.GLU import gluUnProject
from OpenGL.raw.GL._types import GL_FLOAT
from OpenGL.raw.GL.VERSION.GL_1_0 import (
    GL_DEPTH_COMPONENT,
    GL_DEPTH_TEST,
    GL_MODELVIEW_MATRIX,
    GL_PROJECTION_MATRIX,
    GL_VIEWPORT,
    glFlush,
    glIsEnabled,
    glReadPixels,
)

from picogl.logger import Logger as log


[docs] def unproject(x: int, y: int) -> Optional[Tuple[float, float, float]]: """ unproject :param x: x coordinate :param y: y coordinate :return: Tuple[int, int, int] coordinate_data_main Un-projects screen coordinate_data_main (x, y) into 3D world coordinate_data_main. Assumes OpenGL context is current -Ensure OpenGL context is current if needed i.e. self.makeCurrent() ← must be called before this if in Qt widget """ model_view = glGetDoublev(GL_MODELVIEW_MATRIX) log.parameter("model_view", model_view, silent=True) projection = glGetDoublev(GL_PROJECTION_MATRIX) log.parameter("projection", projection, silent=True) viewport = glGetIntegerv(GL_VIEWPORT) log.parameter("viewport", viewport, silent=True) y_gl = viewport[3] - y log.parameter("y_gl", y_gl, silent=True) if not (0 <= x < viewport[2] and 0 <= y_gl < viewport[3]): log.message(f"Coordinates out of bounds: ({x}, {y_gl})") return None if not glIsEnabled(GL_DEPTH_TEST): log.warning("Warning: GL_DEPTH_TEST is not enabled") # Read depth safely depth = np.array([0.0], dtype=np.float32) # log.parameter("depth", depth) try: glFlush() glReadPixels(x, y_gl, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth) except Exception as ex: log.error(f"glReadPixels failed: {ex}") return None wz = float(depth[0]) if wz == 1.0: return None log.parameter("depth", depth, silent=True) wx, wy, wz = gluUnProject(x, y_gl, wz, model_view, projection, viewport) log.parameter("wx", wx, silent=True) log.parameter("wy", wy, silent=True) log.parameter("wz", wz, silent=True) return wx, wy, wz