首页 > 解决方案 > 使用 PyOpenGL 和 PyQt5 制作 Sphere 的问题

问题描述

我正在尝试在 Python 中使用 OpenGL 制作球体,但屏幕中央只出现一个红点。我的代码如下

def paintGL(self):
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    try:
        glUseProgram(self.shader)
        glBindVertexArray(self.vao)
        glDrawArrays(GL_POINTS, 0, int(self.buff_size/3))
    finally:
        glBindVertexArray(0)
        glUseProgram(0)


def geometry(self):
    self.vao = glGenVertexArrays(1)
    self.vbo = glGenBuffers(1)

    lats = 180
    longs = 360
    r = 0.5

    data = []

    for i in range(lats):
        lat0 = np.pi * (-0.5 + (i - 1) / lats)
        z0 = np.sin(lat0)
        zr0 = np.cos(lat0)

        lat1 = np.pi * (-0.5 + i / lats)
        z1 = np.sin(lat1)
        zr1 = np.cos(lat1)

        for j in range(longs):
            lng = 2 * np.pi * (j - 1) / longs
            x_cord = np.cos(lng)
            y = np.sin(lng)

            data.extend([x_cord * zr0, y * zr0, z0])
            data.extend([r * x_cord * zr0, r * y * zr0, r * z0])
            data.extend([x_cord * zr1, y * zr1, z1])
            data.extend([r * x_cord * zr1, r * y * zr1, r * z1])

    data_input = np.array(data, dtype=np.float32)
    self.buff_size = len(data_input)
    vertex_size = int(data_input.nbytes / self.buff_size) * 3

    glUseProgram(self.shader)
    glBindVertexArray(self.vao)

    glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
    glBufferData(GL_ARRAY_BUFFER, data_input.nbytes, data_input, GL_DYNAMIC_DRAW)

    self.vertex_position = glGetAttribLocation(self.shader, 'position')
    glVertexAttribPointer(self.vertex_position, 3, GL_FLOAT, GL_FALSE, vertex_size, None)
    glEnableVertexAttribArray(self.vertex_position)

    glDisableVertexAttribArray(self.vertex_position)
    glBindBuffer(GL_ARRAY_BUFFER, 0)
    glBindVertexArray(0)
    glUseProgram(0)

我的程序的着色器是:

self.vertex_shader = shaders.compileShader(
    """
    #version 330
    in vec3 pos;
    uniform mat4 movement;
    void main() 
    { 
        gl_Position = movement * vec4(pos, 1.0);
    }
    """
    , GL_VERTEX_SHADER
)



self.fragment_shader = shaders.compileShader(
    """
    #version 330
    out vec4 gl_FragColor;
    void main() 
    {
        gl_FragColor = vec4(1.0,0.0,0.5,1.0);
    }
    """
    , GL_FRAGMENT_SHADER
)


self.shader = shaders.compileProgram(self.vertex_shader, self.fragment_shader)

我不知道我哪里有问题。我也尝试使用带有GL_ELEMENT_ARRAY_BUFFERglDrawElementsas 的索引,GL_QUAD_STRIP但没有成功。如果您知道我如何解决此问题,请分享。谢谢

标签: pythonpython-3.xopenglpyqt5pyopengl

解决方案


顶点属性的名称是 pos

in vec3 pos;

所以参数glGetAttribLocation必须是'pos'而不是'position':

self.vertex_position = glGetAttribLocation(self.shader, 'position')

self.vertex_position = glGetAttribLocation(self.shader, 'pos')

如果规范和启用状态存储在Vertex Array Object中。如果你glDisableVertexAttribArray(self.vertex_position),这个状态被存储到了self.vao。去掉它:

glBindVertexArray(self.vao)

glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, data_input.nbytes, data_input, GL_DYNAMIC_DRAW)

self.vertex_position = glGetAttribLocation(self.shader, 'pos')
glVertexAttribPointer(self.vertex_position, 3, GL_FLOAT, GL_FALSE, vertex_size, None)
glEnableVertexAttribArray(self.vertex_position)

#glDisableVertexAttribArray(self.vertex_position) # <--- DELETE
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)

默认情况下的矩阵 unfiorm 使用所有字段 0 进行初始化。

uniform mat4 movement;

如果您不需要制服,则将其取下。或者通过Identity matrix对其进行初始化。

glUseProgram(self.shader)

ident4x4 = np.identity(4, np.float32)
self.movement_loc = glGetUniformLocation(self.shader, 'movement')
glUniformMatrix4fv(self.movement_loc, 1, GL_FALSE, ident4x4)

或者,您可以使用视图和透视投影矩阵(self.width并且self.height是窗口的宽度和高度):

# projection matrix
aspect, ta, near, far = self.width/self.height, np.tan(np.radians(90.0) / 2), 0.1, 10
proj = np.matrix(((1/ta/aspect, 0, 0, 0), (0, 1/ta, 0, 0), (0, 0, -(far+near)/(far-near), -1), (0, 0, -2*far*near/(far-near), 0)), np.float32)

# view matrix
view = np.matrix(((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, -3, 1)), np.float32)

glUniformMatrix4fv(self.movement_loc, 1, GL_FALSE, view * proj)

推荐阅读