我正在使用 opengl(固定功能管道),我正在绘制可能数十万个点,并用文本标签标记每个点。这个问题是关于我是否以合理的方式这样做,以及在速度方面我可以期待什么。
通过为每个字符创建一个纹理坐标矩形来绘制文本标签,并使用一个小的字体位图对矩形进行纹理化(每个字符在纹理中约为 5x13 像素)。
在一个测试文件中,我有大约 158,000 个点,以经度和纬度给出,所以这个 lon/lat 空间是我的“模型空间”。我读取了这些点,并为它们创建了一个 opengl 顶点缓冲区。然后每个点都会得到一个标签,通常是三个或四个字符长。所以,假设平均 3.5 个字符。这些点以屏幕坐标绘制(正射投影模式)。对于每个角色,我创建一个纹理坐标 rect 以获取角色的正确像素,并在屏幕坐标中创建一个矩形,角色将被绘制到该矩形中。这两组矩形分别被放入一个顶点缓冲区。所以这是 158k * 3.5 * 8 = 440 万个点,或 880 万个用于绘图矩形的单独坐标数,还有 880 万个用于纹理坐标的数字。
当需要渲染时,我需要(至少我相信这是唯一的方法)更新所有这些绘图矩形的屏幕坐标,以匹配所有模型点的当前屏幕位置。所以这意味着对于 158 个模型点中的每一个,我必须从该点的模型(世界)坐标计算投影(屏幕)坐标,然后为该点的三个或四个字符矩形中的每一个设置四个角坐标. 所以基本上我会在每次渲染时更新所有 880 万个这些数字。每次渲染大约需要 0.3 秒来更新这些数字。
问题一:这听起来像是在opengl中处理点标记的正确/必要方式吗?如果有某种方式说“自动渲染到这组矩形点中,这将是理想的,这些矩形点链接到这个模型点但被视为与投影模型点的屏幕偏移”。然后我就不必在每个渲染上更新绘制矩形。但是没有这样的事情,对吧?
问题二:除了在每次渲染之前更新所有这些屏幕矩形的时间之外,当所有 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