Skip to content

Commit 585e863

Browse files
new effects!
1 parent c99111a commit 585e863

File tree

2 files changed

+204
-10
lines changed

2 files changed

+204
-10
lines changed

src/chaos simple.py

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import pygame
2+
import numpy as np
3+
import moderngl as mgl
4+
from pyrr import Matrix44
5+
import pmma
6+
7+
pmma.init()
8+
9+
# Initialize Pygame
10+
pygame.init()
11+
screen = pygame.display.set_mode((1920, 1080), pygame.OPENGL | pygame.DOUBLEBUF)
12+
clock = pygame.time.Clock()
13+
14+
# Initialize ModernGL context
15+
ctx = mgl.create_context()
16+
17+
# Vertex Shader
18+
vertex_shader = """
19+
#version 330
20+
uniform mat4 projection;
21+
uniform mat4 view;
22+
uniform mat4 model;
23+
24+
in vec3 in_position; // Base sphere vertex
25+
in vec3 instance_position; // Small sphere instance position
26+
in vec3 instance_color; // Small sphere instance color
27+
in float instance_radius; // Small sphere instance radius
28+
29+
out vec3 frag_color;
30+
31+
void main() {
32+
vec3 scaled_position = in_position * instance_radius; // Scale small sphere
33+
vec3 world_position = scaled_position + instance_position; // Translate to instance position
34+
gl_Position = projection * view * model * vec4(world_position, 1.0);
35+
frag_color = instance_color;
36+
}
37+
"""
38+
39+
# Fragment Shader
40+
fragment_shader = """
41+
#version 330
42+
in vec3 frag_color;
43+
out vec4 color;
44+
45+
void main() {
46+
color = vec4(frag_color, 1.0);
47+
}
48+
"""
49+
50+
# Compile shaders and link program
51+
program = ctx.program(
52+
vertex_shader=vertex_shader,
53+
fragment_shader=fragment_shader,
54+
)
55+
56+
# Uniforms
57+
projection = program['projection']
58+
view = program['view']
59+
model = program['model']
60+
61+
# Generate base sphere geometry (triangular mesh for the small spheres)
62+
def generate_sphere_mesh(radius, segments):
63+
vertices = []
64+
indices = []
65+
for i in range(segments):
66+
theta1 = np.pi * i / segments
67+
theta2 = np.pi * (i + 1) / segments
68+
69+
for j in range(segments):
70+
phi1 = 2 * np.pi * j / segments
71+
phi2 = 2 * np.pi * (j + 1) / segments
72+
73+
# Sphere vertices
74+
x1, y1, z1 = radius * np.sin(theta1) * np.cos(phi1), radius * np.sin(theta1) * np.sin(phi1), radius * np.cos(theta1)
75+
x2, y2, z2 = radius * np.sin(theta2) * np.cos(phi1), radius * np.sin(theta2) * np.sin(phi1), radius * np.cos(theta2)
76+
x3, y3, z3 = radius * np.sin(theta2) * np.cos(phi2), radius * np.sin(theta2) * np.sin(phi2), radius * np.cos(theta2)
77+
x4, y4, z4 = radius * np.sin(theta1) * np.cos(phi2), radius * np.sin(theta1) * np.sin(phi2), radius * np.cos(theta1)
78+
79+
# Append vertices
80+
vertices.extend([(x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4)])
81+
82+
# Add triangle indices
83+
base = len(vertices) - 4
84+
indices.extend([base, base + 1, base + 2, base, base + 2, base + 3])
85+
86+
return np.array(vertices, dtype='f4'), np.array(indices, dtype='i4')
87+
88+
sphere_vertices, sphere_indices = generate_sphere_mesh(1.0, 16)
89+
90+
# Create buffers for sphere geometry
91+
vbo_sphere = ctx.buffer(sphere_vertices.tobytes())
92+
ibo_sphere = ctx.buffer(sphere_indices.tobytes())
93+
94+
# Distribute points on a sphere (outer sphere)
95+
def generate_cube_grid(grid_size=5, spacing=2.0):
96+
""" Generates small sphere positions arranged in a cubic grid. """
97+
positions = []
98+
half_extent = (grid_size - 1) / 2 * spacing # Centering the cube
99+
100+
for x in range(grid_size):
101+
for y in range(grid_size):
102+
for z in range(grid_size):
103+
positions.append((
104+
x * spacing - half_extent,
105+
y * spacing - half_extent,
106+
z * spacing - half_extent
107+
))
108+
109+
return np.array(positions, dtype='f4')
110+
111+
# Generate instance data
112+
instance_positions = generate_cube_grid(grid_size=30, spacing=1.0)
113+
instance_colors = np.random.uniform(0.0, 1.0, (len(instance_positions), 3)).astype('f4')
114+
instance_radii = np.random.uniform(0.1, 0.1, (len(instance_positions),)).astype('f4')
115+
116+
vbo_instance_position = ctx.buffer(instance_positions.tobytes())
117+
vbo_instance_color = ctx.buffer(instance_colors.tobytes())
118+
vbo_instance_radius = ctx.buffer(instance_radii.tobytes())
119+
120+
# Create VAO
121+
vao = ctx.vertex_array(
122+
program,
123+
[
124+
(vbo_sphere, '3f', 'in_position'),
125+
(vbo_instance_position, '3f/i', 'instance_position'),
126+
(vbo_instance_color, '3f/i', 'instance_color'),
127+
(vbo_instance_radius, '1f/i', 'instance_radius'),
128+
],
129+
index_buffer=ibo_sphere,
130+
)
131+
132+
# Projection and view matrices
133+
projection_matrix = Matrix44.perspective_projection(45.0, 1920 / 1080, 0.1, 100.0)
134+
view_matrix = Matrix44.look_at(
135+
eye=(1.0, 1.0, 1.0),
136+
target=(0.0, 0.0, 0.0),
137+
up=(0.0, 1.0, 0.0)
138+
)
139+
model_matrix = Matrix44.identity()
140+
141+
# Main loop
142+
running = True
143+
angle = 0.0
144+
x_noise = pmma.Perlin()
145+
y_noise = pmma.Perlin()
146+
z_noise = pmma.Perlin()
147+
while running:
148+
for event in pygame.event.get():
149+
if event.type == pygame.QUIT:
150+
running = False
151+
152+
# Clear screen
153+
ctx.clear(0, 0, 0)
154+
ctx.enable(mgl.DEPTH_TEST)
155+
156+
# Rotate model matrix
157+
angle += 0.01
158+
model_matrix = Matrix44.from_eulers((angle, angle / 2, angle / 3))
159+
160+
r = x_noise.generate_2D_perlin_noise(pmma.get_application_run_time()/5, pmma.get_application_run_time()/5, new_range=[0, 1])
161+
g = y_noise.generate_2D_perlin_noise(pmma.get_application_run_time()/5, pmma.get_application_run_time()/5, new_range=[0, 1])
162+
b = z_noise.generate_2D_perlin_noise(pmma.get_application_run_time()/5, pmma.get_application_run_time()/5, new_range=[0, 1])
163+
164+
for i in range(len(instance_positions)):
165+
instance_colors[i] = (r, g, b)
166+
167+
# Update the color buffer
168+
vbo_instance_color.write(instance_colors.tobytes())
169+
170+
# Update uniforms
171+
projection.write(projection_matrix.astype('f4').tobytes())
172+
view.write(view_matrix.astype('f4').tobytes())
173+
model.write(model_matrix.astype('f4').tobytes())
174+
175+
# Render spheres
176+
vao.render(instances=len(instance_positions))
177+
178+
# Swap buffers
179+
pygame.display.flip()
180+
clock.tick(60)
181+
182+
pygame.quit()

