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@dataclass
 22class Burst:
 23    """ Track for each burst. """
 24    buffer: arcade.gl.Buffer
 25    vao: arcade.gl.Geometry
 26    start_time: float
 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_v4.glsl",
 37            fragment_shader="fragment_shader.glsl",
 38        )
 39
 40        self.ctx.enable_only(self.ctx.BLEND)
 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 game """
 60
 61        # Create a copy of our list, as we can't modify a list while iterating
 62        # it. Then see if any of the items have completely faded out and need
 63        # to be removed.
 64        temp_list = self.burst_list.copy()
 65        for burst in temp_list:
 66            if time.time() - burst.start_time > MAX_FADE_TIME:
 67               self.burst_list.remove(burst)
 68
 69
 70    def on_mouse_press(self, x: float, y: float, button: int, modifiers: int):
 71        """ User clicks mouse """
 72
 73        def _gen_initial_data(initial_x, initial_y):
 74            """ Generate data for each particle """
 75            for i in range(PARTICLE_COUNT):
 76                angle = random.uniform(0, 2 * math.pi)
 77                speed = abs(random.gauss(0, 1)) * .5
 78                dx = math.sin(angle) * speed
 79                dy = math.cos(angle) * speed
 80                red = random.uniform(0.5, 1.0)
 81                green = random.uniform(0, red)
 82                blue = 0
 83                fade_rate = random.uniform(1 / MAX_FADE_TIME, 1 / MIN_FADE_TIME)
 84
 85                yield initial_x
 86                yield initial_y
 87                yield dx
 88                yield dy
 89                yield red
 90                yield green
 91                yield blue
 92                yield fade_rate
 93
 94        # Recalculate the coordinates from pixels to the OpenGL system with
 95        # 0, 0 at the center.
 96        x2 = x / self.width * 2. - 1.
 97        y2 = y / self.height * 2. - 1.
 98
 99        # Get initial particle data
100        initial_data = _gen_initial_data(x2, y2)
101
102        # Create a buffer with that data
103        buffer = self.ctx.buffer(data=array('f', initial_data))
104
105        # Create a buffer description that says how the buffer data is formatted.
106        buffer_description = arcade.gl.BufferDescription(buffer,
107                                                         '2f 2f 3f f',
108                                                         ['in_pos',
109                                                          'in_vel',
110                                                          'in_color',
111                                                          'in_fade_rate'])
112        # Create our Vertex Attribute Object
113        vao = self.ctx.geometry([buffer_description])
114
115        # Create the Burst object and add it to the list of bursts
116        burst = Burst(buffer=buffer, vao=vao, start_time=time.time())
117        self.burst_list.append(burst)
118
119
120if __name__ == "__main__":
121    window = MyWindow()
122    window.center_window()
123    arcade.run()