OpenGL框选动画

问题遇到的现象和发生背景

你好,我需要OpenGL实现框选的动画,就是鼠标按下移动时会跟随鼠标生成矩形,松开时矩形消失

遇到的现象和发生背景,请写出第一个错误信息

顶点应该是正确的,但窗口上没有图像

用代码块功能插入代码,请勿粘贴截图。 不用代码块回答率下降 50%
import numpy as np
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GL import shaders


class RectPainter():
    def __init__(self):
        """准备模型数据"""
        vshader_src = """
            #version 420 core
            layout (location = 0) in vec3 aPos;
            void main(){ 
                gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); // gl_Position是内置变量
            }
        """

        fshader_src = """
            #version 420 core
            out vec4 frag_color;
            void main(){
                frag_color = vec4(1.0f, 0.5f, 0.2f, 1.0f);// gl_FragColor是内置变量    
            } 
        """
        vshader = shaders.compileShader(vshader_src, GL_VERTEX_SHADER)
        fshader = shaders.compileShader(fshader_src, GL_FRAGMENT_SHADER)
        self.PROGRAM = shaders.compileProgram(vshader, fshader)
        self.start_x = 0
        self.start_y = 0
        self.end_x = 0
        self.end_y = 0
        self.clear_flag = False
        self.vao = glGenVertexArrays(1) 
        self.vertices_buffer = glGenBuffers(1)

    def draw(self):
        """绘制模型"""
        glClearColor(178 / 255, 195 / 255, 234 / 255, 0.5)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)  # 清除缓冲区
        glUseProgram(self.PROGRAM)
        glBindVertexArray(self.vao)
        if self.clear_flag is True:
            self.start_x = 0
            self.start_y = 0
            self.end_x = 0
            self.end_y = 0
        # 顶点数据
        vertices = [[self.start_x, self.start_y, 0.0], [self.end_x, self.start_y, 0.0], [self.end_x, self.end_y, 0.0], [self.start_x, self.end_y, 0.0]]
        vertices = np.array(vertices, dtype=np.float32)

        glBindBuffer(GL_ARRAY_BUFFER, self.vertices_buffer)
        glBufferData(GL_ARRAY_BUFFER, vertices, GL_DYNAMIC_DRAW)  # 动态绘制
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
        glEnableVertexAttribArray(0)
        # 绘制
        print("四点数据:", vertices)
        glDrawArrays(GL_LINE_LOOP, 0, 4)
        # 结束
        glBindVertexArray(0)
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        glUseProgram(0)
        glFlush()  # 执行缓冲区指令


def mymouse(button, state, x, y):
    if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        painter.start_x, painter.start_y = x, y
        painter.end_x, painter.end_y = x, y
        painter.clear_flag = False
    elif button == GLUT_LEFT_BUTTON and state == GLUT_UP:
        painter.end_x, painter.end_y = x, y
        painter.clear_flag = True
        glutPostRedisplay()#update

    '''
    glutPostRedisplay()是一个OpenGL函数,用于重绘当前窗口。
    它通知OpenGL重新渲染整个窗口,以便更新视图。
    这通常用于动画等场景,在窗口大小、位置或其他视图参数发生变化时也会调用。
    '''

def mymotion(x, y):
    painter.end_x, painter.end_y = x, y
    glutPostRedisplay()#update


if __name__ == "__main__":
    glutInit()  # 1. 初始化glut库
    glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE)  # 2. 设置显示模式
    glutInitWindowSize(600, 400)  # 3. 设置窗口大小
    glutCreateWindow('OpenGL Demo')  # 2. 创建glut窗口
    painter = RectPainter()  # 3. 生成着色器程序、顶点数据集、颜色数据集
    glutDisplayFunc(painter.draw)  # 4. 绑定模型绘制函数
    glutMouseFunc(mymouse)  # 5. 绑定鼠标事件
    glutMotionFunc(mymotion)
    glutMainLoop()  # 6. 进入glut主循环


我的解答思路和尝试过的方法

定义一个类RectPainter,包含了初始化,绘图方法,重写鼠标点击,释放事件,在点击释放时记录坐标,释放时clear_flag为True,这样绘制时顶点坐标重置为0(不绘制)同时更新画面,重写鼠标移动事件,鼠标移动时记录坐标并更新画面

OpenGL 使用 NDC(标准化设备坐标) 作为坐标系啊,中心是(0,0),右上角是(1,1),左下角是(-1,-1),所以要把屏幕坐标转换为 NDC 坐标

vert_start_x = self.start_x / 300 - 1
vert_start_y = 1 - self.start_y / 200
vert_end_x = self.end_x / 300 - 1
vert_end_y = 1 - self.end_y / 200
# 顶点数据
vertices = [[vert_start_x, vert_start_y, 0.0], [vert_end_x, vert_start_y, 0.0], [vert_end_x, vert_end_y, 0.0], [vert_start_x, vert_end_y, 0.0]]
vertices = np.array(vertices, dtype=np.float32)