1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
from __future__ import absolute_import
# Visualization of particles with gravity
# Source: http://enja.org/2010/08/27/adventures-in-opencl-part-2-particles-with-opengl/
import pyopencl as cl # OpenCL - GPU computing interface
mf = cl.mem_flags
from pyopencl.tools import get_gl_sharing_context_properties
from OpenGL.GL import * # OpenGL - GPU rendering interface
from OpenGL.GLU import * # OpenGL tools (mipmaps, NURBS, perspective projection, shapes)
from OpenGL.GLUT import * # OpenGL tool to make a visualization window
from OpenGL.arrays import vbo
import numpy # Number tools
import sys # System tools (path, modules, maxint)
width = 800
height = 600
num_particles = 100000
time_step = .005
mouse_down = False
mouse_old = {'x': 0., 'y': 0.}
rotate = {'x': 0., 'y': 0., 'z': 0.}
translate = {'x': 0., 'y': 0., 'z': 0.}
initial_translate = {'x': 0., 'y': 0., 'z': -2.5}
def glut_window():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(width, height)
glutInitWindowPosition(0, 0)
window = glutCreateWindow("Particle Simulation")
glutDisplayFunc(on_display) # Called by GLUT every frame
glutKeyboardFunc(on_key)
glutMouseFunc(on_click)
glutMotionFunc(on_mouse_move)
glutTimerFunc(10, on_timer, 10) # Call draw every 30 ms
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60., width / float(height), .1, 1000.)
return(window)
def initial_buffers(num_particles):
np_position = numpy.ndarray((num_particles, 4), dtype=numpy.float32)
np_color = numpy.ndarray((num_particles, 4), dtype=numpy.float32)
np_velocity = numpy.ndarray((num_particles, 4), dtype=numpy.float32)
np_position[:,0] = numpy.sin(numpy.arange(0., num_particles) * 2.001 * numpy.pi / num_particles)
np_position[:,0] *= numpy.random.random_sample((num_particles,)) / 3. + .2
np_position[:,1] = numpy.cos(numpy.arange(0., num_particles) * 2.001 * numpy.pi / num_particles)
np_position[:,1] *= numpy.random.random_sample((num_particles,)) / 3. + .2
np_position[:,2] = 0.
np_position[:,3] = 1.
np_color[:,:] = [1.,1.,1.,1.] # White particles
np_velocity[:,0] = np_position[:,0] * 2.
np_velocity[:,1] = np_position[:,1] * 2.
np_velocity[:,2] = 3.
np_velocity[:,3] = numpy.random.random_sample((num_particles, ))
gl_position = vbo.VBO(data=np_position, usage=GL_DYNAMIC_DRAW, target=GL_ARRAY_BUFFER)
gl_position.bind()
gl_color = vbo.VBO(data=np_color, usage=GL_DYNAMIC_DRAW, target=GL_ARRAY_BUFFER)
gl_color.bind()
return (np_position, np_velocity, gl_position, gl_color)
def on_timer(t):
glutTimerFunc(t, on_timer, t)
glutPostRedisplay()
def on_key(*args):
if args[0] == '\033' or args[0] == 'q':
sys.exit()
def on_click(button, state, x, y):
mouse_old['x'] = x
mouse_old['y'] = y
def on_mouse_move(x, y):
rotate['x'] += (y - mouse_old['y']) * .2
rotate['y'] += (x - mouse_old['x']) * .2
mouse_old['x'] = x
mouse_old['y'] = y
def on_display():
"""Render the particles"""
# Update or particle positions by calling the OpenCL kernel
cl.enqueue_acquire_gl_objects(queue, [cl_gl_position, cl_gl_color])
kernelargs = (cl_gl_position, cl_gl_color, cl_velocity, cl_start_position, cl_start_velocity, numpy.float32(time_step))
program.particle_fountain(queue, (num_particles,), None, *(kernelargs))
cl.enqueue_release_gl_objects(queue, [cl_gl_position, cl_gl_color])
queue.finish()
glFlush()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# Handle mouse transformations
glTranslatef(initial_translate['x'], initial_translate['y'], initial_translate['z'])
glRotatef(rotate['x'], 1, 0, 0)
glRotatef(rotate['y'], 0, 1, 0) #we switched around the axis so make this rotate_z
glTranslatef(translate['x'], translate['y'], translate['z'])
# Render the particles
glEnable(GL_POINT_SMOOTH)
glPointSize(2)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
# Set up the VBOs
gl_color.bind()
glColorPointer(4, GL_FLOAT, 0, gl_color)
gl_position.bind()
glVertexPointer(4, GL_FLOAT, 0, gl_position)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
# Draw the VBOs
glDrawArrays(GL_POINTS, 0, num_particles)
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
glDisable(GL_BLEND)
glutSwapBuffers()
window = glut_window()
(np_position, np_velocity, gl_position, gl_color) = initial_buffers(num_particles)
platform = cl.get_platforms()[0]
context = cl.Context(properties=[(cl.context_properties.PLATFORM, platform)] + get_gl_sharing_context_properties())
queue = cl.CommandQueue(context)
cl_velocity = cl.Buffer(context, mf.COPY_HOST_PTR, hostbuf=np_velocity)
cl_start_position = cl.Buffer(context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np_position)
cl_start_velocity = cl.Buffer(context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=np_velocity)
cl_gl_position = cl.GLBuffer(context, mf.READ_WRITE, int(gl_position.buffers[0]))
cl_gl_color = cl.GLBuffer(context, mf.READ_WRITE, int(gl_color.buffers[0]))
kernel = """__kernel void particle_fountain(__global float4* position,
__global float4* color,
__global float4* velocity,
__global float4* start_position,
__global float4* start_velocity,
float time_step)
{
unsigned int i = get_global_id(0);
float4 p = position[i];
float4 v = velocity[i];
float life = velocity[i].w;
life -= time_step;
if (life <= 0.f)
{
p = start_position[i];
v = start_velocity[i];
life = 1.0f;
}
v.z -= 9.8f*time_step;
p.x += v.x*time_step;
p.y += v.y*time_step;
p.z += v.z*time_step;
v.w = life;
position[i] = p;
velocity[i] = v;
color[i].w = life; /* Fade points as life decreases */
}"""
program = cl.Program(context, kernel).build()
glutMainLoop()
|