opengl文本标签的技术和速度期望

时间:2011-05-05 23:01:37

标签: performance opengl rendering texturing labeling

我正在使用opengl(固定功能管道),我可能会绘制数十万个点,并用文本标签标记每个点。这个问题是关于我是否以合理的方式做到这一点,以及我在速度方面的期望。

通过为每个字符创建纹理坐标矩形来绘制文本标签,并使用小字体位图对矩形进行纹理化(每个字符在纹理中约为5x13像素)。

在一个测试文件中,我有大约158,000个点,以经度和纬度给出,所以这个lon / lat空间是我的“模型空间”。我读取了那些点,并为它们创建了一个opengl顶点缓冲区。然后每个点获得一个通常为三个或四个字符长的标签。所以,让我们说平均3.5个字符。点以屏幕坐标(正投影模式)绘制。对于每个角色,我创建一个纹理坐标rect来抓取角色的右边像素,然后在屏幕坐标中创建一个矩形,将在其中绘制角色。这两组rects都放入顶点缓冲区。因此,绘图的158k * 3.5 * 8 = 440万点,或880万个坐标数,以及纹理坐标的880万个数字。

当需要渲染时,我需要(至少我相信这是唯一的方法)更新所有绘图的屏幕坐标,以匹配所有模型点的当前屏幕位置。因此,对于158个模型点中的每一个,我必须从该点的模型(世界)坐标计算投影(屏幕)坐标,然后为该点设置三个或四个角色中的每一个的四个角坐标。所以基本上我在每个渲染上更新所有880万个数字。每次渲染需要大约0.3秒来更新这些数字。

问题第一:听起来这是处理opengl中点标记的正确/必要方法吗?如果有某种方式可以说“自动渲染到这组矩形点,它们与这个模型点相关联,但被视为投影模型点的屏幕偏移”,这将是理想的选择。然后,我不必更新每个渲染的绘制rects。但是没有这样的事情,对吧?

问题编号二:除了在每次渲染之前更新所有屏幕显示的时间之外,当屏幕上显示所有158k标签时,渲染本身大约需要1秒钟(这显然不是一个有用的用户体验,但是我只是想了解这里的速度)。当我放大,并且在屏幕上实际绘制的点/标签越来越少时,渲染时间按比例缩短。我只想了解一下,在我的普通/现代笔记本电脑上使用普通/现代GPU,完整的一秒钟听起来像是一个合理的时间来渲染那些158k * 3.5 = 553k纹理四边形。我知道人们谈论“数以百万计的三角形”并不是一个障碍,但我对纹理感到疑惑,我所看到的速度是合理/预期的。

感谢您的帮助。

在下面添加了代码。请注意,这是我想要删除的每个渲染上的position_labels调用。

SCREEN_VERTEX_DTYPE = np.dtype(
    [ ( "x_lb", np.float32 ), ( "y_lb", np.float32 ),
      ( "x_lt", np.float32 ), ( "y_lt", np.float32 ),
      ( "x_rt", np.float32 ), ( "y_rt", np.float32 ),
      ( "x_rb", np.float32 ), ( "y_rb", np.float32 ) ]
)
TEXTURE_COORDINATE_DTYPE = np.dtype(
    [ ( "u_lb", np.float32 ), ( "v_lb", np.float32 ),
      ( "u_lt", np.float32 ), ( "v_lt", np.float32 ),
      ( "u_rt", np.float32 ), ( "v_rt", np.float32 ),
      ( "u_rb", np.float32 ), ( "v_rb", np.float32 ) ]
)

# screen_vertex_data is numpy array of SCREEN_VERTEX_DTYPE
# texcoord_data is numpy array of TEXTURE_COORDINATE_DTYPE
# not shown: code to fill initial vals of screen_vertex_data and texcoord_data
self.vbo_screen_vertexes = gl_vbo.VBO( screen_vertex_data )
self.vbo_texture_coordinates = gl_vbo.VBO( texcoord_data )

...

# then on each render:

