【问题标题】:running into roadblock with opengl function glBeginTransformFeedback使用opengl函数glBeginTransformFeedback遇到障碍
【发布时间】:2019-06-29 09:04:02
【问题描述】:

所以我在使用 opengl 函数 glBeginTransformFeedback 时遇到问题,当我取消注释这些行时,会发生错误。它说 1282 无效操作,虽然这很模糊。

我的问题是如何处理源代码以取消注释这三行:

#glBeginTransformFeedback(GL_POINTS)
#glDrawArrays(GL_POINTS, 0, POINTS_TOTAL)
#glEndTransformFeedback()

一个更广泛的问题是关于如何让它正确呈现的任何建议?

更新:在 Rabbid76 优秀代码的帮助下,程序现在可以运行了!!!非常感谢!

成功!!!!当前输出与预期输出相同:

支持文件:springmass_support.zip

源代码:

#!/usr/bin/python3

import sys
import time
import ctypes

fullscreen = True

sys.path.append("./shared")

from sbmloader import SBMObject    # location of sbm file format loader

from sbmath import m3dDegToRad, m3dRadToDeg, m3dTranslateMatrix44, m3dRotationMatrix44, m3dMultiply, m3dOrtho, m3dPerspective, rotation_matrix, translate, m3dScaleMatrix44, \
    scale, m3dLookAt, normalize

try:
    from OpenGL.GLUT import *
    from OpenGL.GL import *
    from OpenGL.GLU import *
    from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, glBindVertexArray
except:
    print ('''
    ERROR: PyOpenGL not installed properly.
        ''')
    sys.exit()

from array import array
from enum import Enum

import numpy as np 

import glm


from math import cos, sin 
identityMatrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]

render_program = GLuint(0)

myobject = SBMObject()

POSITION_A = 0
POSITION_B = 1
VELOCITY_A = 2
VELOCITY_B = 3
CONNECTION = 4

POINTS_X            = 50
POINTS_Y            = 50
POINTS_TOTAL        = POINTS_X * POINTS_Y
CONNECTIONS_TOTAL = (POINTS_X - 1) * POINTS_Y + (POINTS_Y - 1) * POINTS_X


m_vao = [GLuint(0) for _ in range(2)]
m_vbo = [GLuint(0) for _ in range(5)]

m_index_buffer = GLuint(0)
m_pos_tbo = [GLuint(0), GLuint(0)]
m_update_program = GLuint(0)
m_render_program = GLuint(0)
m_C_loc = GLuint(0)
m_iteration_index = 0

draw_points = True
draw_lines = True
iterations_per_frame = 16


def shader_load(filename, shader_type):

    result = GLuint(0)

    with open ( filename, "rb") as data:

        result = glCreateShader(shader_type)

        glShaderSource(result, data.read() )

    glCompileShader(result)

    return result


def load_shaders():
    global m_update_program
    global m_render_program

    vs = GLuint(0)
    fs = GLuint(0)
    buffer = ''

    vs = shader_load("update.vs.glsl", GL_VERTEX_SHADER)

    if (m_update_program):
        glDeleteProgram(m_update_program)

    m_update_program = glCreateProgram()
    glAttachShader(m_update_program, vs)


    # static const char * tf_varyings[] = 
    # {
        # "tf_position_mass",
        # "tf_velocity"
    # }


    # tricky to convert string array to string pointer

    tf_varyings = ["tf_position_mass", "tf_velocity"]

    # Prepare ctypes data containing the list tf_varyings of strings
    array_type = ctypes.c_char_p * len(tf_varyings)
    buff = array_type()
    for i, e in enumerate(tf_varyings):
        buff[i] = e.encode()
                                                                            #       ctypes.c_char
    tf_varyings_chrpp = ctypes.cast(ctypes.pointer(buff), ctypes.POINTER(ctypes.POINTER(GLchar)))


    glTransformFeedbackVaryings(m_update_program, 2, tf_varyings_chrpp, GL_SEPARATE_ATTRIBS)

    glLinkProgram(m_update_program)

    glGetShaderInfoLog(vs)
    glGetProgramInfoLog(m_update_program)

    glDeleteShader(vs)

    vs = shader_load("render.vs.glsl", GL_VERTEX_SHADER)
    fs = shader_load("render.fs.glsl", GL_FRAGMENT_SHADER)

    if (m_render_program):
        glDeleteProgram(m_render_program)
    m_render_program = glCreateProgram()
    glAttachShader(m_render_program, vs)
    glAttachShader(m_render_program, fs)

    glLinkProgram(m_render_program)



