gpu_particle_burst_07.py Full Listing#

gpu_particle_burst_07.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
  9import arcade
 10import arcade.gl
 11
 12SCREEN_WIDTH = 1024
 13SCREEN_HEIGHT = 768
 14SCREEN_TITLE = "GPU Particle Explosion"
 15
 16PARTICLE_COUNT = 300
 17
 18MIN_FADE_TIME = 0.25
 19MAX_FADE_TIME = 1.5
 20
 21
 22@dataclass
 23class Burst:
 24    """ Track for each burst. """
 25    buffer: arcade.gl.Buffer
 26    vao: arcade.gl.Geometry
 27    start_time: float
 28
 29
 30class MyWindow(arcade.Window):
 31    """ Main window"""
 32    def __init__(self):
 33        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 34        self.burst_list = []
 35
 36        # Program to visualize the points
 37        self.program = self.ctx.load_program(
 38            vertex_shader="vertex_shader_v4.glsl",
 39            fragment_shader="fragment_shader.glsl",
 40        )
 41
 42        self.ctx.enable_only(self.ctx.BLEND)
 43
 44    def on_draw(self):
 45        """ Draw everything """
 46        self.clear()
 47
 48        # Set the particle size
 49        self.ctx.point_size = 2 * self.get_pixel_ratio()
 50
 51        # Loop through each burst
 52        for burst in self.burst_list:
 53
 54            # Set the uniform data
 55            self.program['time'] = time.time() - burst.start_time
 56
 57            # Render the burst
 58            burst.vao.render(self.program, mode=self.ctx.POINTS)
 59
 60    def on_update(self, dt):
 61        """ Update game """
 62
 63        # Create a copy of our list, as we can't modify a list while iterating
 64        # it. Then see if any of the items have completely faded out and need
 65        # to be removed.
 66        temp_list = self.burst_list.copy()
 67        for burst in temp_list:
 68            if time.time() - burst.start_time > MAX_FADE_TIME:
 69               self.burst_list.remove(burst)
 70
 71
 72    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int):
 73        """ User clicks mouse """
 74
 75        def _gen_initial_data(initial_x, initial_y):
 76            """ Generate data for each particle """
 77            for i in range(PARTICLE_COUNT):
 78                angle = random.uniform(0, 2 * math.pi)
 79                speed = abs(random.gauss(0, 1)) * .5
 80                dx = math.sin(angle) * speed
 81                dy = math.cos(angle) * speed
 82                red = random.uniform(0.5, 1.0)
 83                green = random.uniform(0, red)
 84                blue = 0
 85                fade_rate = random.uniform(1 / MAX_FADE_TIME, 1 / MIN_FADE_TIME)
 86
 87                yield initial_x
 88                yield initial_y
 89                yield dx
 90                yield dy
 91                yield red
 92                yield green
 93                yield blue
 94                yield fade_rate
 95
 96        # Recalculate the coordinates from pixels to the OpenGL system with
 97        # 0, 0 at the center.
 98        x2 = x / self.width * 2. - 1.
 99        y2 = y / self.height * 2. - 1.
100
101        # Get initial particle data
102        initial_data = _gen_initial_data(x2, y2)
103
104        # Create a buffer with that data
105        buffer = self.ctx.buffer(data=array('f', initial_data))
106
107        # Create a buffer description that says how the buffer data is formatted.
108        buffer_description = arcade.gl.BufferDescription(buffer,
109                                                         '2f 2f 3f f',
110                                                         ['in_pos',
111                                                          'in_vel',
112                                                          'in_color',
113                                                          'in_fade_rate'])
114        # Create our Vertex Attribute Object
115        vao = self.ctx.geometry([buffer_description])
116
117        # Create the Burst object and add it to the list of bursts
118        burst = Burst(buffer=buffer, vao=vao, start_time=time.time())
119        self.burst_list.append(burst)
120
121
122if __name__ == "__main__":
123    window = MyWindow()
124    window.center_window()
125    arcade.run()