psychopy.tools.viewtools

Tools for working with view projections for 2- and 3-D rendering.

computeFrustum(scrWidth, scrAspect, scrDist) Calculate frustum parameters.
generalizedPerspectiveProjection(…[, …]) Generalized derivation of projection and view matrices based on the physical configuration of the display system.
orthoProjectionMatrix(left, right, bottom, …) Compute an orthographic projection matrix with provided frustum parameters.
perspectiveProjectionMatrix(left, right, …) Compute an perspective projection matrix with provided frustum parameters.
lookAt(eyePos, centerPos, upVec) Create a transformation matrix to orient towards some point.
pointToNdc(wcsPos, viewMatrix, projectionMatrix) Map the position of a point in world space to normalized device coordinates/space.

Function details

psychopy.tools.viewtools.computeFrustum(scrWidth, scrAspect, scrDist, convergeOffset=0.0, eyeOffset=0.0, nearClip=0.01, farClip=100.0)

Calculate frustum parameters. If an eye offset is provided, an asymmetric frustum is returned which can be used for stereoscopic rendering.

Parameters:
  • scrWidth (float) – The display’s width in meters.
  • scrAspect (float) – Aspect ratio of the display (width / height).
  • scrDist (float) – Distance to the screen from the view in meters. Measured from the center of their eyes.
  • convergeOffset (float) – Offset of the convergence plane from the screen. Objects falling on this plane will have zero disparity. For best results, the convergence plane should be set to the same distance as the screen (0.0 by default).
  • eyeOffset (float) – Half the inter-ocular separation (i.e. the horizontal distance between the nose and center of the pupil) in meters. If eyeOffset is 0.0, a symmetric frustum is returned.
  • nearClip (float) – Distance to the near clipping plane in meters from the viewer. Should be at least less than scrDist.
  • farClip (float) – Distance to the far clipping plane from the viewer in meters. Must be >nearClip.
Returns:

Namedtuple with frustum parameters. Can be directly passed to glFrustum (e.g. glFrustum(*f)).

Return type:

Frustum

Notes

The view point must be transformed for objects to appear correctly. Offsets in the X-direction must be applied +/- eyeOffset to account for inter-ocular separation. A transformation in the Z-direction must be applied to account for screen distance. These offsets MUST be applied to the MODELVIEW matrix, not the PROJECTION matrix! Doing so may break lighting calculations.

Examples

Creating a frustum and setting a window’s projection matrix:

scrWidth = 0.5  # screen width in meters
scrAspect = win.size[0] / win.size[1]
scrDist = win.scrDistCM * 100.0  # monitor setting, can be anything
frustum = viewtools.computeFrustum(scrWidth, scrAspect, scrDist)
# convert frustum to projection matrix
win.projectionMatrix = viewtools.perspectiveProjectionMatrix(*frustum)
# set your view matrix to account for the screen distance!!!
win.applyEyeTransform()  # call before drawing

Off-axis frustums for stereo rendering:

# compute view matrix for each eye, these value usually don't change
eyeOffset = (-0.035, 0.035)  # +/- IOD / 2.0
leftProjMatrix = viewtools.perspectiveProjectionMatrix(
    viewtools.computeFrustum(
        scrWidth, scrAspect, scrDist, eyeOffset[0]))
rightProjMatrix = viewtools.computeFrustum(
    viewtools.computeFrustum(
        scrWidth, scrAspect, scrDist, eyeOffset[1]))
# ... after calling 'setBuffer('left')' ...
win.projectionMatrix = leftProjMatrix
# setup your view matrix accordingly, must account for screen distance
# and eye offset
win.applyViewTransform()  # call before drawing
# do the same for 'setBuffer('right')' using the other matrix ...
psychopy.tools.viewtools.generalizedPerspectiveProjection(posBottomLeft, posBottomRight, posTopLeft, eyePos, nearClip=0.01, farClip=100.0)

Generalized derivation of projection and view matrices based on the physical configuration of the display system.

