Я использую opengl (конвейер с фиксированной функцией) и потенциально рисую сотни тысяч точек и помечаю каждую текстовой меткой. Этот вопрос о том, делаю ли я это разумно и чего я могу ожидать с точки зрения скорости.
Текстовые метки рисуются путем создания прямоугольника с координатами текстуры для каждого символа и текстурирования прямоугольников с использованием растрового изображения мелкого шрифта (каждый символ имеет размер примерно 5x13 пикселей в текстуре).
В тестовом файле у меня есть около 158 000 точек, заданных по долготе и широте, поэтому это пространство долгота/широта является моим «модельным пространством». Я читаю точки и создаю для них буфер вершин opengl. Затем каждая точка получает метку, которая обычно состоит из трех или четырех символов. Итак, скажем, 3,5 символа в среднем. Точки рисуются в экранных координатах (режим ортопроекции). Для каждого персонажа я создаю прямоугольник координат текстуры, чтобы получить правильные пиксели для персонажа, и я создаю прямоугольник в экранных координатах, в который будет нарисован персонаж. Каждый из этих двух наборов прямоугольников помещается в буфер вершин. Итак, 158k * 3,5 * 8 = 4,4 миллиона точек, или 8,8 миллиона отдельных чисел координат для прямоугольников чертежа, а также 8,8 миллионов чисел для координат текстуры.
Когда приходит время рендеринга, мне нужно (по крайней мере, я считаю, что это единственный способ сделать это) обновить экранные координаты всех этих прямоугольников рисования, чтобы они соответствовали текущему положению на экране всех точек модели. Это означает, что для каждой из 158 точек модели я должен вычислить спроецированные (экранные) координаты из модельных (мировых) координат точки, а затем установить четыре угловых координаты для каждого из трех или четырех символов прямоугольников для точки . Так что в основном я обновляю все 8,8 миллиона этих чисел при каждом рендере. Для обновления этих чисел требуется около 0,3 секунды на рендеринг.
ВОПРОС НОМЕР ОДИН: Звучит ли это как правильный/необходимый способ обработки маркировки точек в opengl? Было бы идеально, если бы был какой-то способ сказать: «автоматически визуализировать в этот набор прямоугольных точек, которые связаны с этой точкой модели, но обрабатываются как смещения экрана от проецируемой точки модели». Тогда мне не пришлось бы обновлять прямоугольники отрисовки при каждом рендеринге. Но ведь такого нет?
ВОПРОС НОМЕР ВТОРОЙ: Помимо времени, необходимого для обновления всех этих прямоугольников экрана перед каждым рендерингом, сам рендеринг занимает около 1 полной секунды, когда на экране отображаются все 158 тыс. просто пытаюсь понять скорости здесь). По мере того, как я увеличиваю масштаб и на экране отображается все меньше и меньше точек/меток, время рендеринга становится пропорционально короче. Я просто пытаюсь понять, звучит ли на моем среднем/современном ноутбуке со средним/современным графическим процессором эта полная секунда как разумное количество времени для рендеринга этих 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