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
|
from pathlib import Path
import random
import numpy
from pyrr import matrix44
import moderngl
import moderngl_window
from moderngl_window.opengl.vao import VAO
class Boids(moderngl_window.WindowConfig):
"""
An attempt to make something boid-list with GL3.3.
Not currently working as intended, but still creates
and interesting result.
For this to properly work we need to split the calculations
into several passes.
We are doing this the O(n^2) way with the gpu using transform feedback.
To make the data avaialble to the vertex shader (looping through it)
we copy the vertex buffer every frame to a texture.
A better way in the future is to use compute shader.
"""
title = "Boids"
resource_dir = (Path(__file__) / '../../resources').absolute()
aspect_ratio = 3440 / 1440
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
MAX_TEX_WIDTH = 8192
N = MAX_TEX_WIDTH * 1
def gen_initial_data(n, x_area=2.0, y_area=2.0):
for n in range(n):
# position
yield (random.random() - 0.5) * x_area
yield (random.random() - 0.5) * y_area
# Velocity
yield (random.random() - 0.5)
yield (random.random() - 0.5)
# Create geometry data
gen = gen_initial_data(N, x_area=self.aspect_ratio * 2 * 0.9, y_area=2.0 * 0.95)
data = numpy.fromiter(gen, count=N * 4, dtype='f4')
self.boids_buffer_1 = self.ctx.buffer(data.tobytes())
self.boids_buffer_2 = self.ctx.buffer(data=self.boids_buffer_1.read())
self.boids_vao_1 = VAO(name='boids_1', mode=moderngl.POINTS)
self.boids_vao_1.buffer(self.boids_buffer_1, '2f 2f', ['in_position', 'in_velocity'])
self.boids_vao_2 = VAO(name='boids_2', mode=moderngl.POINTS)
self.boids_vao_2.buffer(self.boids_buffer_2, '2f 2f', ['in_position', 'in_velocity'])
self.boids_texture = self.ctx.texture((MAX_TEX_WIDTH, N * 2 // MAX_TEX_WIDTH), components=2, dtype='f4')
# Programs
self.boids_render_program = self.load_program('programs/boids/boids_render.glsl')
self.boids_transform_program = self.load_program('programs/boids/boids_transform.glsl')
# Prepare for rendering
self.m_proj = matrix44.create_orthogonal_projection(
-self.aspect_ratio, self.aspect_ratio,
-1.0, 1.0,
-1.0, 1.0,
dtype='f4',
)
self.boids_render_program['m_proj'].write(self.m_proj.tobytes())
self.boids_transform_program['data'].value = 0
self.boids_transform_program['num_boids'].value = N
self.boids_transform_program['tex_width'].value = MAX_TEX_WIDTH
def render(self, time, frame_time):
self.boids_texture.use(location=0)
self.boids_transform_program['timedelta'].value = frame_time # max(frame_time, 1.0 / 60.0)
self.boids_vao_1.transform(self.boids_transform_program, self.boids_buffer_2)
self.boids_vao_2.render(self.boids_render_program)
# Swap around ..
self.boids_vao_1, self.boids_vao_2 = self.boids_vao_2, self.boids_vao_1
self.boids_buffer_1, self.boids_buffer_2 = self.boids_buffer_2, self.boids_buffer_1
# Write vertex data into texture so we can interate it in shader
self.boids_texture.write(self.boids_buffer_1.read())
if __name__ == '__main__':
moderngl_window.run_window_config(Boids)
|