You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyOpenGL中glGenVertexArrays函数在部分脚本调用失败求助

问题:PyOpenGL调用glGenVertexArrays时抛出NullFunctionError

在编写PyOpenGL程序显示四边形时,调用glGenVertexArrays函数时出现以下错误:

OpenGL.error.NullFunctionError: Attempt to call an undefined function glGenVertexArrays

推测问题与初始化流程有关。

相关代码

loader.py(核心为create_vao函数)

from raw_model import RawModel
from OpenGL.GL import *
from OpenGL.GLUT import *


class Loader:

    __vaos = []
    __vbos = []

    def load_to_vao(self, positions: list):
        vao_id = self.create_vao()
        self.store_data_in_attribute_list(0, positions)
        self.unbind_vao()
        return RawModel(vao_id, len(positions)//3)

    @classmethod
    def clean_up(cls):
        for vao in cls.__vaos:
            glDeleteVertexArrays(vao)
        for vbo in cls.__vbos:
            glDeleteBuffers(vbo)

    @classmethod
    def create_vao(cls):
        vao_id = glGenVertexArrays(1)
        cls.__vaos.append(vao_id)
        glBindVertexArray(vao_id)
        return vao_id

    @classmethod
    def store_data_in_attribute_list(cls, attribute_number: int, data: list):
        vbo_id = glGenBuffers()
        cls.__vbos.append(vbo_id)
        glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
        glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW)
        glVertexAttribPointer(attribute_number, 3, GL_FLOAT, False, 0, 0)
        glBindBuffer(GL_ARRAY_BUFFER, 0)

    @staticmethod
    def unbind_vao():
        glBindVertexArray(0)

display_manager.py(核心为create_display函数)

from OpenGL.GL import *
from OpenGL.GLUT import *


class DisplayManager:

    def __init__(self, x: int = 1920, y: int = 1080):
        if x is not None: self.__width = x
        if y is not None: self.__height = y

    def create_display(self, window_name):
        glutInit()
        glutInitDisplayMode(GLUT_RGBA)                           # initialize colors
        glutInitWindowSize(self.get_width(), self.get_height())  # set windows size
        glutInitWindowPosition(0, 0)                             # set window position
        glutCreateWindow(f"{window_name}")                       # create window (with a name) and set window attribute
        print(glGenVertexArrays(1))
        input("This ran")
        glutDisplayFunc(self.update_display)
        glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS)  # prevent program from stopping

    @staticmethod
    def update_display():
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)  # Remove everything from screen (i.e. displays all white)
        glLoadIdentity()                                    # Reset all graphic/shape's position
        glutSwapBuffers()                                   # Important for double buffering

    def get_width(self):
        return self.__width

    def get_height(self):
        return self.__height

    @classmethod
    def set_window(cls, window):
        cls.__WIND = window

已尝试在loader.py中加入glutInit()但无效,无法明确该函数的有效调用时机。


解决方案

原因分析

glGenVertexArrays是OpenGL 3.0及以上版本的核心函数,默认情况下GLUT创建的上下文可能是OpenGL 2.x版本,不支持VAO相关函数,导致函数未定义。另外,OpenGL函数的有效性依赖于已创建并激活的OpenGL上下文,如果在上下文创建前调用glGenVertexArrays也会触发该错误。

修复步骤

  1. 指定OpenGL版本并创建核心上下文
    修改DisplayManager.create_display方法,强制创建OpenGL 3.2及以上的核心上下文:

    def create_display(self, window_name):
        glutInit()
        # 强制指定OpenGL版本和核心上下文
        glutInitContextVersion(3, 2)
        glutInitContextProfile(GLUT_CORE_PROFILE)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)  # 补充双缓冲和深度缓冲
        glutInitWindowSize(self.get_width(), self.get_height())
        glutInitWindowPosition(0, 0)
        glutCreateWindow(f"{window_name}")
        # 验证上下文版本
        print(f"OpenGL版本: {glGetString(GL_VERSION)}")
        glutDisplayFunc(self.update_display)
        glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS)
    
  2. 确保VAO函数在上下文创建后调用
    所有OpenGL相关操作(包括Loader中的VAO创建)必须在glutCreateWindow之后执行,不能在上下文未初始化的代码中提前调用。

  3. 修复BufferData参数错误
    原代码中glBufferData直接传入Python列表会报错,需要转换为numpy数组并指定数据类型:
    先安装numpy:pip install numpy,再修改store_data_in_attribute_list方法:

    import numpy as np
    
    @classmethod
    def store_data_in_attribute_list(cls, attribute_number: int, data: list):
        vbo_id = glGenBuffers()
        cls.__vbos.append(vbo_id)
        glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
        # 转换为float32类型的numpy数组
        data_array = np.array(data, dtype=np.float32)
        glBufferData(GL_ARRAY_BUFFER, data_array, GL_STATIC_DRAW)
        glVertexAttribPointer(attribute_number, 3, GL_FLOAT, GL_FALSE, 0, None)
        glEnableVertexAttribArray(attribute_number)  # 必须启用顶点属性数组
        glBindBuffer(GL_ARRAY_BUFFER, 0)
    
  4. 启动GLUT主渲染循环
    在创建窗口后需要启动主循环,否则程序会直接退出,添加调用代码:

    if __name__ == "__main__":
        dm = DisplayManager()
        dm.create_display("Quad Display")
        glutMainLoop()
    

内容的提问来源于stack exchange,提问作者Andreas Sabelfeld

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:55:16