2017-07-30 75 views
1

我打算畫點通常只改變屏幕上的位置。在OpenGL 3.3中,有沒有更有效率和正確的繪製點的方法?

顏色和大小通常不會有所不同。

所以我做了這個類Point在python:

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() 

該圖是實用的,看似高效,但問題是......:

- 我做對了嗎?

回答

3

你這樣做的方式將起作用並且是合理的。如果你正在繪製大量的點(數千到數百萬),你可能想要用所有座標和另一個具有所有點的頂點屬性的數組來製作單個數組,並對這些數組發出一次繪製調用。這將減少繪製調用的次數,這可能是性能限制因素。但是如果你只畫幾十到幾百,你可能不會注意到巨大的差異。與往常一樣,您需要分析您的代碼並查看減速的情況,而不是猜測。

+0

好主意,我將編輯代碼,通過屬性改變統一,並把一個數組與所有不同點的座標,繪製一個或幾個 –

1

您應該使用instanced繪圖。只加載一個點的模型作爲靜態數據,併爲這些對象使用位置數組(任何其他屬性)。

有很多關於這種方法的教程。例如,這裏是one