简体   繁体   中英

Python glDrawArrays Showing Blank Screen

So I'm trying to render 2D (and eventually 3D) models using OpenGL in Python. I've done this before in Java (long time ago) and somewhat started off by copying the program.

Everything looks perfect, but whenever I run the program I get a blank screen.

With an earlier version today (before I did some cleaning up) I would only sometimes get a blank screen (about 75% of the time) by simply restarting the kernel and not changing anything. I ran the program on three different computers with the same results. (The 75% blank was on two Ubuntu 20.04 systems, I did not try this part on Windows.)

My guess is that something is going wrong when loading the vertices used to render a 2D texture (in the on_enable(..) of JGE2D.Renderer ), though I'm not sure of course.

I'm kind of out of ideas now and am hoping someone more experienced might know what's wrong, or perhaps have a suggestion as to where to look. The program basically takes a main engine to which the renderer is inserted as a separate module.

Currently textures are not rendered by the shader program.

I uploaded the full program to github ( https://github.com/jeussa/JGE ). Though, everything relevant should be down here.

The main program (minus a few utility classes):

import numpy as np

import os
import platform
import sys
import time

from PIL import Image
import traceback

import glfw as GLFW
from OpenGL import GL



# ==========
# = Engine =
# ==========
class Engine:

    def __init__(self, fps = 60):
        self.modules = []
        self.sync = Sync(fps)
        self.ups = UPS()
        self.scheduler = Scheduler()
    

    # = Start =
    def start(self):
        self.startat = time.time()

        Console.info("==========================================================================")
        Console.info("os.name == \"{a}\"".format(a=os.name))
        Console.info("sys.platform == \"{a}\"".format(a=sys.platform))
        Console.info("platform.system() == \"{a}\"".format(a=platform.system()))
        Console.info("platform.machine() == \"{a}\"".format(a=platform.machine()))
        Console.info("platform.architecture() == \"{a}\"".format(a=platform.architecture()))
        Console.info("sys.version == \"{a}\"".format(a=sys.version))
        Console.info("==========================================================================")

        # Initialize
        if not GLFW.init():
            raise ValueError("Failed to initialize GLFW !")
        GLFW.set_error_callback(Console.gl_error)

        # Load modules
        Console.info("Loading modules ...")
        self.__call_modules__("on_load")
        
        # Configure GLFW
        GLFW.default_window_hints()

        # Create window
        self.window = GLFW.create_window(800, 600, "jeussa Graphics Engine", None, None)
        if not self.window:
            raise ValueError("Failed to create GLFW window !")
        GLFW.make_context_current(self.window)

        # Clear window
        GL.glClearColor(0, .8, 0, 0)

        # Enable modules
        Console.info("Enabling modules ...")
        self.__call_modules__("on_enable")

        # Finish
        Console.info("Startup done! [{a} ms]".format(a=round((time.time()-self.startat)*1000)))
    

    # = Loop =
    def loop(self):
        Console.info("Entering loop ...")

        while not GLFW.window_should_close(self.window):
            self.sync.start()

            # Events
            GLFW.poll_events()

            # Scheduler
            self.scheduler.poll()

            # Clear buffers
            GL.glViewport(0, 0, *GLFW.get_window_size(self.window))
            GL.glClear(GL.GL_COLOR_BUFFER_BIT|GL.GL_DEPTH_BUFFER_BIT)

            # Loop modules
            self.__call_modules__("on_loop")
            
            # Update window
            GLFW.swap_buffers(self.window)

            self.ups.tick()
            self.sync.end()
        
        Console.info("Exiting loop ...")
    

    # = End =
    def end(self):
        Console.info("Disabling modules ...")
        self.__call_modules__("on_disable")

        Console.info("Stopping JGEngine ...")
        GLFW.terminate()
        Console.info("JGEngine stopped")
    

    # = Call Modules =
    def __call_modules__(self, func):
        for module in self.modules:
            if hasattr(module.__class__, func):
                attr = getattr(module.__class__, func)
                if callable(attr):
                    try:
                        attr(module)
                    except Exception:
                        traceback.print_exc()
                        self.modules.remove(module)

The 2D renderer:

import numpy as np
from OpenGL import GL

from JGE import Console
from JGEMath import Matrix4



# ============
# = Renderer =
# ============
class Renderer:

    def __init__(self, engine):
        self.engine = engine
        self.models = []

        self.vao = None
        self.vbo = None
        self.shader = None
    
    
    # = On Enable =
    def on_enable(self):
        # Create VAO
        self.vao = GL.glGenVertexArrays(1)
        GL.glBindVertexArray(self.vao)

        self.vbo = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbo)

        GL.glBufferData(GL.GL_ARRAY_BUFFER, np.array([
            -.5, .5, -.5, -.5, .5, .5, .5, -.5
        ], np.float32), GL.GL_STATIC_DRAW)
        GL.glVertexAttribPointer(0, 2, GL.GL_FLOAT, False, 0, 0)

        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)

        # Load Shader
        self.shader = [GL.glCreateProgram()]

        for program in [["lib/JGE2D.vs.glsl", GL.GL_VERTEX_SHADER], ["lib/JGE2D.fs.glsl", GL.GL_FRAGMENT_SHADER]]:
            input = open(program[0], 'r')

            id = GL.glCreateShader(program[1])
            GL.glShaderSource(id, input.read())
            GL.glCompileShader(id)

            input.close()

            if GL.glGetShaderiv(id, GL.GL_COMPILE_STATUS) == GL.GL_FALSE:
                Console.error("Failed to compile shader !")
                Console.error(GL.glGetProgramInfoLog(id))
                raise ValueError("Failed to compile shader !")

            self.shader.append(id)
        
        GL.glAttachShader(self.shader[0], self.shader[1])
        GL.glAttachShader(self.shader[0], self.shader[2])

        GL.glLinkProgram(self.shader[0])

        if GL.glGetProgramiv(self.shader[0], GL.GL_LINK_STATUS) == GL.GL_FALSE:
            raise ValueError("Failed to link shader programs !")
        
        self.uv_InvertY = GL.glGetUniformLocation(self.shader[0], "in_InvertY")
        self.uv_ObjPos = GL.glGetUniformLocation(self.shader[0], "in_ObjPos")

    

    # = On Loop =
    def on_loop(self):
        if not self.models:
            return
        
        # Prepare
        GL.glUseProgram(self.shader[0])
        GL.glBindVertexArray(self.vao)
        GL.glDisable(GL.GL_DEPTH_TEST)
        GL.glEnableVertexAttribArray(0)
        GL.glBindAttribLocation(self.shader[0], 0, "in_Vector")

        # Render
        for model in self.models:
            GL.glActiveTexture(GL.GL_TEXTURE0)
            GL.glBindTexture(GL.GL_TEXTURE_2D, model.texture.handle)

            GL.glUniformMatrix4fv(self.uv_ObjPos, 1, False, np.matrix.flatten(model.generate_translation_matrix()))
            GL.glUniform1f(self.uv_InvertY, 1 if model.invert_y else 0)

            GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4)

        # Cleanup
        GL.glUseProgram(0)
        GL.glDisableVertexAttribArray(0)
        GL.glBindVertexArray(0)

