gpu_particle_burst_06.py Full Listing#

gpu_particle_burst_06.py#
  1"""
  2Example showing how to create particle explosions via the GPU.
  3"""
  4import random
  5import time
  6import math
  7from array import array
  8from dataclasses import dataclass
  9
 10import arcade
 11import arcade.gl
 12
 13SCREEN_WIDTH = 1024
 14SCREEN_HEIGHT = 768
 15SCREEN_TITLE = "GPU Particle Explosion"
 16
 17PARTICLE_COUNT = 300
 18
 19
 20@dataclass
 21class Burst:
 22    """ Track for each burst. """
 23    buffer: arcade.gl.Buffer
 24    vao: arcade.gl.Geometry
 25    start_time: float
 26
 27
 28class MyWindow(arcade.Window):
 29    """ Main window"""
 30    def __init__(self):
 31        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 32        self.burst_list = []
 33
 34        # Program to visualize the points
 35        self.program = self.ctx.load_program(
 36            vertex_shader="vertex_shader_v3.glsl",
 37            fragment_shader="fragment_shader.glsl",
 38        )
 39
 40        self.ctx.enable_only()
 41
 42    def on_draw(self):
 43        """ Draw everything """
 44        self.clear()
 45
 46        # Set the particle size
 47        self.ctx.point_size = 2 * self.get_pixel_ratio()
 48
 49        # Loop through each burst
 50        for burst in self.burst_list:
 51
 52            # Set the uniform data
 53            self.program['time'] = time.time() - burst.start_time
 54
 55            # Render the burst
 56            burst.vao.render(self.program, mode=self.ctx.POINTS)
 57
 58    def on_update(self, dt):
 59        """ Update everything """
 60        pass
 61
 62    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int):
 63        """ User clicks mouse """
 64
 65        def _gen_initial_data(initial_x, initial_y):
 66            """ Generate data for each particle """
 67            for i in range(PARTICLE_COUNT):
 68                angle = random.uniform(0, 2 * math.pi)
 69                speed = abs(random.gauss(0, 1)) * .5
 70                dx = math.sin(angle) * speed
 71                dy = math.cos(angle) * speed
 72                red = random.uniform(0.5, 1.0)
 73                green = random.uniform(0, red)
 74                blue = 0
 75                yield initial_x
 76                yield initial_y
 77                yield dx
 78                yield dy
 79                yield red
 80                yield green
 81                yield blue
 82
 83        # Recalculate the coordinates from pixels to the OpenGL system with
 84        # 0, 0 at the center.
 85        x2 = x / self.width * 2. - 1.
 86        y2 = y / self.height * 2. - 1.
 87
 88        # Get initial particle data
 89        initial_data = _gen_initial_data(x2, y2)
 90
 91        # Create a buffer with that data
 92        buffer = self.ctx.buffer(data=array('f', initial_data))
 93
 94        # Create a buffer description specifying the buffer's data format
 95        buffer_description = arcade.gl.BufferDescription(
 96            buffer,
 97            '2f 2f 3f',
 98            ['in_pos', 'in_vel', 'in_color'])
 99
100        # Create our Vertex Attribute Object
101        vao = self.ctx.geometry([buffer_description])
102
103        # Create the Burst object and add it to the list of bursts
104        burst = Burst(buffer=buffer, vao=vao, start_time=time.time())
105        self.burst_list.append(burst)
106
107
108if __name__ == "__main__":
109    window = MyWindow()
110    window.center_window()
111    arcade.run()