在OpenGL 3.3中,有没有更有效、更正确的绘制点的方法?

shstlldc  于 2022-11-04  发布在  其他
关注(0)|答案(2)|浏览(138)

我打算绘制通常只改变屏幕上位置的点。
颜色和大小通常不会变化。
所以我用Python编写了这个类Point

class Point2D():
    _verts = None
    _vshader_code = '''
        #version 330

        in vec2 pos;

        uniform float size;

        void main() {
            gl_Position = vec4(pos, 0.0, 1.0);
            gl_PointSize = size;
        }
    '''
    _fshader_code = '''
        #version 330

        uniform vec4 col;

        void main() {
            gl_FragColor = col;
        }
    '''

    def __init__(self, size, col):
        ## CREATE PROGRAM/SHADER ##
        self.program = GL.glCreateProgram()

        self.shaders = [
            CreateShader(self._vshader_code, GL.GL_VERTEX_SHADER),
            CreateShader(self._fshader_code, GL.GL_FRAGMENT_SHADER)
        ]

        for shader in self.shaders:
            GL.glAttachShader(self.program, shader)

        GL.glLinkProgram(self.program)
        #CheckShaderError(self.program, GL.GL_LINK_STATUS, True, "Error: Program linking failed:")
        GL.glValidateProgram(self.program)
        #CheckShaderError(self.program, GL.GL_VALIDATE_STATUS, True, "Error: Program is invalid:")

        self.unif_size = GL.glGetUniformLocation(self.program, 'size')
        self.unif_col = GL.glGetUniformLocation(self.program, 'col')

        GL.glUseProgram(self.program)
        GL.glUniform1f(self.unif_size, size)
        GL.glUniform4fv(self.unif_col, 1, col)

        ## FLAGS ##
        #GL.glEnable(GL.GL_PROGRAM_POINT_SIZE);
        GL.glEnable(GL.GL_VERTEX_PROGRAM_POINT_SIZE)

    def bind_array(self, array):
        self._verts = array

        ## BIND BUFFER ##
        self.vertexArrayObject = GL.glGenVertexArrays(1)
        GL.glBindVertexArray(self.vertexArrayObject)

        self.buff = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.buff)

        GL.glBufferData(GL.GL_ARRAY_BUFFER, self._verts.nbytes, self._verts, GL.GL_STATIC_DRAW)

        self.attr_pos = GL.glGetAttribLocation(self.program, 'pos')

        GL.glEnableVertexAttribArray(0)
        GL.glVertexAttribPointer(self.attr_pos, 2, GL.GL_FLOAT, GL.GL_FALSE, 8, None)

        GL.glBindVertexArray(0)

    def update_size_and_color(self, size, col):
        #GL.glPointSize(size)
        GL.glUseProgram(self.program)

        GL.glUniform1f(self.unif_size, size)
        GL.glUniform4fv(self.unif_col, 1, col)

    def update_elem(self, index, value):
        GL.glUseProgram(self.program)

        self._verts[index] = value
        GL.glBindVertexArray(self.vertexArrayObject)
        GL.glBufferSubData(GL.GL_ARRAY_BUFFER, index * 8, 8, value)
        GL.glBindVertexArray(0)

    def Draw(self):
        GL.glUseProgram(self.program)

        GL.glBindVertexArray(self.vertexArrayObject)
        GL.glDrawArrays(GL.GL_POINTS, 0, len(self._verts))
        GL.glBindVertexArray(0)

    def __del__(self):
        try:
            #if the context is alive, you want to try and delete shader/program stuff manually
            #this could be triggered with e.g. `del Display`
            for shader in self.shaders:
                GL.glDetachShader(self.program, shader)
                GL.glDeleteShader(shader)
            GL.glDeleteProgram(self.program)
        except OpenGL.error.NullFunctionError as error:
            print("context already deleted my shader/program stuff!")

        GL.glDisable(GL.GL_VERTEX_PROGRAM_POINT_SIZE)

使用创建的点对象,我可以按如下方式绘制点:

point = Point2D(10.0, numpy.array((1.0, 0.0, 0.0, 1.0), 'f4'))
point.bind_array(numpy.zeros((2, 2), 'f4'))

## DRAW ##

point.update_elem(0, numpy.array((0.5, 0.0), 'f4'))
point.update_elem(1, numpy.array((-0.5, 0.0), 'f4'))
point.Draw()
(...code...)
point.update_elem(1, numpy.array((0.25, 0.25), 'f4'))
point.Draw()

这幅画很实用,看起来也很有效率,但问题是我做得对吗?

sg3maiej

sg3maiej1#

你这样做是可行的,也是合理的。如果你画了很多点(数千到数百万),您可能希望创建一个包含所有坐标的数组和另一个包含所有点的顶点属性的数组,并使用这些数组发出一个绘制调用。这将减少绘制调用的数量,这可能是一个性能限制因素。但是如果您只绘制几十到几百个代码,您可能不会注意到巨大的差异。与往常一样,分析代码并查看速度下降的地方比猜测要划算。

kdfy810k

kdfy810k2#

您应该使用instanced绘图。只加载一个点模型作为静态数据,并使用这些对象的位置数组(任何其他属性)。
有很多关于这个方法的教程。这里有一个例子。

相关问题