Vectorized Particle System and Geometry Shaders
Source available for download below:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL import GL as gl
import random
import time
import numpy
import math
#These three defines exist in OpenGL.GL, but does not correspond to those used here
GL_GEOMETRY_SHADER_EXT = 0x8DD9
GL_GEOMETRY_INPUT_TYPE_EXT = 0x8DDB
GL_GEOMETRY_OUTPUT_TYPE_EXT = 0x8DDC
GL_GEOMETRY_VERTICES_OUT_EXT = 0x8DDA
# 1:
# Define the missing glProgramParameteri method
_glProgramParameteri = None
def glProgramParameteri( program, pname, value ):
global _glProgramParameteri
if not _glProgramParameteri:
import ctypes
# Open the opengl32.dll
gldll = ctypes.windll.opengl32
# define a function pointer prototype of *(GLuint program, GLenum pname, GLint value)
prototype = ctypes.WINFUNCTYPE( ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.c_int )
# Get the win gl func adress
fptr = gldll.wglGetProcAddress( 'glProgramParameteriEXT' )
if fptr==0:
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
raise Exception( "wglGetProcAddress('glProgramParameteriEXT') returned a zero adress, which will result in a nullpointer error if used.")
_glProgramParameteri = prototype( fptr )
_glProgramParameteri( program, pname, value )
# 2:
# Define the missing glCreateShaderObject method
_glCreateShaderObject = None
def glCreateShaderObject( shadertype ):
global _glCreateShaderObject
if not _glCreateShaderObject:
import ctypes
# Open the opengl32.dll
gldll = ctypes.windll.opengl32
# define a function pointer prototype of *(GLuint program, GLenum pname, GLint value)
prototype = ctypes.WINFUNCTYPE( ctypes.c_int, ctypes.c_uint )
# Get the win gl func adress
fptr = gldll.wglGetProcAddress( 'glCreateShaderObjectARB' )
if fptr==0:
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
raise Exception( "wglGetProcAddress('glCreateShaderObjectARB') returned a zero adress, which will result in a nullpointer error if used.")
_glCreateShaderObject = prototype( fptr )
return _glCreateShaderObject( shadertype )
vert = '''
void main(){
gl_FrontColor = gl_Color;
gl_Position = ftransform();
}
'''
geom = '''#version 120
#extension GL_EXT_geometry_shader4 : enable
const float radius = 0.5;
varying out vec2 coord;
void main()
{
gl_FrontColor = gl_FrontColorIn[0];
coord = vec2( -1,-1 );
gl_Position = (gl_PositionIn[0] + gl_ProjectionMatrix * vec4(-radius,-radius,0,0) );
EmitVertex();
coord = vec2( -1,1 );
gl_Position = (gl_PositionIn[0] + gl_ProjectionMatrix * vec4(-radius,radius, 0,0) );
EmitVertex();
coord = vec2( 1,-1 );
gl_Position = (gl_PositionIn[0] + gl_ProjectionMatrix * vec4( radius,-radius, 0,0) );
EmitVertex();
coord = vec2( 1,1 );
gl_Position = (gl_PositionIn[0] + gl_ProjectionMatrix * vec4( radius,radius, 0,0) );
EmitVertex();
EndPrimitive();
}
'''
frag = '''
varying in vec2 coord;
void main(){
vec4 color = gl_Color;
color.a = 1.0-length( coord );
if (color.a<0.0) discard;
// A VERY FAKE "lighting" model
float d = dot( normalize(vec3(coord,1.0)), vec3( 0.19, 0.19, 0.96225 ) );
color.rgb *= d*d;
// end "lighting"
gl_FragColor = color;
}
'''
theta = 0.0
delta = 0.0
TIMEOUTFACTOR = 5.0
def my_idle( ):
global theta
global delta
t = time.clock()
passed = t-delta
theta += passed
delta = t
dirvector = numpy.array( [ -1-(math.sin( theta/2.0 )), -1-(math.cos(theta/2.0)), 1.0 ] )
dirvector *= (1.0 / math.sqrt( (dirvector**2).sum() ) )
global POINTS
global VEL
global TIMES
#Add "gravity" to all the velocities
VEL[:,2] -= passed * 9.81 * 5
#Increment positions according to velocities
POINTS += passed*VEL
pbelow_zero = POINTS[:,2] < 0.0
# "drag" all points below zero (in z) up again
POINTS[pbelow_zero] *= [1,1,0]
# Change the z velocity for all "collisions" with the zero z plane
VEL[ pbelow_zero ] *= [1,1,-1.0]
# add passed seconds to all points timeout
TIMES += passed
timeouts = TIMES > TIMEOUTFACTOR
TIMES[timeouts] = numpy.random.random( timeouts.sum() ) * 0.1 * TIMEOUTFACTOR
VEL[timeouts] = dirvector + 0.5*numpy.random.random( timeouts.sum() * 3 ).reshape( (-1,3) )
VEL[timeouts] *= 50.0
POINTS[timeouts] = [0.0,0.0,0.0]
glutPostRedisplay()
shader_program = None
def define_shader():
global shader_program
shader_program = gl.glCreateProgram()
glProgramParameteri(shader_program, GL_GEOMETRY_INPUT_TYPE_EXT, gl.GL_POINTS )
glProgramParameteri(shader_program, GL_GEOMETRY_OUTPUT_TYPE_EXT, gl.GL_TRIANGLE_STRIP )
glProgramParameteri(shader_program, GL_GEOMETRY_VERTICES_OUT_EXT, 4 )
vobj = glCreateShaderObject( GL_VERTEX_SHADER )
glShaderSource( vobj, vert )
glCompileShader( vobj )
print glGetShaderInfoLog(vobj)
glAttachShader( shader_program, vobj )
gobj = glCreateShaderObject( GL_GEOMETRY_SHADER_EXT )
glShaderSource( gobj, geom)
glCompileShader( gobj )
print glGetShaderInfoLog(gobj)
glAttachShader( shader_program, gobj )
fobj = glCreateShaderObject( GL_FRAGMENT_SHADER )
glShaderSource( fobj, frag)
glCompileShader( fobj )
print glGetShaderInfoLog(fobj)
glAttachShader( shader_program, fobj )
glLinkProgram( shader_program )
print glGetProgramInfoLog(shader_program)
def reshape( width, height ):
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, width / float(height), 1, 1000 );
glMatrixMode(GL_MODELVIEW);
POINTS = None
COLORS = None
VEL = None
TIMES = None
def display( ):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
glLoadIdentity()
gluLookAt( 60.0,60.0,25.0,
0.0,0.0,0.0,
0.0,0.0,1.0 )
#glRotate( theta*10.0, 0.0,0.0,1.0 )
glTranslatef( 25.0,25.0,0 )
#glEnable( GL_BLEND )
glBlendFunc( GL_SRC_ALPHA, GL_ONE )
glUseProgram( shader_program )
glEnableClientState( GL_COLOR_ARRAY )
glEnableClientState( GL_VERTEX_ARRAY )
glColorPointer( 3,GL_FLOAT,0,COLORS )
glVertexPointer(3,GL_FLOAT,0,POINTS )
glDrawArrays( 0,0, len( POINTS ) )
glutSwapBuffers()
def init():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE )
glutInitWindowSize(1280, 720)
# Open a window
glutCreateWindow("Glut test window")
glutReshapeFunc( reshape )
glutDisplayFunc( display )
glutIdleFunc( my_idle )
glEnable( GL_DEPTH_TEST )
glClearColor( 1,1,1,0 )
define_shader()
# 100k Balls
count = 100000
global POINTS
global COLORS
global VEL
global TIMES
COLORS =numpy.random.random( count*3 ).reshape( (-1,3) )
POINTS = 100000*numpy.ones( count*3 ).reshape( (-1,3) )
VEL = numpy.zeros( count*3 ).reshape( (-1,3) )
TIMES = numpy.random.random( count ) * TIMEOUTFACTOR
glutMainLoop();
init()