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

时间:2017-07-30 04:00:13

标签: opengl pyopengl

我打算画点通常只会改变屏幕上的位置。

颜色和大小通常不会有所不同。

所以我在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()

这幅画很实用,看似很有效,但问题是......:

- 我做得对吗?

2 个答案:

答案 0 :(得分:3)

你做这件事的方式是有效的,也是合理的。如果你要绘制大量的点(数千到数百万),你可能想要制作一个包含所有坐标的单个数组和另一个包含所有点的顶点属性的数组,并对这些数组发出单个绘图调用。这将减少绘制调用的数量,这可能是性能限制因素。但是,如果你只画几十到几百,你可能不会注意到一个巨大的差异。与往常一样,分析代码并查看减速的位置而不是猜测是值得的。

答案 1 :(得分:1)

您应该使用instanced绘图。只加载一个点的模型作为静态数据,并使用这些对象的位置数组(任何其他属性)。

有很多关于此方法的教程。例如,这里是one