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