This implementation is based on Robert Kooima’s ‘Generalized Perspective Projection’ (see http://csc.lsu.edu/~kooima/articles/genperspective/) method.

Parameters:
  • posBottomLeft (list of float or ndarray) – Bottom-left 3D coordinate of the screen in meters.
  • posBottomRight (list of float or ndarray) – Bottom-right 3D coordinate of the screen in meters.
  • posTopLeft (list of float or ndarray) – Top-left 3D coordinate of the screen in meters.
  • eyePos (list of float or ndarray) – Coordinate of the eye in meters.
  • nearClip (float) – Near clipping plane distance from viewer in meters.
  • farClip (float) – Far clipping plane distance from viewer in meters.
Returns:

The 4x4 projection and view matrix.

Return type:

tuple

Notes

The resulting projection frustums are off-axis relative to the center of the display. The returned matrices are row-major. Values are floats with 32-bits of precision stored as a contiguous (C-order) array.

psychopy.tools.viewtools.orthoProjectionMatrix(left, right, bottom, top, nearClip, farClip)

Compute an orthographic projection matrix with provided frustum parameters.

Parameters:
  • left (float) – Left clipping plane coordinate.
  • right (float) – Right clipping plane coordinate.
  • bottom (float) – Bottom clipping plane coordinate.
  • top (float) – Top clipping plane coordinate.
  • nearClip (float) – Near clipping plane distance from viewer.
  • farClip (float) – Far clipping plane distance from viewer.
Returns:

4x4 projection matrix

Return type:

ndarray

Notes

The returned matrix is row-major. Values are floats with 32-bits of precision stored as a contiguous (C-order) array.

psychopy.tools.viewtools.perspectiveProjectionMatrix(left, right, bottom, top, nearClip, farClip)

Compute an perspective projection matrix with provided frustum parameters. The frustum can be asymmetric.

Parameters:
  • left (float) – Left clipping plane coordinate.
  • right (float) – Right clipping plane coordinate.
  • bottom (float) – Bottom clipping plane coordinate.
  • top (float) – Top clipping plane coordinate.
  • nearClip (float) – Near clipping plane distance from viewer.
  • farClip (float) – Far clipping plane distance from viewer.
Returns:

4x4 projection matrix

Return type:

ndarray

Notes

The returned matrix is row-major. Values are floats with 32-bits of precision stored as a contiguous (C-order) array.

psychopy.tools.viewtools.lookAt(eyePos, centerPos, upVec)

Create a transformation matrix to orient towards some point. Based on the same algorithm as ‘gluLookAt’. This does not generate a projection matrix, but rather the matrix to transform the observer’s view in the scene.

For more information see: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml

Parameters:
  • eyePos (list of float or ndarray) – Eye position in the scene.
  • centerPos (list of float or ndarray) – Position of the object center in the scene.
  • upVec (list of float or ndarray) – Vector defining the up vector.
Returns:

4x4 view matrix

Return type:

ndarray

Notes

The returned matrix is row-major. Values are floats with 32-bits of precision stored as a contiguous (C-order) array.

psychopy.tools.viewtools.pointToNdc(wcsPos, viewMatrix, projectionMatrix)

Map the position of a point in world space to normalized device coordinates/space.

Parameters:
  • wcsPos (tuple, list or ndarray) – 3x1 position vector(s) (xyz) in world space coordinates
  • viewMatrix (ndarray) – 4x4 view matrix
  • projectionMatrix (ndarray) – 4x4 projection matrix
Returns:

3x1 vector of normalized device coordinates with type ‘float32’

Return type:

ndarray

Notes

The point is not visible, falling outside of the viewing frustum, if the returned coordinates fall outside of -1 and 1 along any dimension.

In the rare instance the point falls directly on the eye in world space where the frustum converges to a point (singularity), the divisor will be zero during perspective division. To avoid this, the divisor is ‘bumped’ to machine epsilon for the ‘float32’ type.

This function assumes the display area is rectilinear. Any distortion or warping applied in normalized device or viewport space is not considered.

Examples

Determine if a point is visible::
point = (0.0, 0.0, 10.0) # behind the observer ndc = pointToNdc(point, win.viewMatrix, win.projectionMatrix) isVisible = not np.any((ndc > 1.0) | (ndc < -1.0))
Convert NDC to viewport (or pixel) coordinates::
scrRes = (1920, 1200) point = (0.0, 0.0, -5.0) # forward -5.0 from eye x, y, z = pointToNdc(point, win.viewMatrix, win.projectionMatrix) pixelX = ((x + 1.0) / 2.0) * scrRes[0]) pixelY = ((y + 1.0) / 2.0) * scrRes[1]) # object at point will appear at (pixelX, pixelY)

Back to top