Team Ai
Apppublic

OpenMotionLab/MotionGPT

sourceHugging Facemitupdated 1y agoView on Hugging Face
118likes
camera.py438 linesDownload Raw Back to pyrender
1"""Virtual cameras compliant with the glTF 2.0 specification as described at2https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-camera3 4Author: Matthew Matl5"""6import abc7import numpy as np8import six9import sys10 11from .constants import DEFAULT_Z_NEAR, DEFAULT_Z_FAR12 13 14@six.add_metaclass(abc.ABCMeta)15class Camera(object):16    """Abstract base class for all cameras.17 18    Note19    ----20    Camera poses are specified in the OpenGL format,21    where the z axis points away from the view direction and the22    x and y axes point to the right and up in the image plane, respectively.23 24    Parameters25    ----------26    znear : float27        The floating-point distance to the near clipping plane.28    zfar : float29        The floating-point distance to the far clipping plane.30        ``zfar`` must be greater than ``znear``.31    name : str, optional32        The user-defined name of this object.33    """34 35    def __init__(self,36                 znear=DEFAULT_Z_NEAR,37                 zfar=DEFAULT_Z_FAR,38                 name=None):39        self.name = name40        self.znear = znear41        self.zfar = zfar42 43    @property44    def name(self):45        """str : The user-defined name of this object.46        """47        return self._name48 49    @name.setter50    def name(self, value):51        if value is not None:52            value = str(value)53        self._name = value54 55    @property56    def znear(self):57        """float : The distance to the near clipping plane.58        """59        return self._znear60 61    @znear.setter62    def znear(self, value):63        value = float(value)64        if value < 0:65            raise ValueError('z-near must be >= 0.0')66        self._znear = value67 68    @property69    def zfar(self):70        """float : The distance to the far clipping plane.71        """72        return self._zfar73 74    @zfar.setter75    def zfar(self, value):76        value = float(value)77        if value <= 0 or value <= self.znear:78            raise ValueError('zfar must be >0 and >znear')79        self._zfar = value80 81    @abc.abstractmethod82    def get_projection_matrix(self, width=None, height=None):83        """Return the OpenGL projection matrix for this camera.84 85        Parameters86        ----------87        width : int88            Width of the current viewport, in pixels.89        height : int90            Height of the current viewport, in pixels.91        """92        pass93 94 95class PerspectiveCamera(Camera):96 97    """A perspective camera for perspective projection.98 99    Parameters100    ----------101    yfov : float102        The floating-point vertical field of view in radians.103    znear : float104        The floating-point distance to the near clipping plane.105        If not specified, defaults to 0.05.106    zfar : float, optional107        The floating-point distance to the far clipping plane.108        ``zfar`` must be greater than ``znear``.109        If None, the camera uses an infinite projection matrix.110    aspectRatio : float, optional111        The floating-point aspect ratio of the field of view.112        If not specified, the camera uses the viewport's aspect ratio.113    name : str, optional114        The user-defined name of this object.115    """116 117    def __init__(self,118                 yfov,119                 znear=DEFAULT_Z_NEAR,120                 zfar=None,121                 aspectRatio=None,122                 name=None):123        super(PerspectiveCamera, self).__init__(124            znear=znear,125            zfar=zfar,126            name=name,127        )128 129        self.yfov = yfov130        self.aspectRatio = aspectRatio131 132    @property133    def yfov(self):134        """float : The vertical field of view in radians.135        """136        return self._yfov137 138    @yfov.setter139    def yfov(self, value):140        value = float(value)141        if value <= 0.0:142            raise ValueError('Field of view must be positive')143        self._yfov = value144 145    @property146    def zfar(self):147        """float : The distance to the far clipping plane.148        """149        return self._zfar150 151    @zfar.setter152    def zfar(self, value):153        if value is not None:154            value = float(value)155            if value <= 0 or value <= self.znear:156                raise ValueError('zfar must be >0 and >znear')157        self._zfar = value158 159    @property160    def aspectRatio(self):161        """float : The ratio of the width to the height of the field of view.162        """163        return self._aspectRatio164 165    @aspectRatio.setter166    def aspectRatio(self, value):167        if value is not None:168            value = float(value)169            if value <= 0.0:170                raise ValueError('Aspect ratio must be positive')171        self._aspectRatio = value172 173    def get_projection_matrix(self, width=None, height=None):174        """Return the OpenGL projection matrix for this camera.175 176        Parameters177        ----------178        width : int179            Width of the current viewport, in pixels.180        height : int181            Height of the current viewport, in pixels.182        """183        aspect_ratio = self.aspectRatio184        if aspect_ratio is None:185            if width is None or height is None:186                raise ValueError('Aspect ratio of camera must be defined')187            aspect_ratio = float(width) / float(height)188 189        a = aspect_ratio190        t = np.tan(self.yfov / 2.0)191        n = self.znear192        f = self.zfar193 194        P = np.zeros((4,4))195        P[0][0] = 1.0 / (a * t)196        P[1][1] = 1.0 / t197        P[3][2] = -1.0198 199        if f is None:200            P[2][2] = -1.0201            P[2][3] = -2.0 * n202        else:203            P[2][2] = (f + n) / (n - f)204            P[2][3] = (2 * f * n) / (n - f)205 206        return P207 208 209class OrthographicCamera(Camera):210    """An orthographic camera for orthographic projection.211 212    Parameters213    ----------214    xmag : float215        The floating-point horizontal magnification of the view.216    ymag : float217        The floating-point vertical magnification of the view.218    znear : float219        The floating-point distance to the near clipping plane.220        If not specified, defaults to 0.05.221    zfar : float222        The floating-point distance to the far clipping plane.223        ``zfar`` must be greater than ``znear``.224        If not specified, defaults to 100.0.225    name : str, optional226        The user-defined name of this object.227    """228 229    def __init__(self,230                 xmag,231                 ymag,232                 znear=DEFAULT_Z_NEAR,233                 zfar=DEFAULT_Z_FAR,234                 name=None):235        super(OrthographicCamera, self).__init__(236            znear=znear,237            zfar=zfar,238            name=name,239        )240 241        self.xmag = xmag242        self.ymag = ymag243 244    @property245    def xmag(self):246        """float : The horizontal magnification of the view.247        """248        return self._xmag249 250    @xmag.setter251    def xmag(self, value):252        value = float(value)253        if value <= 0.0:254            raise ValueError('X magnification must be positive')255        self._xmag = value256 257    @property258    def ymag(self):259        """float : The vertical magnification of the view.260        """261        return self._ymag262 263    @ymag.setter264    def ymag(self, value):265        value = float(value)266        if value <= 0.0:267            raise ValueError('Y magnification must be positive')268        self._ymag = value269 270    @property271    def znear(self):272        """float : The distance to the near clipping plane.273        """274        return self._znear275 276    @znear.setter277    def znear(self, value):278        value = float(value)279        if value <= 0:280            raise ValueError('z-near must be > 0.0')281        self._znear = value282 283    def get_projection_matrix(self, width=None, height=None):284        """Return the OpenGL projection matrix for this camera.285 286        Parameters287        ----------288        width : int289            Width of the current viewport, in pixels.290            Unused in this function.291        height : int292            Height of the current viewport, in pixels.293            Unused in this function.294        """295        xmag = self.xmag296        ymag = self.ymag297 298        # If screen width/height defined, rescale xmag299        if width is not None and height is not None:300            xmag = width / height * ymag301 302        n = self.znear303        f = self.zfar304        P = np.zeros((4,4))305        P[0][0] = 1.0 / xmag306        P[1][1] = 1.0 / ymag307        P[2][2] = 2.0 / (n - f)308        P[2][3] = (f + n) / (n - f)309        P[3][3] = 1.0310        return P311 312 313class IntrinsicsCamera(Camera):314    """A perspective camera with custom intrinsics.315 316    Parameters317    ----------318    fx : float319        X-axis focal length in pixels.320    fy : float321        Y-axis focal length in pixels.322    cx : float323        X-axis optical center in pixels.324    cy : float325        Y-axis optical center in pixels.326    znear : float327        The floating-point distance to the near clipping plane.328        If not specified, defaults to 0.05.329    zfar : float330        The floating-point distance to the far clipping plane.331        ``zfar`` must be greater than ``znear``.332        If not specified, defaults to 100.0.333    name : str, optional334        The user-defined name of this object.335    """336 337    def __init__(self,338                 fx,339                 fy,340                 cx,341                 cy,342                 znear=DEFAULT_Z_NEAR,343                 zfar=DEFAULT_Z_FAR,344                 name=None):345        super(IntrinsicsCamera, self).__init__(346            znear=znear,347            zfar=zfar,348            name=name,349        )350 351        self.fx = fx352        self.fy = fy353        self.cx = cx354        self.cy = cy355 356    @property357    def fx(self):358        """float : X-axis focal length in meters.359        """360        return self._fx361 362    @fx.setter363    def fx(self, value):364        self._fx = float(value)365 366    @property367    def fy(self):368        """float : Y-axis focal length in meters.369        """370        return self._fy371 372    @fy.setter373    def fy(self, value):374        self._fy = float(value)375 376    @property377    def cx(self):378        """float : X-axis optical center in pixels.379        """380        return self._cx381 382    @cx.setter383    def cx(self, value):384        self._cx = float(value)385 386    @property387    def cy(self):388        """float : Y-axis optical center in pixels.389        """390        return self._cy391 392    @cy.setter393    def cy(self, value):394        self._cy = float(value)395 396    def get_projection_matrix(self, width, height):397        """Return the OpenGL projection matrix for this camera.398 399        Parameters400        ----------401        width : int402            Width of the current viewport, in pixels.403        height : int404            Height of the current viewport, in pixels.405        """406        width = float(width)407        height = float(height)408 409        cx, cy = self.cx, self.cy410        fx, fy = self.fx, self.fy411        if sys.platform == 'darwin':412            cx = self.cx * 2.0413            cy = self.cy * 2.0414            fx = self.fx * 2.0415            fy = self.fy * 2.0416 417        P = np.zeros((4,4))418        P[0][0] = 2.0 * fx / width419        P[1][1] = 2.0 * fy / height420        P[0][2] = 1.0 - 2.0 * cx / width421        P[1][2] = 2.0 * cy / height - 1.0422        P[3][2] = -1.0423 424        n = self.znear425        f = self.zfar426        if f is None:427            P[2][2] = -1.0428            P[2][3] = -2.0 * n429        else:430            P[2][2] = (f + n) / (n - f)431            P[2][3] = (2 * f * n) / (n - f)432 433        return P434 435 436__all__ = ['Camera', 'PerspectiveCamera', 'OrthographicCamera',437           'IntrinsicsCamera']438