Техника и скорость ожидания для текстовой маркировки OpenGL - PullRequest
1 голос
/ 06 мая 2011

Я использую opengl (конвейер с фиксированной функцией), и я рисую потенциально сотни тысяч точек и помечаю каждую текстовой меткой.Вопрос в том, правильно ли я это делаю, и чего я могу ожидать в плане скорости.

Текстовые метки рисуются путем создания текстурного координатного прямоугольника для каждого символа и текстурирования прямоугольников.используя растровое изображение небольшого шрифта (каждый символ имеет около 5x13 пикселей в текстуре).

В тестовом файле у меня есть около 158 000 точек, заданных по долготе и широте, поэтому это пространство lon / lat мое »пространство".Я читаю точки в них и создаю для них буфер вершин opengl.Затем каждая точка получает метку, которая обычно состоит из трех или четырех символов.Итак, скажем, 3,5 символа в среднем.Точки рисуются в экранных координатах (режим ортопроекции).Для каждого символа я создаю прямоугольник координат текстуры, чтобы получить правильные пиксели для символа, и я создаю прямоугольник в координатах экрана, в который будет нарисован символ.Эти два набора ректов каждый помещаются в буфер вершин.Таким образом, это 158k * 3,5 * 8 = 4,4 миллиона точек, или 8,8 миллиона отдельных чисел координат для контуров чертежа, а также 8,8 миллиона чисел для координат текстуры.

Когда приходит время рендеринга, мне нужно (по крайней мере, я считаю, что это единственный способ сделать это) обновить координаты экрана всех этих чертежей, чтобы они соответствовали текущему положению экрана всех точек модели.Таким образом, это означает, что для каждой из 158 точек модели я должен вычислить проекционные (экранные) координаты из координат модели (мира) точки, а затем установить четыре угловые координаты для каждого из трех или четырех символьных рядов для точки.,В общем, я обновляю все 8,8 миллиона из этих чисел в каждом рендере.Обновление этих чисел занимает около 0,3 секунды.

ВОПРОС НОМЕР ОДИН: Похоже ли это на правильный / необходимый способ обработки маркировки точек в opengl?Было бы идеально, если бы был какой-то способ сказать: «автоматически визуализировать в этот набор прямоугольных точек, которые связаны с этой точкой модели, но рассматриваются как смещения экрана от проецируемой точки модели».Тогда мне не пришлось бы обновлять рецензии на каждый рендер.Но такой вещи не существует, верно?

ВОПРОС НОМЕР ВТОРОЙ: В дополнение к времени обновления всех этих экранных отрывков перед каждым рендерингом, сам рендеринг занимает около 1 полной секунды, когда все метки 158k отображаются наэкран (который, очевидно, не является полезным для пользователя, но я просто пытаюсь понять скорость здесь).При увеличении масштаба и уменьшении количества точек и меток на экране время визуализации становится пропорционально короче.Я просто пытаюсь понять, звучит ли на моем среднем / современном ноутбуке со средним / современным графическим процессором столько одной секунды, как разумное количество времени для рендеринга этих текстурированных квадратов 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 голосов
/ 06 мая 2011

Режим проекции и экранные координаты - это две разные вещи.Вы можете выбрать параметры проекции, чтобы единицы OpenGL соответствовали пикселям экрана, но в этом нет необходимости.Просто для пояснения.

На первый вопрос: OpenGL - это просто API для рисования, функциональности более высокого уровня нет.Так что да, это ваше бремя, чтобы держать этих парней в синхронизации.К счастью, вы должны сделать математику только один раз.Масштабирование, перемещение, вращение и т. Д. Могут быть выполнены путем манипулирования матрицами преобразования;однако каждое изменение в представлении требует полной перерисовки.

На вопрос два: все сводится к заполнению, а не к обработке того, что не видно.Одна интересная вещь заключается в том, что, хотя графические процессоры могут обрабатывать миллионы треугольников в секунду, они делают это лучше всего, если подают их легкоусвояемыми порциями, то есть, если они поступают партиями, все они помещаются в кеши.Я обнаружил, что от 1000 до 3000 вершин каждая работает лучше всего.Также некоторое влияние оказывает общий размер доступной текстуры, а не только часть, к которой вы фактически обращаетесь.Однако ваши цифры звучат разумно для неоптимизированного метода рисования.

...