gpu_particle_burst_05.py Full Listing#

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