def render( self ):
    self.position_labels()

    gl.glEnable( gl.GL_TEXTURE_2D )
    gl.glBindTexture( gl.GL_TEXTURE_2D, self.font_texture )

    gl.glEnableClientState( gl.GL_VERTEX_ARRAY )
    self.vbo_screen_vertexes.bind()
    gl.glVertexPointer( 2, gl.GL_FLOAT, 0, None )

    gl.glEnableClientState( gl.GL_TEXTURE_COORD_ARRAY )
    self.vbo_texture_coordinates.bind()
    gl.glTexCoordPointer( 2, gl.GL_FLOAT, 0, None )

    # set up an orthogonal projection
    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.glPushMatrix()
    gl.glLoadIdentity()
    window_size = application.GetClientSize()
    gl.glOrtho(0, window_size[ 0 ], 0, window_size[ 1 ], -1, 1)
    gl.glMatrixMode(gl.GL_MODELVIEW)
    gl.glPushMatrix()
    gl.glLoadIdentity()

    vertex_count = np.alen( self.character_coordinates_data ) * 4
    gl.glDrawArrays( gl.GL_QUADS, 0, vertex_count )

    # undo the orthogonal projection
    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.glPopMatrix()
    gl.glMatrixMode(gl.GL_MODELVIEW)
    gl.glPopMatrix()

    self.vbo_texture_coordinates.unbind()
    gl.glDisableClientState( gl.GL_TEXTURE_COORD_ARRAY )

    self.vbo_screen_vertexes.unbind()
    gl.glDisableClientState( gl.GL_VERTEX_ARRAY )

    gl.glBindTexture( gl.GL_TEXTURE_2D, 0 )
    gl.glDisable( gl.GL_TEXTURE_2D )

def position_labels( self ):
    window_size = application.GetClientSize()
    world_size = ( rect.width( application.world_rect ), rect.height( application.world_rect ) )

    world_to_screen_factor_x = float( window_size[ 0 ] ) / float( world_size[ 0 ] )
    world_to_screen_factor_y = float( window_size[ 1 ] ) / float( world_size[ 1 ] )

    wr_lower_left = application.world_rect[ 0 ]
    shift_pixels_x = ( wr_lower_left[ 0 ] + 180.0 ) * world_to_screen_factor_x
    shift_pixels_y = ( wr_lower_left[ 1 ] + 90.0 ) * world_to_screen_factor_y

    # map to screen coordinates
    self.character_coordinates_data.screen_x = ( self.character_coordinates_data.world_x + 180.0 ) * world_to_screen_factor_x - shift_pixels_x
    self.character_coordinates_data.screen_y = ( self.character_coordinates_data.world_y + 90.0 ) * world_to_screen_factor_y - shift_pixels_y

    screen_vertex_data = self.vbo_screen_vertexes.data

    screen_vertex_data.x_lb = self.character_coordinates_data.screen_x + self.character_coordinates_data.screen_offset_x
    screen_vertex_data.y_lb = self.character_coordinates_data.screen_y + self.character_coordinates_data.screen_offset_y - self.character_coordinates_data.screen_height
    screen_vertex_data.x_lt = screen_vertex_data.x_lb
    screen_vertex_data.y_lt = screen_vertex_data.y_lb + self.character_coordinates_data.screen_height
    screen_vertex_data.x_rt = screen_vertex_data.x_lb + self.character_coordinates_data.screen_width
    screen_vertex_data.y_rt = screen_vertex_data.y_lb + self.character_coordinates_data.screen_height
    screen_vertex_data.x_rb = screen_vertex_data.x_lb + self.character_coordinates_data.screen_width
    screen_vertex_data.y_rb = screen_vertex_data.y_lb

    self.vbo_screen_vertexes[ : np.alen( screen_vertex_data ) ] = screen_vertex_data

1 个答案:

答案 0 :(得分:0)

投影模式和屏幕坐标是两个截然不同的东西。您可以确定选择投影参数,以便OpenGL单元匹配屏幕像素,但这不是必需的。只是为了澄清。

问一个问题:OpenGL只是一个绘图API,没有更高级别的功能。所以,是的,让这些家伙保持同步是你的负担。幸运的是,你只需要做一次数学运算。缩放,平移,旋转等都可以通过操纵变换矩阵来完成;但是视图中的每个更改都需要完全重绘。

质疑二:这一切归结为填充而不是处理不可见的东西。一个有趣的事情是,虽然GPU可以在一秒钟内处理数百万个三角形,但如果以易于消化的块状态提供服务,它们会做得最好,即如果它分批进入,则全部适合缓存。我发现,批量1000到3000个顶点的效果最好。此外,一些影响来自所访问纹理的总大小,而不仅仅是您实际访问的部分。然而,对于未经优化的绘图方法,您的数字听起来合理。