I started to learn opengl in python using moderngl and pygame-ce libraries. Still long way to go, need to wrap my head around all the concepts, I guess.
I can draw on a screen using mouse or spawn some primitives, and it is visable. If I change something in a shader - it changes what is drawn on the screen, so shader pipeline is working. But for some reason it won't update at all. It just stays static.
Probably I lack something basic, like understanding how to feedthrough same texture or something like that.
Edit: Question was marked as a duplicate of this question, but I have no problem drawing something, my problem is that it won't update.
What I did so far: I desided to replicate this tutorial to make game of life on gpu.
Basic idea is simple:
draw on a screen
convert pygame surface to moderngl texture
feed it to vertex (make quad basically) and fragment shader
in fragment shader impliment game of life rules (for each point look for neighbors, get their colors and add them together (don't forget to substract initial point), if this sum is equal to 2 and we have initial point "alive" point stays in that state, if sum equal 3 and initial point "dead" it became "alive")
render newly processed texture
Here is the code for basic pygame window:
import struct
from pathlib import Path
import moderngl
import pygame
from pygame.locals import *
pygame.init()
VIRTUAL_RES = (160, 120)
REAL_RES = (800, 600)
FPS = 60
clock = pygame.time.Clock()
screen = pygame.Surface(VIRTUAL_RES).convert((255, 65280, 16711680, 0))
pygame.display.set_mode(REAL_RES, DOUBLEBUF | OPENGL)
ctx = moderngl.create_context()
texture_coordinates = [0, 1, 1, 1,
0, 0, 1, 0]
world_coordinates = [-1, -1, 1, -1,
-1, 1, 1, 1]
render_indices = [0, 1, 2,
1, 2, 3]
vert_shader = Path("shaders/basic.vert").read_text()
frag_shader = Path("shaders/gol.frag").read_text()
prog = ctx.program(vertex_shader=vert_shader, fragment_shader=frag_shader)
screen_texture = ctx.texture(
VIRTUAL_RES, 3,
pygame.image.tobytes(screen, "RGB"))
vbo = ctx.buffer(struct.pack('8f', *world_coordinates))
uvmap = ctx.buffer(struct.pack('8f', *texture_coordinates))
ibo = ctx.buffer(struct.pack('6I', *render_indices))
vao_content = [
(vbo, '2f', 'vert'),
(uvmap, '2f', 'in_text')
]
vao = ctx.vertex_array(prog, vao_content, ibo)
pygame.draw.circle(screen, (255, 255, 255), (80, 60), 30)
done = False
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
mouse_position = (0, 0)
last_pos = None
drawing = False
def render():
texture_data = screen.get_view('1')
screen_texture.write(texture_data)
ctx.clear(14 / 255, 40 / 255, 66 / 255)
screen_texture.use()
vao.render()
pygame.display.flip()
while not done:
# screen.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == pygame.MOUSEMOTION:
if drawing:
mouse_position = pygame.mouse.get_pos()
mouse_position = (mouse_position[0] / 5, mouse_position[1] / 5)
if last_pos is not None:
pygame.draw.line(screen, WHITE, last_pos, mouse_position, 1)
last_pos = mouse_position
elif event.type == pygame.MOUSEBUTTONUP:
mouse_position = (0, 0)
drawing = False
elif event.type == pygame.MOUSEBUTTONDOWN:
drawing = True
render()
clock.tick(FPS)
pygame.quit()
and here are shaders:
#version 330 core
in vec2 vert;
in vec2 in_text;
out vec2 v_text;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
v_text = in_text;
}
#version 330 core
uniform sampler2D tex;
in vec2 v_text;
out vec4 f_color;
void main() {
vec2 uv = v_text;
vec4 color = texture(tex, uv);
float a = color.r;
float num = 0.0;
for (float i = -1.0; i < 2.0; i++) {
for (float j = -1.0; j < 2.0; j++) {
float x = uv.x + i;
float y = uv.y + j;
num += texture(tex, vec2(x, y)).r;
}
}
num -= a;
if(a > 0.5) {
if(num < 1.5) {
a = 0.0;
}
if(num > 3.5) {
a = 0.0;
}
} else {
if(num > 2.5 && num < 3.5) {
a = 1.0;
}
}
f_color = vec4(a, a, a, 1.0);
}