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
  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_v3.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                red = random.uniform(0.5, 1.0)
 72                green = random.uniform(0, red)
 73                blue = 0
 74                yield initial_x
 75                yield initial_y
 76                yield dx
 77                yield dy
 78                yield red
 79                yield green
 80                yield blue
 81
 82        # Recalculate the coordinates from pixels to the OpenGL system with
 83        # 0, 0 at the center.
 84        x2 = x / self.width * 2. - 1.
 85        y2 = y / self.height * 2. - 1.
 86
 87        # Get initial particle data
 88        initial_data = _gen_initial_data(x2, y2)
 89
 90        # Create a buffer with that data
 91        buffer = self.ctx.buffer(data=array('f', initial_data))
 92
 93        # Create a buffer description that says how the buffer data is formatted.
 94        buffer_description = arcade.gl.BufferDescription(buffer,
 95                                                         '2f 2f 3f',
 96                                                         ['in_pos', 'in_vel', 'in_color'])
 97        # Create our Vertex Attribute Object
 98        vao = self.ctx.geometry([buffer_description])
 99
100        # Create the Burst object and add it to the list of bursts
101        burst = Burst(buffer=buffer, vao=vao, start_time=time.time())
102        self.burst_list.append(burst)
103
104
105if __name__ == "__main__":
106    window = MyWindow()
107    window.center_window()
108    arcade.run()