[Python] Why does opengl VAO bind fail in this paint function?

Discussão em 'Python' iniciado por Stack, Abril 20, 2025.

  1. Stack

    Stack Membro Participativo

    I have a simple PyQt OpenGL widget. It fails to render.

    When the fragment shader is

    #version 330
    in vec2 f_position;
    out vec4 fragColor;
    void main()
    {
    fragColor = vec4(f_position.x, f_position.y, 0.5, 1.0);
    }


    then this in paintGL()

    if not self.vao.bind():
    print ("paintGL could not bind vao: "+ str(glGetError()))


    prints

    paintGL could not bind vao: 0


    This is weird: couldn't bind but error is 0?

    When I use the full fragment shader in the code below, I get

    paintGL could not bind vao: 1282


    Either way, the only thing that renders is the glClearColor value.

    Full code:

    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtOpenGL import *

    from OpenGL.GL import *

    import math
    import numpy.linalg

    VERTEX_SHADER = """
    #version 330
    in vec2 v_position;
    out vec2 f_position;
    void main() {
    f_position = v_position;
    gl_Position = vec4(v_position, 0.0, 1.0);
    }
    """

    FRAGMENT_SHADER = """
    #version 330
    in vec2 f_position;
    uniform vec3 u_base_colour;
    uniform vec3 u_surface_focus; // centre of globe to (latitude,longitude,altitude=1) NOT scaled by radius
    uniform vec3 u_right_unit;
    uniform vec3 u_up_unit;
    uniform vec3 u_globe_position;
    uniform float u_globe_radius;
    out vec4 fragColor;

    vec3 sphericalToCartesian(float polar_angle, float azimuthal_angle) // latitude, longitude
    {
    float cos_polar = cos(polar_angle);
    float sin_polar = sin(polar_angle);
    float cos_azimuthal = cos(azimuthal_angle);
    float sin_azimuthal = sin(azimuthal_angle);

    float x = cos_polar * cos_azimuthal;
    float y = cos_polar * sin_azimuthal;
    float z = sin_polar;

    return vec3(x, y, z);
    }

    // returns (latitude,longitude,altitude)
    vec3 cartesianToSpherical(vec3 cartesian)
    {
    float x = cartesian.x;
    float y = cartesian.y;
    float z = cartesian.z;

    // Calculate altitude (distance from origin)
    float altitude = length(cartesian);

    // Handle the case when point is at the origin
    if (altitude < 1e-6)
    return vec3(0.0, 0.0, 0.0);

    // Calculate polar angle (latitude)
    float polar_angle = asin(z / altitude);

    // Calculate azimuthal angle (longitude)
    float azimuthal_angle = atan(y, x);

    // Ensure azimuthal_angle is in the range [0, 2π]
    if (azimuthal_angle < 0.0)
    azimuthal_angle += 2.0 * 3.14159265359;

    return vec3(polar_angle, azimuthal_angle, altitude);
    }

    float raySphereIntersect (vec3 ray_origin, vec3 ray_direction, vec3 sphere_centre, float radius)
    {
    float a = dot (ray_direction, ray_direction);
    vec3 centre_to_ray_origin = ray_origin - sphere_centre;
    float b = 2.0 * dot(ray_direction, centre_to_ray_origin);
    float c = dot(centre_to_ray_origin, centre_to_ray_origin) - (radius * radius);

    float discriminant = b*b - 4.0*a*c;

    if (discriminant < 0.0)
    return -1.0;
    else
    return (-b - sqrt(discriminant))/(2.0*a);
    }

    void main()
    {

    vec3 camera_coordinate = f_position.x*u_right_unit + f_position.y*u_up_unit;

    // 1.1 is arbitrary, but >1 to prevent rounding error edge case.
    vec3 camera_origin = (1.1*u_globe_radius) * u_surface_focus;

    vec3 ray_direction = -u_surface_focus;

    float distance_to_intersection = raySphereIntersect (
    camera_origin + camera_coordinate*u_globe_radius,
    ray_direction,
    vec3(0.0, 0.0, 0.0), // We are in local space
    u_globe_radius);

    if (distance_to_intersection < 0.0)
    fragColor = vec4(0.0, 0.0, 0.9, 1.0);
    else
    {
    vec3 surface_intersection = camera_origin + distance_to_intersection * ray_direction;

    // TODO invert the rotation given time

    vec3 local_surface = cartesianToSpherical(surface_intersection);

    // geological coordinates -> local coordinates over time
    // invert this to get geological coordinates
    vec3 geo_surface = local_surface;

    vec3 lat_lon_alt = cartesianToSpherical(geo_surface);

    vec2 geo_texture_coordinates = vec2(
    lat_lon_alt.x / (2.0 * 3.14159265359),
    (1.0 + lat_lon_alt.y / 3.14159265359) / 2.0);

    fragColor = vec4(geo_texture_coordinates.x, geo_texture_coordinates.y, u_base_colour.z, 1.0);
    }
    }
    """



    def sphericalToCartesian(polar_angle, azimuthal_angle): # latitude, longitude

    cos_polar = math.cos(polar_angle);
    sin_polar = math.sin(polar_angle);
    cos_azimuthal = math.cos(azimuthal_angle);
    sin_azimuthal = math.sin(azimuthal_angle);

    return [
    cos_polar * cos_azimuthal,
    cos_polar * sin_azimuthal,
    sin_polar]



    class SquareGLWidget(QOpenGLWidget):
    def __init__(self, parent=None):
    super().__init__(parent)
    self.shaderProgram = None
    self.u_base_colour = [1.0, 0.0, 1.0]
    self.u_globe_position = [0.0, 0.0, 0.0]
    self.surface_focus_lat_lon = [0.0, 0.0]
    self.u_globe_radius = 6378 # Earth, km

    def initializeGL(self):
    self.shaderProgram = QOpenGLShaderProgram()

    if not self.shaderProgram.addShaderFromSourceCode(QOpenGLShader.Vertex, VERTEX_SHADER):
    print("Vertex shader compilation failed:", self.shaderProgram.log())
    return

    if not self.shaderProgram.addShaderFromSourceCode(QOpenGLShader.Fragment, FRAGMENT_SHADER):
    print("Fragment shader compilation failed:", self.shaderProgram.log())
    return

    if not self.shaderProgram.link():
    print("Shader program linking failed:", self.shaderProgram.log())
    return

    print("Shader program linked successfully")

    self.vao = QOpenGLVertexArrayObject()

    if not self.vao.create():
    print("Could not create VAO")
    return

    self.vao.bind()

    self.vbo = QOpenGLBuffer()

    if not self.vbo.create():
    print("Could not create VAO")
    return

    self.vbo.bind()

    vertices = [-1.0, -1.0,
    1.0, -1.0,
    -1.0, 1.0,
    1.0, 1.0]

    data = numpy.array(vertices, dtype=numpy.float32)

    self.vbo.allocate(data, data.nbytes)

    self.shaderProgram.bind()

    attr_loc = self.shaderProgram.attributeLocation("v_position")
    print (f"{attr_loc=}") # is 0
    self.shaderProgram.enableAttributeArray(attr_loc)
    self.shaderProgram.setAttributeBuffer(attr_loc, GL_FLOAT, 0, 2, 2 * sizeof(GLfloat))

    self.shaderProgram.release()
    self.vbo.release()
    self.vao.release()

    glEnable(GL_DEPTH_TEST)
    glClearColor(0.5, 0.0, 0.5, 1.0)

    def paintGL(self):

    if not QOpenGLContext.currentContext():
    print ("No currentContext")

    if not self.context():
    print ("Not self.context")

    if not self.context().isValid():
    print("Invalid self.context")
    return

    surface_focus = sphericalToCartesian(*self.surface_focus_lat_lon) # has unit length

    right_unit = numpy.linalg.cross([0.0,1.0,0.0], surface_focus)
    up_unit = numpy.linalg.cross(surface_focus, right_unit)

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    if not self.shaderProgram.isLinked():
    print ("paintGL: shader is not linked")

    if not self.shaderProgram.bind():
    print ("paintGL could not bind shader")

    self.shaderProgram.setUniformValue("u_base_colour", *self.u_base_colour)
    self.shaderProgram.setUniformValue("u_globe_position", *self.u_globe_position)
    self.shaderProgram.setUniformValue("u_surface_focus", *surface_focus)
    self.shaderProgram.setUniformValue("u_right_unit", *right_unit)
    self.shaderProgram.setUniformValue("u_up_unit", *up_unit)
    self.shaderProgram.setUniformValue("u_globe_radius", self.u_globe_radius)

    if not self.vao.bind():
    print ("paintGL could not bind vao "+ str(glGetError())) # 1282
    self.shaderProgram.release()
    return
    else:
    print ("paintGL could bind vao")

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)

    self.vao.release()
    self.shaderProgram.release()

    def resizeGL(self, w, h):
    side = min(w, h)
    x = (w - side) // 2
    y = (h - side) // 2
    glViewport(x, y, side, side)


    What am I doing wrong?

    Continue reading...

Compartilhe esta Página