Screen appears completely white when using ModernGL and Pygame to render a texture

Question:

I am trying to make a minimal Moderngl example of about <150 lines so I can better understand how it works. The issue here is that when I try to render this texture (it is an image of a mushroom), it instead draws a fully white screen. What am I doing wrong?

Below is all of the code for the project (<200 lines). You can easily copy it and run it, however you do need an image to load into the texture

main.py

import moderngl as mg
import pygame
import sys
import texture

class Context:

    def __init__(self, size):
        self.window_size = size
        pygame.display.set_mode(size, pygame.OPENGL | pygame.DOUBLEBUF)
        self.ctx = mg.create_context()
        self.clock = pygame.time.Clock()
        m = pygame.image.load("images/Mushroom1.png").convert()
        self.tex = texture.Texture(self.ctx, m)

    def get_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.tex.destroy()
                pygame.quit()
                sys.exit()

    def render(self):
        self.ctx.clear(color=(1.0,0.0,0.0))
        self.tex.render()
        pygame.display.flip()

    def run(self):
        while True:
            self.get_events()
            self.render()
            self.clock.tick(60)

c = Context((800,600))
c.run()

texture.py

import moderngl as mg
import numpy as np
import pygame

class Texture:

    def __init__(self, ctx, img):
        self.ctx = ctx
        self.img = img
        self.vbo = self.create_vbo()
        self.texture = self.get_texture()
        self.shader = self.get_shader_program("default")
        self.vao = self.get_vao()

    def render(self):
        self.shader["Texture_0"] = 0
        self.texture.use(location=0)
        self.vao.render()

    def destroy(self):
        self.vbo.release()
        self.texture.release()
        self.shader.release()
        self.vao.release()

    def get_texture(self):
        texture = self.ctx.texture((self.img.get_width(), self.img.get_height()), 4, pygame.image.tostring(self.img, "RGBA"))
        return texture

    def get_vao(self):
        vao = self.ctx.vertex_array(self.shader, [(self.vbo, "2f 3f", "in_coords", "in_position")])
        return vao

    def create_vbo(self):
        vertices = [(-1.0, -1.0, 0.0), (1.0, -1.0, 0.0), (1.0, 1.0, 0.0), (-1.0, 1.0, 0.0)]
        tex_coords = [(0.2, 0.2), (0.8, 0.2), (0.8, 0.8), (0.2, 0.8)]
        indices = [(0, 1, 2), (0, 2, 3)]

        vertices = self.get_data(vertices, indices)
        tex_coords = self.get_data(tex_coords, indices)

        vertices = np.hstack([tex_coords, vertices])

        vbo = self.ctx.buffer(vertices)
        return vbo

    @staticmethod
    def get_data(vertices, indices):
        data = [vertices[ind] for t in indices for ind in t]
        return np.array(data, dtype="f4")

    def get_shader_program(self, shader_name):
        with open(f"shaders/{shader_name}.vert") as vert:
            v_shader = vert.read()

        with open(f"shaders/{shader_name}.frag") as frag:
            f_shader = frag.read()

        program = self.ctx.program(vertex_shader = v_shader, fragment_shader = f_shader)
        return program

vertex shader source:

#version 330

layout (location = 0) in vec2 in_coords;
layout (location = 1) in vec3 in_position;

out vec2 uv_0;

void main() {
    vec2 uv_0 = in_coords;
    gl_Position = vec4(in_position, 1.0);
}

and the fragment shader source:

#version 330

uniform sampler2D Texture_0;

layout (location = 0) out vec4 fragColor;

in vec2 uv_0;

void main() {
    vec3 color = vec3(texture(Texture_0, uv_0));
    fragColor = vec4(color, 1.0);
}
Asked By: Protolaser 28

||

Answers:

In your vertex shader, you are redeclaring uv_0
vec2 uv_0 = in_coords;
instead of assigning the value to the output value defined above.

Change vec2 uv_0 = in_coords; to uv_0 = in_coords;

Answered By: DaNubCoding
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.