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