And the shader programs (vertex shader and fragment shader respectively):

#version 400 core

in vec2 in_Vector;

uniform float in_InvertY;
uniform mat4 in_ObjPos;

out vec2 pass_TexVec;

void main(void){
    // Position
    //gl_Position = in_ObjPos * vec4(in_Vector, 0.0, 1.0);        // The position of the current vertex on the screen
    gl_Position = vec4(in_Vector, 0.0, 1.0);

    // Texture
    if(in_InvertY > 0.5)pass_TexVec = vec2(in_Vector.x + 0.5, 0.5 - in_Vector.y);
    else pass_TexVec = vec2(in_Vector.x + 0.5, in_Vector.y + 0.5);
}
#version 400 core

in vec2 pass_TexVec;

uniform sampler2D in_Texture;

out vec4 gl_FragColor;

void main(void){
    // Texture
    //out_Color = texture2D(in_Texture, pass_TexVec);
    //if(out_Color.a < 0.5)discard;
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Anyways, thanks for stopping by my post:!! :)

If a named buffer object is bound, then the 6th parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store. But the type of the parameter is a pointer anyway ( c_void_p ).

So if the offset is 0, then the 6th parameter can either be None or c_void_p(0) :

GL.glVertexAttribPointer(0, 2, GL.GL_FLOAT, False, 0, 0)

GL.glVertexAttribPointer(0, 2, GL.GL_FLOAT, False, 0, None)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM