Hello,
This example should help you get the result you want. Note that we’re rendering the sphere with perspective here.
from psychopy import event, core
import numpy as np
import pyglet.gl as GL
import psychopy.visual as visual
import psychopy.tools.mathtools as mt
import psychopy.tools.gltools as gltools
win = visual.Window(monitor='testMonitor', size=(800, 800),
color='Black', allowGUI=True, fullscr=False)
# configure how the spehre is drawn
NDOTS = 500
SPHERE_SCALE = 0.25
SPHERE_POS = (0, 0, -1.5) # 1.5 meters away from screen, -Z is forward in OpenGL
# note that the distance from the viewer to SPHERE_POS is abs(viewdist + SPHERE_POS[2])
length = mt.normalize(np.random.uniform(-1, 1, size=(NDOTS, 3))) * SPHERE_SCALE
# Create a buffer in GPU memory with vertex data, it must be set as
# GL_DYNAMIC_DRAW since we are updating it's contents often.
vertBuffer = gltools.createVBO(length, usage=GL.GL_DYNAMIC_DRAW)
# create a vertex array object
vertVAO = gltools.createVAO({0: vertBuffer})
# Here is how you can update dots. The buffer is in GPU memory, but needs to be
# accessed by the CPU. Use `mapBuffer` to get a pointer to the buffer. You can
# then treat the buffer like a regular numpy array. Be super careful though,
# you need to unmap the buffer right after writing new values to it. The data
# has to have the same size as the original data (same number of dots).
# ptrVerts = gltools.mapBuffer(vertBuffer)
# ptrVerts[:, :] = mt.normalize(np.random.uniform(-1, 1, size=(NDOTS, 3))) * SPHERE_SCALE
# gltools.unmapBuffer(vertBuffer) # ABSOLUTELY CALL THIS AFTER SETTING VALUES!
# store rotation angle
rotationDir = 1 # make 1 or -1 to switch directions
rotationAngle = 0.0
while 1:
# set a perspective view, needs a monitor configuration with viewing
# distance defined
win.setPerspectiveView()
# enable 3D drawing
win.draw3d = True
GL.glPushMatrix()
GL.glColor3f(1, 1, 1) # set dot color
GL.glPointSize(6.0) # size in pixels
GL.glTranslatef(*SPHERE_POS)
GL.glRotatef(rotationAngle * rotationDir, 0, 1, 0) # angle, ax, ay, az
gltools.drawVAO(vertVAO, GL.GL_POINTS) # draw the VAO as points
GL.glPopMatrix()
win.draw3d = False
rotationAngle += 0.1 # rotation in degrees per frame
# reset if angle greater than 1 revolution
if rotationAngle > 360.0 or rotationAngle < -360.0:
rotationAngle = 0.0
win.flip()
if event.getKeys():
break
core.quit()
If you want to draw with no perspective, do the following. Note the the scale of the stimulus will be in normalized screen units (eg. 0.5 will make the sphere have a radius of which is equal to half the width of the screen). There is no translation anymore.
from psychopy import event, core
import numpy as np
import pyglet.gl as GL
import psychopy.visual as visual
import psychopy.tools.mathtools as mt
import psychopy.tools.gltools as gltools
win = visual.Window(monitor='testMonitor', size=(800, 600),
color='Black', allowGUI=True, fullscr=False)
# configure how the spehre is drawn
NDOTS = 1000
SPHERE_SCALE = 0.25 # in screen units
length = mt.normalize(np.random.uniform(-1, 1, size=(NDOTS, 3))) * SPHERE_SCALE
# Create a buffer in GPU memory with vertex data, it must be set as
# GL_DYNAMIC_DRAW since we are updating it's contents often.
vertBuffer = gltools.createVBO(length, usage=GL.GL_DYNAMIC_DRAW)
# create a vertex array object
vertVAO = gltools.createVAO({0: vertBuffer})
# Here is how you can update dots. The buffer is in GPU memory, but needs to be
# accessed by the CPU. Use `mapBuffer` to get a pointer to the buffer. You can
# then treat the buffer like an regular numpy array. Be super careful though,
# you need to unmap the buffer right after writing new values to it. The data
# has to have the same size as the original data (same number of dots).
# ptrVerts = gltools.mapBuffer(vertBuffer)
# ptrVerts[:, :] = mt.normalize(np.random.uniform(-1, 1, size=(NDOTS, 3))) * SPHERE_SCALE
# gltools.unmapBuffer(vertBuffer) # ABSOLUTELY CALL THIS AFTER SETTING VALUES!
# store rotation angle
rotationDir = 1 # make 1 or -1 to switch directions
rotationAngle = 0.0
while 1:
# set a perspective view, needs a monitor configuration with viewing
# distance defined
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
aspect = win.size[0] / win.size[1]
GL.glOrtho(-1 * aspect, 1 * aspect, -1, 1, -1, 1)
# clear the depth buffer
win.depthMask = True
GL.glClear(GL.GL_DEPTH_BUFFER_BIT)
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
# enable 3D drawing
win.draw3d = True
GL.glPushMatrix()
GL.glColor3f(1, 1, 1) # set dot color
GL.glPointSize(6.0) # size in pixels
GL.glRotatef(rotationAngle * rotationDir, 0, 1, 0) # angle, ax, ay, az
gltools.drawVAO(vertVAO, GL.GL_POINTS) # draw the VAO as points
GL.glPopMatrix()
win.draw3d = False
rotationAngle += 0.1 # rotation in degrees per frame
# reset if angle greater than 1 revolution
if rotationAngle > 360.0 or rotationAngle < -360.0:
rotationAngle = 0.0
win.flip()
if event.getKeys():
break
core.quit()