Python Moderngl 雨波纹着色器

问题描述 投票:0回答:1

我正在尝试通过 pygame 使用 glsl 着色器和窗口管理在 python 中重新创建以下文章中的连锁反应 https://web.archive.org/web/20160418004149/http://freespace.virgin.net/hugo.elias/graphics/x_water.htm 我发现了一些其他来源: https://www.youtube.com/watch?v=qm5cDNbtGig https://www.youtube.com/watch?v=BZUdGqeOD0w

如果我单击更改两个缓冲区之间像素的 RGB 值,同时还应用阻尼效果,着色器应该会在屏幕上创建水波纹。

理论上来说,有一个当前缓冲区存储当前帧的像素数据,还有一个先前缓冲区包含来自前一帧的纹素数据。您可以根据周围像素的值更改每个像素的 RGB 值,同时应用阻尼因子来降低像素的亮度。

然后显示当前缓冲区 并交换缓冲区

该实现不应该使用余弦或正弦,这使得它非常有趣。

我的问题是波纹没有显示出来。

我尝试过两个版本,但都不成功: 第一次尝试主要是在第一个视频之后 我使用 numpy 数组(float32),它们被写入 Moderngl 纹理中。 片段着色器捕获着色器的像素并像视频中一样对其进行修改。然后吐出结果是一样的。

第二种大部分放弃了片段着色器 它使用两个 float32 的 numpy 数组,这些数组被写入 Moderngl 纹理中,仅用于渲染。 我按照这篇文章来处理更改像素并重新写入纹理

第一次尝试

import numpy
import pygame, moderngl
from sys import exit

class Main():
    def __init__(self):
        self.vertex_shader: str = """
# version 460 core

in vec2 aPosition;
in vec2 aTexCoord;
out vec2 pos;

void main(){
    pos = aTexCoord;
    pos.y = 1.0 - pos.y;

    gl_Position = vec4(aPosition, 0.0, 1.0);
}
"""

        self.fragment_shader: str = """
#version 460 core

uniform vec2 resolution;
uniform float dampening;
uniform sampler2D currBuffer;
uniform sampler2D prevBuffer;

in vec2 pos;

out vec4 f_colour;

void main(){
    vec2 pix = 1.0/resolution;

    float prev = texture(prevBuffer, pos).r;

    float u = texture(currBuffer, pos + vec2(0.0, pix.y)).r;
    float d = texture(currBuffer, pos - vec2(0.0, pix.y)).r;
    float r = texture(currBuffer, pos + vec2(pix.x, 0.0)).r;
    float l = texture(currBuffer, pos - vec2(pix.x, 0.0)).r;

    float next = ((u + d + l + r) / 2.0) - prev;
    next = next * dampening;

    f_colour = vec4(next, next/2.0 + 0.5, 1.0, 1.0);
}
"""

        pygame.init()
        self.screen: pygame.Surface   = pygame.display.set_mode((1000,600), pygame.RESIZABLE | pygame.OPENGL | pygame.DOUBLEBUF)
        self.clock: pygame.time.Clock = pygame.time.Clock()
        pygame.display.set_caption("Render Engine Test")

        self.ctx: moderngl.Context = moderngl.create_context()

        self.program: moderngl.Program     = self.ctx.program(vertex_shader=self.vertex_shader, fragment_shader=self.fragment_shader)
        self.vbo_1:   moderngl.Buffer      = self.ctx.buffer(data=numpy.array([-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0], dtype="f4"))
        self.vbo_2:   moderngl.Buffer      = self.ctx.buffer(data=numpy.array([-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0], dtype="f4"))
        self.vao:     moderngl.VertexArray = self.ctx.vertex_array(self.program, [(self.vbo_1, "2f", "aPosition"), (self.vbo_2, "2f", "aTexCoord")])
        self.current_buffer  = numpy.array([[0.0 for x in range(self.screen.get_size()[0])] for y in range(self.screen.get_size()[1])], dtype="f4")
        self.previous_buffer = numpy.array([[0.0 for x in range(self.screen.get_size()[0])] for y in range(self.screen.get_size()[1])], dtype="f4")
        
        self.current_buffer[500][300] = 0.1

        self.program["resolution"] = self.screen.get_size()
        self.program["dampening"]  = 0.9

        self.current_texture:  moderngl.Texture = self.ctx.texture(size=self.screen.get_size(), components=4)
        self.previous_texture: moderngl.Texture = self.ctx.texture(size=self.screen.get_size(), components=4)

        self.current_texture.use(location=0)
        self.previous_texture.use(location=1)
        self.program["currBuffer"] = 0
        self.program["prevBuffer"] = 1

    def update(self):

        self.current_texture.write(data=self.current_buffer)
        self.previous_texture.write(data=self.previous_buffer)

        temp_buffer = self.previous_buffer
        self.previous_buffer = self.current_buffer
        self.current_buffer  = temp_buffer


    def draw(self):
        self.ctx.clear(0.0, 0.0, 0.0)
        self.vao.render(mode=moderngl.TRIANGLE_STRIP)
        pygame.display.flip()

    def check_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.exit_garbage()
                pygame.quit()
                exit()


    def exit_garbage(self):
        self.vao.release()
        self.program.release()
        self.vbo_1.release()
        self.vbo_2.release()
        self.current_texture.release()
        self.previous_texture.release()

    def run(self):
        while True:
            self.check_events()
            self.update()
            self.draw()
            self.clock.tick(60)

