Spaces:
Runtime error
Runtime error
| """Virtual cameras compliant with the glTF 2.0 specification as described at | |
| https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-camera | |
| Author: Matthew Matl | |
| """ | |
| import abc | |
| import numpy as np | |
| import six | |
| import sys | |
| from .constants import DEFAULT_Z_NEAR, DEFAULT_Z_FAR | |
| class Camera(object): | |
| """Abstract base class for all cameras. | |
| Note | |
| ---- | |
| Camera poses are specified in the OpenGL format, | |
| where the z axis points away from the view direction and the | |
| x and y axes point to the right and up in the image plane, respectively. | |
| Parameters | |
| ---------- | |
| znear : float | |
| The floating-point distance to the near clipping plane. | |
| zfar : float | |
| The floating-point distance to the far clipping plane. | |
| ``zfar`` must be greater than ``znear``. | |
| name : str, optional | |
| The user-defined name of this object. | |
| """ | |
| def __init__(self, | |
| znear=DEFAULT_Z_NEAR, | |
| zfar=DEFAULT_Z_FAR, | |
| name=None): | |
| self.name = name | |
| self.znear = znear | |
| self.zfar = zfar | |
| def name(self): | |
| """str : The user-defined name of this object. | |
| """ | |
| return self._name | |
| def name(self, value): | |
| if value is not None: | |
| value = str(value) | |
| self._name = value | |
| def znear(self): | |
| """float : The distance to the near clipping plane. | |
| """ | |
| return self._znear | |
| def znear(self, value): | |
| value = float(value) | |
| if value < 0: | |
| raise ValueError('z-near must be >= 0.0') | |
| self._znear = value | |
| def zfar(self): | |
| """float : The distance to the far clipping plane. | |
| """ | |
| return self._zfar | |
| def zfar(self, value): | |
| value = float(value) | |
| if value <= 0 or value <= self.znear: | |
| raise ValueError('zfar must be >0 and >znear') | |
| self._zfar = value | |
| def get_projection_matrix(self, width=None, height=None): | |
| """Return the OpenGL projection matrix for this camera. | |
| Parameters | |
| ---------- | |
| width : int | |
| Width of the current viewport, in pixels. | |
| height : int | |
| Height of the current viewport, in pixels. | |
| """ | |
| pass | |
| class PerspectiveCamera(Camera): | |
| """A perspective camera for perspective projection. | |
| Parameters | |
| ---------- | |
| yfov : float | |
| The floating-point vertical field of view in radians. | |
| znear : float | |
| The floating-point distance to the near clipping plane. | |
| If not specified, defaults to 0.05. | |
| zfar : float, optional | |
| The floating-point distance to the far clipping plane. | |
| ``zfar`` must be greater than ``znear``. | |
| If None, the camera uses an infinite projection matrix. | |
| aspectRatio : float, optional | |
| The floating-point aspect ratio of the field of view. | |
| If not specified, the camera uses the viewport's aspect ratio. | |
| name : str, optional | |
| The user-defined name of this object. | |
| """ | |
| def __init__(self, | |
| yfov, | |
| znear=DEFAULT_Z_NEAR, | |
| zfar=None, | |
| aspectRatio=None, | |
| name=None): | |
| super(PerspectiveCamera, self).__init__( | |
| znear=znear, | |
| zfar=zfar, | |
| name=name, | |
| ) | |
| self.yfov = yfov | |
| self.aspectRatio = aspectRatio | |
| def yfov(self): | |
| """float : The vertical field of view in radians. | |
| """ | |
| return self._yfov | |
| def yfov(self, value): | |
| value = float(value) | |
| if value <= 0.0: | |
| raise ValueError('Field of view must be positive') | |
| self._yfov = value | |
| def zfar(self): | |
| """float : The distance to the far clipping plane. | |
| """ | |
| return self._zfar | |
| def zfar(self, value): | |
| if value is not None: | |
| value = float(value) | |
| if value <= 0 or value <= self.znear: | |
| raise ValueError('zfar must be >0 and >znear') | |
| self._zfar = value | |
| def aspectRatio(self): | |
| """float : The ratio of the width to the height of the field of view. | |
| """ | |
| return self._aspectRatio | |
| def aspectRatio(self, value): | |
| if value is not None: | |
| value = float(value) | |
| if value <= 0.0: | |
| raise ValueError('Aspect ratio must be positive') | |
| self._aspectRatio = value | |
| def get_projection_matrix(self, width=None, height=None): | |
| """Return the OpenGL projection matrix for this camera. | |
| Parameters | |
| ---------- | |
| width : int | |
| Width of the current viewport, in pixels. | |
| height : int | |
| Height of the current viewport, in pixels. | |
| """ | |
| aspect_ratio = self.aspectRatio | |
| if aspect_ratio is None: | |
| if width is None or height is None: | |
| raise ValueError('Aspect ratio of camera must be defined') | |
| aspect_ratio = float(width) / float(height) | |
| a = aspect_ratio | |
| t = np.tan(self.yfov / 2.0) | |
| n = self.znear | |
| f = self.zfar | |
| P = np.zeros((4,4)) | |
| P[0][0] = 1.0 / (a * t) | |
| P[1][1] = 1.0 / t | |
| P[3][2] = -1.0 | |
| if f is None: | |
| P[2][2] = -1.0 | |
| P[2][3] = -2.0 * n | |
| else: | |
| P[2][2] = (f + n) / (n - f) | |
| P[2][3] = (2 * f * n) / (n - f) | |
| return P | |
| class OrthographicCamera(Camera): | |
| """An orthographic camera for orthographic projection. | |
| Parameters | |
| ---------- | |
| xmag : float | |
| The floating-point horizontal magnification of the view. | |
| ymag : float | |
| The floating-point vertical magnification of the view. | |
| znear : float | |
| The floating-point distance to the near clipping plane. | |
| If not specified, defaults to 0.05. | |
| zfar : float | |
| The floating-point distance to the far clipping plane. | |
| ``zfar`` must be greater than ``znear``. | |
| If not specified, defaults to 100.0. | |
| name : str, optional | |
| The user-defined name of this object. | |
| """ | |
| def __init__(self, | |
| xmag, | |
| ymag, | |
| znear=DEFAULT_Z_NEAR, | |
| zfar=DEFAULT_Z_FAR, | |
| name=None): | |
| super(OrthographicCamera, self).__init__( | |
| znear=znear, | |
| zfar=zfar, | |
| name=name, | |
| ) | |
| self.xmag = xmag | |
| self.ymag = ymag | |
| def xmag(self): | |
| """float : The horizontal magnification of the view. | |
| """ | |
| return self._xmag | |
| def xmag(self, value): | |
| value = float(value) | |
| if value <= 0.0: | |
| raise ValueError('X magnification must be positive') | |
| self._xmag = value | |
| def ymag(self): | |
| """float : The vertical magnification of the view. | |
| """ | |
| return self._ymag | |
| def ymag(self, value): | |
| value = float(value) | |
| if value <= 0.0: | |
| raise ValueError('Y magnification must be positive') | |
| self._ymag = value | |
| def znear(self): | |
| """float : The distance to the near clipping plane. | |
| """ | |
| return self._znear | |
| def znear(self, value): | |
| value = float(value) | |
| if value <= 0: | |
| raise ValueError('z-near must be > 0.0') | |
| self._znear = value | |
| def get_projection_matrix(self, width=None, height=None): | |
| """Return the OpenGL projection matrix for this camera. | |
| Parameters | |
| ---------- | |
| width : int | |
| Width of the current viewport, in pixels. | |
| Unused in this function. | |
| height : int | |
| Height of the current viewport, in pixels. | |
| Unused in this function. | |
| """ | |
| xmag = self.xmag | |
| ymag = self.ymag | |
| # If screen width/height defined, rescale xmag | |
| if width is not None and height is not None: | |
| xmag = width / height * ymag | |
| n = self.znear | |
| f = self.zfar | |
| P = np.zeros((4,4)) | |
| P[0][0] = 1.0 / xmag | |
| P[1][1] = 1.0 / ymag | |
| P[2][2] = 2.0 / (n - f) | |
| P[2][3] = (f + n) / (n - f) | |
| P[3][3] = 1.0 | |
| return P | |
| class IntrinsicsCamera(Camera): | |
| """A perspective camera with custom intrinsics. | |
| Parameters | |
| ---------- | |
| fx : float | |
| X-axis focal length in pixels. | |
| fy : float | |
| Y-axis focal length in pixels. | |
| cx : float | |
| X-axis optical center in pixels. | |
| cy : float | |
| Y-axis optical center in pixels. | |
| znear : float | |
| The floating-point distance to the near clipping plane. | |
| If not specified, defaults to 0.05. | |
| zfar : float | |
| The floating-point distance to the far clipping plane. | |
| ``zfar`` must be greater than ``znear``. | |
| If not specified, defaults to 100.0. | |
| name : str, optional | |
| The user-defined name of this object. | |
| """ | |
| def __init__(self, | |
| fx, | |
| fy, | |
| cx, | |
| cy, | |
| znear=DEFAULT_Z_NEAR, | |
| zfar=DEFAULT_Z_FAR, | |
| name=None): | |
| super(IntrinsicsCamera, self).__init__( | |
| znear=znear, | |
| zfar=zfar, | |
| name=name, | |
| ) | |
| self.fx = fx | |
| self.fy = fy | |
| self.cx = cx | |
| self.cy = cy | |
| def fx(self): | |
| """float : X-axis focal length in meters. | |
| """ | |
| return self._fx | |
| def fx(self, value): | |
| self._fx = float(value) | |
| def fy(self): | |
| """float : Y-axis focal length in meters. | |
| """ | |
| return self._fy | |
| def fy(self, value): | |
| self._fy = float(value) | |
| def cx(self): | |
| """float : X-axis optical center in pixels. | |
| """ | |
| return self._cx | |
| def cx(self, value): | |
| self._cx = float(value) | |
| def cy(self): | |
| """float : Y-axis optical center in pixels. | |
| """ | |
| return self._cy | |
| def cy(self, value): | |
| self._cy = float(value) | |
| def get_projection_matrix(self, width, height): | |
| """Return the OpenGL projection matrix for this camera. | |
| Parameters | |
| ---------- | |
| width : int | |
| Width of the current viewport, in pixels. | |
| height : int | |
| Height of the current viewport, in pixels. | |
| """ | |
| width = float(width) | |
| height = float(height) | |
| cx, cy = self.cx, self.cy | |
| fx, fy = self.fx, self.fy | |
| if sys.platform == 'darwin': | |
| cx = self.cx * 2.0 | |
| cy = self.cy * 2.0 | |
| fx = self.fx * 2.0 | |
| fy = self.fy * 2.0 | |
| P = np.zeros((4,4)) | |
| P[0][0] = 2.0 * fx / width | |
| P[1][1] = 2.0 * fy / height | |
| P[0][2] = 1.0 - 2.0 * cx / width | |
| P[1][2] = 2.0 * cy / height - 1.0 | |
| P[3][2] = -1.0 | |
| n = self.znear | |
| f = self.zfar | |
| if f is None: | |
| P[2][2] = -1.0 | |
| P[2][3] = -2.0 * n | |
| else: | |
| P[2][2] = (f + n) / (n - f) | |
| P[2][3] = (2 * f * n) / (n - f) | |
| return P | |
| __all__ = ['Camera', 'PerspectiveCamera', 'OrthographicCamera', | |
| 'IntrinsicsCamera'] | |