Python glDrawArrays 显示空白屏幕

Python glDrawArrays Showing Blank Screen

所以我尝试在 Python 中使用 OpenGL 渲染 2D(最终是 3D)模型。我以前在 Java(很久以前)做过这个,并从复制程序开始。

一切看起来都很完美,但每当我 运行 程序时,我都会得到一个空白屏幕。

今天使用较早的版本(在我做一些清理之前)我只是有时会通过简单地重新启动内核而不更改任何内容来得到一个空白屏幕(大约 75% 的时间)。我运行 程序在三台不同的电脑上结果一样。 (75% 的空白是在两个 Ubuntu 20.04 系统上,我没有在 Windows 上尝试这部分。)

我的猜测是加载用于渲染 2D 纹理的顶点时出现问题(在 JGE2D.Rendereron_enable(..) 中),当然我不确定。

我现在有点不知所措,希望更有经验的人可能知道哪里出了问题,或者可能对在哪里查看有建议。该程序基本上采用一个主引擎,渲染器作为一个单独的模块插入其中。

目前着色器程序不渲染纹理。

我将完整的程序上传到 github (https://github.com/jeussa/JGE)。不过,相关的一切都应该在这里。

主程序(减去一些实用程序类):

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)

二维渲染器:

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)

以及着色器程序(分别为顶点着色器和片段着色器):

#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);
}

无论如何,谢谢你来我的post!!! :)

如果绑定了命名缓冲区对象,则 glVertexAttribPointer 的第 6 个参数被视为缓冲区对象数据存储中的字节偏移量。但是参数的类型无论如何都是指针(c_void_p).

所以如果偏移量为0,那么第6个参数可以是None或者c_void_p(0):

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

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