【问题标题】:In OpenGL 3.3, is there any more efficient and correct way of drawing a point?在 OpenGL 3.3 中,有没有更有效和正确的绘制点的方法?
【发布时间】:2022-03-28 21:04:19
【问题描述】:

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

颜色和大小通常不会变化。

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

绘图实用且看似高效,但问题是我做得对吗?

【问题讨论】:

    标签: opengl pyopengl


    【解决方案1】:

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

    【讨论】:

    • 好主意,我将编辑代码,按属性更改 uniform 并放置一个函数,该函数接受一个包含不同点的所有坐标的数组,以绘制一个或多个
    【解决方案2】:

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

    有很多关于这种方法的教程。这里以one 为例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-30
      • 2020-08-19
      相关资源
      最近更新 更多