gpu_particle_burst_07.py Full Listing#
gpu_particle_burst_07.py#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | """ Example showing how to create particle explosions via the GPU. """ import random import time import math from array import array from dataclasses import dataclass import arcade import arcade.gl SCREEN_WIDTH = 1024 SCREEN_HEIGHT = 768 SCREEN_TITLE = "GPU Particle Explosion" PARTICLE_COUNT = 300 MIN_FADE_TIME = 0.25 MAX_FADE_TIME = 1.5 @dataclass class Burst: """ Track for each burst. """ buffer: arcade.gl.Buffer vao: arcade.gl.Geometry start_time: float class MyWindow(arcade.Window): """ Main window""" def __init__(self): super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) self.burst_list = [] # Program to visualize the points self.program = self.ctx.load_program( vertex_shader="vertex_shader_v4.glsl", fragment_shader="fragment_shader.glsl", ) self.ctx.enable_only(self.ctx.BLEND) def on_draw(self): """ Draw everything """ self.clear() # Set the particle size self.ctx.point_size = 2 * self.get_pixel_ratio() # Loop through each burst for burst in self.burst_list: # Set the uniform data self.program['time'] = time.time() - burst.start_time # Render the burst burst.vao.render(self.program, mode=self.ctx.POINTS) def on_update(self, dt): """ Update game """ # Create a copy of our list, as we can't modify a list while iterating # it. Then see if any of the items have completely faded out and need # to be removed. temp_list = self.burst_list.copy() for burst in temp_list: if time.time() - burst.start_time > MAX_FADE_TIME: self.burst_list.remove(burst) def on_mouse_press(self, x: float, y: float, button: int, modifiers: int): """ User clicks mouse """ def _gen_initial_data(initial_x, initial_y): """ Generate data for each particle """ for i in range(PARTICLE_COUNT): angle = random.uniform(0, 2 * math.pi) speed = abs(random.gauss(0, 1)) * .5 dx = math.sin(angle) * speed dy = math.cos(angle) * speed red = random.uniform(0.5, 1.0) green = random.uniform(0, red) blue = 0 fade_rate = random.uniform(1 / MAX_FADE_TIME, 1 / MIN_FADE_TIME) yield initial_x yield initial_y yield dx yield dy yield red yield green yield blue yield fade_rate # Recalculate the coordinates from pixels to the OpenGL system with # 0, 0 at the center. x2 = x / self.width * 2. - 1. y2 = y / self.height * 2. - 1. # Get initial particle data initial_data = _gen_initial_data(x2, y2) # Create a buffer with that data buffer = self.ctx.buffer(data=array('f', initial_data)) # Create a buffer description that says how the buffer data is formatted. buffer_description = arcade.gl.BufferDescription(buffer, '2f 2f 3f f', ['in_pos', 'in_vel', 'in_color', 'in_fade_rate']) # Create our Vertex Attribute Object vao = self.ctx.geometry([buffer_description]) # Create the Burst object and add it to the list of bursts burst = Burst(buffer=buffer, vao=vao, start_time=time.time()) self.burst_list.append(burst) if __name__ == "__main__": window = MyWindow() window.center_window() arcade.run() |