if __name__ == "__main__":
    main: Main = Main()
    main.run()

第二次尝试

import numpy
import pygame, moderngl
from sys import exit

class Main():
    def __init__(self):
        self.vertex_shader: str = """
# version 460 core

in vec2 aPosition;

void main(){
    gl_Position = vec4(aPosition, 0.0, 1.0);
}
"""

        self.fragment_shader: str = """
#version 460 core

uniform vec2 resolution;
uniform sampler2D myTexture;
uniform float dampening;
out vec4 f_colour;

void main(){

    vec2 pos = vec2(gl_FragCoord.xy / resolution.xy);

    float next = texture(myTexture, pos).r * dampening;
    f_colour   = vec4(next, next/2.0 + 0.5, 1.0, 1.0);
}
"""

        pygame.init()
        self.screen: pygame.Surface   = pygame.display.set_mode((500,500), pygame.RESIZABLE | pygame.OPENGL | pygame.DOUBLEBUF)
        self.clock: pygame.time.Clock = pygame.time.Clock()
        pygame.display.set_caption("Render Engine Test")

        self.ctx: moderngl.Context = moderngl.create_context()

        self.program: moderngl.Program     = self.ctx.program(vertex_shader=self.vertex_shader, fragment_shader=self.fragment_shader)
        self.vbo_1:   moderngl.Buffer      = self.ctx.buffer(data=numpy.array([-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0], dtype="f4"))
        self.vao:     moderngl.VertexArray = self.ctx.vertex_array(self.program, [(self.vbo_1, "2f", "aPosition")])

        # self.buffer_1 = numpy.array([1.0 for x in range(self.screen.get_width()) for x in range(self.screen.get_height())], dtype="f4")
        self.buffer_1 = numpy.zeros(shape=(self.screen.get_height(), self.screen.get_width()), dtype="f4")
        self.buffer_2 = numpy.zeros(shape=(self.screen.get_height(), self.screen.get_width()), dtype="f4")
        
        self.texture: moderngl.Texture = self.ctx.texture(size=self.screen.get_size(), components=4)
        self.texture.write(data=self.buffer_1.tobytes())
        self.texture.use(location=0)

        self.program["dampening"]  = 0.9
        self.program["resolution"] = self.screen.get_size()
        self.program["myTexture"]  = 0
    
    def update(self):
        try:
            for y in range(len(self.buffer_2)):
                for x in range(len(self.buffer_2)):
                    self.buffer_2[y][x] = (
                        self.buffer_1[y][x-1] +
                        self.buffer_1[y][x+1] +
                        self.buffer_1[y+1][x] +
                        self.buffer_1[y-1][x]
                    ) / 2 - self.buffer_2[y][x]
        except: pass

    def draw(self):
        self.ctx.clear(0.0, 0.0, 0.0)
        self.vao.render(mode=moderngl.TRIANGLE_STRIP)
        pygame.display.flip()

        temp_buffer = self.buffer_2
        self.buffer_2 = self.buffer_1
        self.buffer_1 = temp_buffer

        self.texture.write(data=self.buffer_1.tobytes())

    def check_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.exit_garbage()
                pygame.quit()
                exit()
        if pygame.mouse.get_pressed()[0]:
            x: int; y: int
    
            x, y = pygame.mouse.get_pos()
            self.buffer_1[y-1][x-1] = 1


    def exit_garbage(self):
        self.ctx.release()
        self.vao.release()
        self.vbo_1.release()
        self.texture.release()

    def run(self):
        while True:
            self.check_events()
            self.update()
            self.draw()
            self.clock.tick(60)

if __name__ == "__main__":
    main: Main = Main()
    main.run()

我可以帮忙吗?

python opengl glsl shader python-moderngl
1个回答
0
投票

哭吧你这个悲伤的小男孩

© www.soinside.com 2019 - 2024. All rights reserved.