Bonus - Procedural / particle animation¶
Objectives:
Understand how to reload dynamically any attribute tables on the fly
Pre-requisites:
Practical 2 - Meshes and modeling must be finished, but there are no other dependencies than using the framework in
core.py
Principle¶
Any attribute can be updated from the python code to the GPU during the rendering loop, in the draw call of any object.
We provide an example in the code below, with
the PythonAnimation
class, which shows how this may be done with the
simple case of four particles given a purely sinusoidal trajectory.
class PointAnimation(Mesh):
""" Simple animated particle set """
def __init__(self, shader):
# render points with wide size to be seen
GL.glPointSize(10)
# instantiate and store 4 points to animate
self.coords = ((-1, -1, -5), (1, -1, -5), (1, 1, -5), (-1, 1, -5))
# send as position attribute to GPU, set uniform variable global_color.
# GL_STREAM_DRAW tells OpenGL that attributes of this object
# will change on a per-frame basis (as opposed to GL_STATIC_DRAW)
super().__init__(shader, attributes=dict(position=self.coords),
usage=GL.GL_STREAM_DRAW, global_color=(0.5, 0.5, 0.8))
def draw(self, primitives=GL.GL_POINTS, attributes=None, **uniforms):
# compute a sinusoidal x-coord displacement, different for each point.
# this could be any per-point function: build your own particle system!
dp = [[sin(i + glfw.get_time()), 0, 0] for i in range(len(self.coords))]
# update position buffer on CPU, send to GPU attribute to draw with it
coords = np.array(self.coords, 'f') + np.array(dp, 'f')
super().draw(primitives, attributes=dict(position=coords), **uniforms)
You can update any attribute buffer you had initialized in the constructor, but you don’t have to update all of them, you may choose to update only a subset.
You may extend this code in any direction of your choice for the project.
Code base¶
New file:
Previously used files from practical 2:
color.vert
color.frag
core.py
transform.py