psychopy.tools.viewtools
¶Tools for working with view projections for 2 and 3D 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, out, dtype]) 
Create a transformation matrix to orient a view towards some point. 
pointToNdc (wcsPos, viewMatrix, projectionMatrix) 
Map the position of a point in world space to normalized device coordinates/space. 
psychopy.tools.viewtools.
computeFrustum
(scrWidth, scrAspect, scrDist, convergeOffset=0.0, eyeOffset=0.0, nearClip=0.01, farClip=100.0)[source]¶Calculate frustum parameters. If an eye offset is provided, an asymmetric frustum is returned which can be used for stereoscopic rendering.
Parameters: 


Returns:  Namedtuple with frustum parameters. Can be directly passed to glFrustum (e.g. glFrustum(*f)). 
Return type:  Frustum 
Notes
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)
Accessing frustum parameters:
left, right, bottom, top, nearVal, farVal = frustum
# ... or ...
left = frustum.left
Offaxis frustums for stereo rendering:
# compute view matrix for each eye, these value usually don't change
eyeOffset = (0.035, 0.035) # +/ IOD / 2.0
scrDist = 0.50 # 50cm
scrWidth = 0.53 # 53cm
scrAspect = 1.778
leftFrustum = viewtools.computeFrustum(scrWidth, scrAspect, scrDist, eyeOffset[0])
rightFrustum = viewtools.computeFrustum(scrWidth, scrAspect, scrDist, eyeOffset[1])
# make sure your view matrix accounts for the screen distance and eye offsets!
Using computed view frustums with a window:
win.projectionMatrix = viewtools.perspectiveProjectionMatrix(*frustum)
# generate a view matrix looking ahead with correct viewing distance,
# origin is at the center of the screen. Assumes eye is centered with
# the screen.
eyePos = [0.0, 0.0, scrDist]
screenPos = [0.0, 0.0, 0.0] # look at screen center
eyeUp = [0.0, 1.0, 0.0]
win.viewMatrix = viewtools.lookAt(eyePos, screenPos, eyeUp)
win.applyViewTransform() # call before drawing
psychopy.tools.viewtools.
generalizedPerspectiveProjection
(posBottomLeft, posBottomRight, posTopLeft, eyePos, nearClip=0.01, farClip=100.0, dtype=None)[source]¶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’ method [1].
Parameters: 


Returns:  The 4x4 projection and view matrix. 
Return type: 
See also
computeFrustum()
Notes
References
[1]  Kooima, R. (2009). Generalized perspective projection. J. Sch. Electron. Eng. Comput. Sci. 
Examples
Computing a projection and view matrices for a window:
projMatrix, viewMatrix = viewtools.generalizedPerspectiveProjection(
posBottomLeft, posBottomRight, posTopLeft, eyePos)
# set the window matrices
win.projectionMatrix = projMatrix
win.viewMatrix = viewMatrix
# before rendering
win.applyEyeTransform()
Stereopair rendering example from Kooima (2009):
# configuration of screen and eyes
posBottomLeft = [1.5, 0.75, 18.0]
posBottomRight = [1.5, 0.75, 18.0]
posTopLeft = [1.5, 0.75, 18.0]
posLeftEye = [1.25, 0.0, 0.0]
posRightEye = [1.25, 0.0, 0.0]
# create projection and view matrices
leftProjMatrix, leftViewMatrix = generalizedPerspectiveProjection(
posBottomLeft, posBottomRight, posTopLeft, posLeftEye)
rightProjMatrix, rightViewMatrix = generalizedPerspectiveProjection(
posBottomLeft, posBottomRight, posTopLeft, posRightEye)
psychopy.tools.viewtools.
orthoProjectionMatrix
(left, right, bottom, top, nearClip, farClip, out=None, dtype=None)[source]¶Compute an orthographic projection matrix with provided frustum parameters.
Parameters: 


Returns:  4x4 projection matrix 
Return type:  ndarray 
See also
perspectiveProjectionMatrix()
Notes
psychopy.tools.viewtools.
perspectiveProjectionMatrix
(left, right, bottom, top, nearClip, farClip, out=None, dtype=None)[source]¶Compute an perspective projection matrix with provided frustum parameters. The frustum can be asymmetric.
Parameters: 


Returns:  4x4 projection matrix 
Return type:  ndarray 
See also
orthoProjectionMatrix()
Notes
psychopy.tools.viewtools.
lookAt
(eyePos, centerPos, upVec=(0.0, 1.0, 0.0), out=None, dtype=None)[source]¶Create a transformation matrix to orient a view 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/OpenGLRefpages/gl2.1/xhtml/gluLookAt.xml
Parameters: 


Returns:  4x4 view matrix 
Return type:  ndarray 
Notes
psychopy.tools.viewtools.
pointToNdc
(wcsPos, viewMatrix, projectionMatrix, out=None, dtype=None)[source]¶Map the position of a point in world space to normalized device coordinates/space.
Parameters: 


Returns:  3x1 vector of normalized device coordinates with type ‘float32’ 
Return type:  ndarray 
Notes
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)