src/chaos.py

+22-10
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ def generate_cube_grid(grid_size=5, spacing=2.0):
141141
# Main loop
142142
running = True
143143
angle = 0.0
144-
x_noise = pmma.Perlin()
145-
y_noise = pmma.Perlin()
146-
z_noise = pmma.Perlin()
144+
x_noise = pmma.Perlin(do_prefill=False)
145+
y_noise = pmma.Perlin(do_prefill=False)
146+
z_noise = pmma.Perlin(do_prefill=False)
147147
while running:
148148
for event in pygame.event.get():
149149
if event.type == pygame.QUIT:
@@ -157,15 +157,27 @@ def generate_cube_grid(grid_size=5, spacing=2.0):
157157
angle += 0.01
158158
model_matrix = Matrix44.from_eulers((angle, angle / 2, angle / 3))
159159

160-
for i, position in enumerate(instance_positions):
161-
# Use the starting position and time as inputs to the noise function
162-
r = x_noise.generate_2D_perlin_noise(position[0]/25 + pmma.get_application_run_time()/5, position[1]/25 + pmma.get_application_run_time()/5, new_range=[0, 1])
163-
g = y_noise.generate_2D_perlin_noise(position[1]/25 + pmma.get_application_run_time()/5, position[2]/25 + pmma.get_application_run_time()/5, new_range=[0, 1])
164-
b = z_noise.generate_2D_perlin_noise(position[2]/25 + pmma.get_application_run_time()/5, position[0]/25 + pmma.get_application_run_time()/5, new_range=[0, 1])
160+
# Normalize instance positions for noise
161+
norm_x = instance_positions[:, 0] / 25 + pmma.get_application_run_time() / 25
162+
norm_y = instance_positions[:, 1] / 25 + pmma.get_application_run_time() / 25
163+
norm_z = instance_positions[:, 2] / 25 + pmma.get_application_run_time() / 25
165164

166-
instance_colors[i] = (r, g, b)
165+
# Vectorized Perlin noise generation
166+
vec_perlin_x = np.vectorize(x_noise.generate_2D_perlin_noise, otypes=['f4'])
167+
vec_perlin_y = np.vectorize(y_noise.generate_2D_perlin_noise, otypes=['f4'])
168+
vec_perlin_z = np.vectorize(z_noise.generate_2D_perlin_noise, otypes=['f4'])
167169

168-
# Update the color buffer
170+
# Compute noise values efficiently
171+
r_values = (vec_perlin_x(norm_x, norm_y) + 1) / 2
172+
g_values = (vec_perlin_y(norm_y, norm_z) + 1) / 2
173+
b_values = (vec_perlin_z(norm_z, norm_x) + 1) / 2
174+
175+
# Assign noise values to instance colors
176+
instance_colors[:, 0] = r_values
177+
instance_colors[:, 1] = g_values
178+
instance_colors[:, 2] = b_values
179+
180+
# Update the color buffer in one go
169181
vbo_instance_color.write(instance_colors.tobytes())
170182

171183
# Update uniforms

0 commit comments

Comments
 (0)