class Scene:

    def __init__(self, width, height):
        global m_vao
        global m_vbo

        i = 0
        j = 0

        load_shaders()


        initial_positions = [glm.vec4() for _ in range(POINTS_TOTAL)]
        initial_velocities = [glm.vec3() for _ in range(POINTS_TOTAL)]
        connection_vectors = [glm.ivec3() for _ in range(POINTS_TOTAL)]


        n=0
        for j in range(0, POINTS_Y):
            fj = float(j) / float(POINTS_Y)

            for i in range(0, POINTS_X):

                fi = float(i) / float(POINTS_X)

                initial_positions[n] = glm.vec4((fi - 0.5) * float(POINTS_X), (fj - 0.5) * float(POINTS_Y), 0.6 * sin(fi) * cos(fj), 1.0)
                initial_velocities[n] = glm.vec3(0.0)
                connection_vectors[n] = glm.ivec4(-1)

                if (j != (POINTS_Y - 1)):

                    if (i != 0):
                        connection_vectors[n][0] = n - 1

                    if (j != 0):
                        connection_vectors[n][1] = n - POINTS_X

                    if (i != (POINTS_X - 1)):
                        connection_vectors[n][2] = n + 1

                    if (j != (POINTS_Y - 1)):
                        connection_vectors[n][3] = n + POINTS_X
                n+=1


        for i in range(0, 2):
            glGenVertexArrays(1, m_vao[i])

        for i in range(0, 5):
            glGenBuffers(i+1, m_vbo[i])

        for i in range(0, 2):

            glBindVertexArray(m_vao[i])

            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[POSITION_A + i])


            # POSITION_A
            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[POSITION_A + i])

            ar_position = np.empty([POINTS_TOTAL, 4], dtype='float32')
            for j, e in enumerate(initial_positions):
                ar_position[j] = e

            glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.vec4()), ar_position, GL_DYNAMIC_COPY)
            glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
            glEnableVertexAttribArray(0)

            # VELOCITY_A
            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[VELOCITY_A + i])

            ar_velocities = np.empty([POINTS_TOTAL, 3], dtype='float32')
            for j, e in enumerate(initial_velocities):
                ar_velocities[j] = e

            glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.vec3()), ar_velocities, GL_DYNAMIC_COPY)
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, None)
            glEnableVertexAttribArray(1)

            # CONNECTION
            glBindBuffer(GL_ARRAY_BUFFER, m_vbo[CONNECTION])

            ar_connection = np.empty([POINTS_TOTAL, 4], dtype='uint32')
            for j, e in enumerate(connection_vectors):
                ar_connection[j] = e

            glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.ivec4()), ar_connection, GL_STATIC_DRAW)
            glVertexAttribIPointer(2, 4, GL_INT, 0, None)
            glEnableVertexAttribArray(2)

        glGenTextures(2, m_pos_tbo)
        glBindTexture(GL_TEXTURE_BUFFER, m_pos_tbo[0])
        glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_vbo[POSITION_A])
        glBindTexture(GL_TEXTURE_BUFFER, m_pos_tbo[1])
        glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_vbo[POSITION_B])

        lines = (POINTS_X - 1) * POINTS_Y + (POINTS_Y - 1) * POINTS_X

        glGenBuffers(1, m_index_buffer)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, lines * 2 * ctypes.sizeof(ctypes.c_int), None, GL_STATIC_DRAW)

        e = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, lines * 2 * ctypes.sizeof(ctypes.c_int), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)

        int_array = (ctypes.c_int * (4 * lines * 2)).from_address(e) 
        n = 0
        for j in range(0, POINTS_Y):
            for i in range(0, POINTS_X - 1):
                int_array[n] = i + j * POINTS_X
                n+=1

                int_array[n] = 1 + i + j * POINTS_X
                n+=1

        for i in range(0, POINTS_X):

            for j in range(0, POINTS_Y - 1):
                int_array[n] = i + j * POINTS_X
                n+=1

                int_array[n] = POINTS_X + i + j * POINTS_X
                n+=1


        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER)


    def display(self):
        global m_iteration_index

        glUseProgram(m_update_program)

        glEnable(GL_RASTERIZER_DISCARD)


        for i in range( iterations_per_frame, 0, -1):

            glBindVertexArray(m_vao[m_iteration_index & 1])
            glBindTexture(GL_TEXTURE_BUFFER, m_pos_tbo[m_iteration_index & 1])
            m_iteration_index +=1
            glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_vbo[POSITION_A + (m_iteration_index & 1)])
            glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_vbo[VELOCITY_A + (m_iteration_index & 1)])

            glBeginTransformFeedback(GL_POINTS)
            glDrawArrays(GL_POINTS, 0, POINTS_TOTAL)
            glEndTransformFeedback()

        glDisable(GL_RASTERIZER_DISCARD)

        black = [ 0.0, 0.0, 0.0, 0.0 ]

        glViewport(0, 0, self.width, self.height)
        glClearBufferfv(GL_COLOR, 0, black)

        glUseProgram(m_render_program)

        if (draw_points):
            glPointSize(4.0)
            glDrawArrays(GL_POINTS, 0, POINTS_TOTAL)

        if (draw_lines):
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer)
            glDrawElements(GL_LINES, CONNECTIONS_TOTAL * 2, GL_UNSIGNED_INT, None)

        glutSwapBuffers()

    def reshape(self, width, height):
        self.width = width
        self.height = height

    def keyboard(self, key, x, y ):
        global fullscreen

        print ('key:' , key)
        if key == b'\x1b': # ESC
            sys.exit()

        elif key == b'f' or key == b'F': #fullscreen toggle

            if (fullscreen == True):
                glutReshapeWindow(512, 512)
                glutPositionWindow(int((1360/2)-(512/2)), int((768/2)-(512/2)))
                fullscreen = False
            else:
                glutFullScreen()
                fullscreen = True

        print('done')

    def init(self):
        pass

    def timer(self, blah):

        glutPostRedisplay()
        glutTimerFunc( int(1/60), self.timer, 0)
        time.sleep(1/60.0)


