Skip to content

Commit 51f784e

Browse files
new effect
This took some time to work
1 parent 159b014 commit 51f784e

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

src/3d spinning ball.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import math
2+
import moderngl as mgl
3+
import numpy as np
4+
from PIL import Image
5+
from pyrr import Matrix44
6+
from moderngl_window import geometry, run_window_config
7+
from moderngl_window.conf import settings
8+
from moderngl_window.context.base import WindowConfig
9+
import pmma
10+
from time import perf_counter
11+
12+
pmma.init()
13+
14+
# Set up configuration
15+
class SphereWindow(WindowConfig):
16+
window_size = (800, 600)
17+
resource_dir = '.' # Directory where textures are stored
18+
aspect_ratio = 800 / 600
19+
title = "Spinning Textured Sphere"
20+
21+
def __init__(self, **kwargs):
22+
super().__init__(**kwargs)
23+
self.camera_position = (0.0, 0.0, 10.0) # Move the camera further back
24+
self.rotation_angle = 0.0
25+
26+
# Compile shaders
27+
self.program = self.ctx.program(
28+
vertex_shader="""
29+
#version 330 core
30+
31+
uniform mat4 model;
32+
uniform mat4 projection;
33+
uniform sampler2D texture0;
34+
35+
in vec3 in_position; // Input vertex position
36+
in vec2 in_texcoord_0; // Input texture coordinates
37+
38+
out float luminance;
39+
40+
void main() {
41+
// Sample the texture using the texture coordinates
42+
vec3 tex_color = texture(texture0, in_texcoord_0).rgb;
43+
44+
// Calculate the luminance (darker = higher protrusion)
45+
luminance = 1.0 - dot(tex_color, vec3(0.2126, 0.7152, 0.0722)); // Standard luminance calculation
46+
47+
// Offset the vertex position along its normal
48+
vec3 displaced_position = in_position + in_position * luminance * 0.2; // Adjust the 0.2 factor as needed
49+
50+
// Set the final vertex position
51+
gl_Position = projection * model * vec4(displaced_position, 1.0);
52+
}
53+
54+
""",
55+
fragment_shader="""
56+
#version 330 core
57+
58+
out vec3 fragColor;
59+
in float luminance;
60+
61+
uniform vec3 inner_color;
62+
uniform vec3 outer_color;
63+
64+
void main() {
65+
fragColor = mix(inner_color, outer_color, luminance);
66+
}
67+
""",
68+
)
69+
70+
# Geometry
71+
self.sphere = geometry.sphere(radius=1.0, sectors=64, rings=64)
72+
73+
# Uniform locations
74+
self.model = self.program["model"]
75+
self.projection = self.program["projection"]
76+
77+
# Setup projection matrix
78+
self.projection_matrix = Matrix44.perspective_projection(
79+
75.0, # Increase the field of view
80+
self.aspect_ratio,
81+
0.1,
82+
100.0,
83+
)
84+
85+
self.texture = self.ctx.texture(
86+
size=(64, 64),
87+
components=3,
88+
data=None, # No initial data
89+
)
90+
self.texture.use(location=0)
91+
self.texture.filter = (mgl.LINEAR, mgl.LINEAR)
92+
self.texture.repeat_x = True
93+
self.texture.repeat_y = True
94+
95+
self.program["inner_color"].write(np.array([1.0, 0.0, 0.0], dtype="f4"))
96+
self.program["outer_color"].write(np.array([0.0, 0.0, 1.0], dtype="f4"))
97+
98+
self.noise = pmma.Perlin(octaves=1)
99+
self.inner_color = pmma.ColorConverter()
100+
self.outer_color = pmma.ColorConverter()
101+
pmma.set_in_game_loop(True)
102+
103+
def render(self, time, frame_time):
104+
self.ctx.clear(0, 0, 0)
105+
self.ctx.enable(mgl.DEPTH_TEST)
106+
107+
# Create texture from integer array
108+
array = np.zeros((64, 64, 3), dtype=np.uint8)
109+
110+
for x in range(0, 64):
111+
for y in range(0, 64):
112+
c = self.noise.generate_2D_perlin_noise(
113+
(x % 64) / 20 + time / 5,
114+
(y % 64) / 20 + time / 5,
115+
new_range=[0, 255]
116+
)
117+
array[x][y] = [c, c, c]
118+
119+
# Resize to fit the sphere's texture size
120+
rgb_array = array#np.repeat(np.repeat(array, 64 // array.shape[0], axis=0), 64 // array.shape[1], axis=1)
121+
122+
# Upload texture
123+
self.texture.write(rgb_array.tobytes())
124+
125+
# Calculate model matrix
126+
self.rotation_angle += frame_time/5
127+
model_matrix = Matrix44.from_translation((0.0, 0.0, -2.0))# * Matrix44.from_eulers((-self.rotation_angle, self.rotation_angle, 0.0))
128+
129+
# Update uniforms
130+
self.model.write(model_matrix.astype("f4"))
131+
self.projection.write(self.projection_matrix.astype("f4"))
132+
133+
self.program["inner_color"].write(np.array(self.inner_color.generate_color_from_perlin_noise(value=time/10, format=pmma.Constants.SMALL_RGB), dtype="f4"))
134+
self.program["outer_color"].write(np.array(self.outer_color.generate_color_from_perlin_noise(value=-time/10+20.54365, format=pmma.Constants.SMALL_RGB), dtype="f4"))
135+
136+
# Render the sphere
137+
self.sphere.render(self.program)
138+
139+
if __name__ == "__main__":
140+
settings.WINDOW['class'] = 'pyglet'
141+
run_window_config(SphereWindow)

0 commit comments

Comments
 (0)