if __name__ == '__main__':
    start = time.time()

    glutInit()


    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)

    glutInitWindowSize(512, 512)

    w1 = glutCreateWindow('OpenGL SuperBible - Spring-Mass Simulator')
    glutInitWindowPosition(int((1360/2)-(512/2)), int((768/2)-(512/2)))

    fullscreen = False
    many_cubes = False
    #glutFullScreen()

    scene = Scene(512,512)
    glutReshapeFunc(scene.reshape)
    glutDisplayFunc(scene.display)
    glutKeyboardFunc(scene.keyboard)

    glutIdleFunc(scene.display)
    #glutTimerFunc( int(1/60), scene.timer, 0)

    scene.init()

    glutMainLoop()

我从 Superbible OpenGL 7ed 的第 7 章将此程序移植到 python。

移植自:springmass.cpp

【问题讨论】:

    标签: python python-3.x opengl glut opengl-3


    【解决方案1】:

    sys.getsizeof() 不返回对象所指的缓冲区大小,而是返回对象的大小。

    如果您想获得由ctypes 对象管理的缓冲区的大小,那么您需要ctypes.sizeof。例如:

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, lines * 2 * sys.getsizeof(int), None, GL_STATIC_DRAW)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, lines * 2 * ctypes.sizeof(ctypes.c_int), None, GL_STATIC_DRAW)

    PyGLM alos 提供了一个glm.sizeof() 函数。例如:

    glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * sys.getsizeof(glm.vec4()), ar, GL_DYNAMIC_COPY)
    glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.vec4), ar, GL_DYNAMIC_COPY)

    NumPy 提供.itmesize 属性。例如:

    np.dtype('float32').itemsize
    

    一行代码就可以生成一个list的对象:

    initial_positions = [glm.vec4() for _ in range(POINTS_TOTAL)]
    initial_velocities = [glm.vec3() for _ in range(POINTS_TOTAL)]
    connection_vectors = [glm.ivec3() for _ in range(POINTS_TOTAL)]
    

    要从列表中生成一个数组,您可以通过numpy.empty 创建一个空数组。
    分别创建一个形状为 ([POINTS_TOTAL, 4]) 的二维数组 ([POINTS_TOTAL, 3])。 glm 向量对象可以循环分配。
    注意,integral 属性的数组类型必须是 'uint32' 而不是 float32

    # POSITION_A
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo[POSITION_A + i])
    
    ar = np.empty([POINTS_TOTAL, 4], dtype='float32')
    for j, e in enumerate(initial_positions):
        ar[j] = e
    
    glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.vec4), ar, GL_DYNAMIC_COPY)
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
    glEnableVertexAttribArray(0)
    
    # VELOCITY_A
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo[VELOCITY_A + i])
    
    ar = np.empty([POINTS_TOTAL, 3], dtype='float32')
    for j, e in enumerate(initial_velocities):
        ar[j] = e
    
    glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.vec3), ar, GL_DYNAMIC_COPY)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, None)
    glEnableVertexAttribArray(1)
    
    # CONNECTION
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo[CONNECTION])
    
    ar = np.empty([POINTS_TOTAL, 4], dtype='uint32')
    for j, e in enumerate(connection_vectors):
        ar[j] = e
    
    glBufferData(GL_ARRAY_BUFFER, POINTS_TOTAL * glm.sizeof(glm.ivec4), ar, GL_STATIC_DRAW)
    glVertexAttribIPointer(2, 4, GL_INT, 0, None)
    glEnableVertexAttribArray(2)
    

    说明

    int_array = ((ctypes.c_int * 4) * lines * 2).from_address(e) 
    

    将生成一个 3 维数组。使用*- 运算符一次可以生成一个二维数组,其中包含所有元素的大小(例如(ctypes.c_int * (4 * lines * 2))):

    int_array = (ctypes.c_int * (4 * lines * 2)).from_address(e) 
    n = 0
    for j in range(0, POINTS_Y):
        for i in range(0, POINTS_X - 1):
            int_array[n] = i + j * POINTS_X
            n+=1
    
            int_array[n] = 1 + i + j * POINTS_X
            n+=1
    
    for i in range(0, POINTS_X):
    
        for j in range(0, POINTS_Y - 1):
            int_array[n] = i + j * POINTS_X
            n+=1
    
            int_array[n] = POINTS_X + i + j * POINTS_X
            n+=1
    

    另外还有一个问题是当你生成顶点数组对象和缓冲区对象时。

    为对象创建列表:

    m_vao = [GLuint(0) for _ in range(2)]
    m_vbo = [GLuint(0) for _ in range(5)]
    

    for 循环中创建 1 个单个对象:

    for i in range(0, 5):
        glGenBuffers(1, m_vbo[i])
    
    for i in range(0, 2):
        glGenVertexArrays(1, m_vao[i])
    

    终于可以使用glBeginTransformFeedback了:

    for i in range( iterations_per_frame, 0, -1):
    
        glBindVertexArray(m_vao[m_iteration_index & 1])
        glBindTexture(GL_TEXTURE_BUFFER, m_pos_tbo[m_iteration_index & 1])
        m_iteration_index +=1
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_vbo[POSITION_A + (m_iteration_index & 1)])
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_vbo[VELOCITY_A + (m_iteration_index & 1)])
    
        glBeginTransformFeedback(GL_POINTS)
        glDrawArrays(GL_POINTS, 0, POINTS_TOTAL)
        glEndTransformFeedback()
    

    我更改了iterations_per_frame = 1,我跳过了glutIdleFunc,但激活了glutIdleFunc

    class Scene:
    
       # [...]
    
       def timer(self, blah):
    
            glutPostRedisplay()
            glutTimerFunc( 50, self.timer, 0)
    
    if __name__ == '__main__':
    
        # [...]
    
        #glutIdleFunc(scene.display)
        glutTimerFunc( 1000, scene.timer, 0) 
    

    得到以下结果:

    【讨论】:

    • 我只能用连接初始化一个班轮,另外两个,initial_positionsinitial_velocities,正在seg。错误使用一个衬垫初始化ar 变量。不知道为什么。除了用np.empty 初始化的小东西之外,非常棒的代码,非常感谢您查看并修复它,太棒了!!!
    • 原来我无法用变量ar 的一个衬垫初始化这三个变量中的任何一个。似乎np.array 出于某种原因得到GC 是我的猜测。因此,使用np.empty 进行初始化是可行的方法。我更新了源代码。而且它成功了,程序正在运行,没有问题并且稳定。非常感谢 Rabbid76,你的帮助和洞察力太棒了!!!
    猜你喜欢
    • 1970-01-01
    • 2011-11-09
    • 2015-08-31
    • 1970-01-01
    • 2022-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多