1

私はopengl(固定機能パイプライン)を使用しており、潜在的に数十万のポイントを描画し、それぞれにテキストラベルを付けています。この質問は、私が合理的な方法でこれを行っているかどうか、および速度に関して何が期待できるかについてのものです。

テキスト ラベルは、文字ごとにテクスチャ座標の四角形を作成し、小さなフォント ビットマップを使用して四角形をテクスチャリングすることによって描画されます (各文字は、テクスチャ内で約 5x13 ピクセルです)。

テスト ファイルには、経度と緯度で指定された約 158,000 のポイントがあるため、この経度/緯度空間が「モデル空間」です。それらのポイントを読み取り、それらのopengl頂点バッファーを作成します。次に、各ポイントは、通常 3 文字または 4 文字の長さのラベルを取得します。つまり、平均で 3.5 文字としましょう。ポイントはスクリーン座標で描画されます (オルソ投影モード)。キャラクターごとに、テクスチャ座標の rect を作成してキャラクターの適切なピクセルを取得し、スクリーン座標でキャラクターが描画される四角形を作成します。これら 2 つの四角形のセットは、それぞれ頂点バッファーに入れられます。つまり、158k * 3.5 * 8 = 440 万ポイント、つまり、描画四角形の 880 万の個別の座標番号と、テクスチャ座標の 880 万の番号です。

レンダリングするときが来たら、すべてのモデル ポイントの現在の画面位置と一致するように、すべての描画四角形の画面座標を更新する必要があります (少なくともこれが唯一の方法だと思います)。つまり、158 個のモデル ポイントのそれぞれについて、ポイントのモデル (ワールド) 座標から投影された (スクリーン) 座標を計算し、ポイントの 3 つまたは 4 つの文字四角形のそれぞれに 4 つのコーナー座標を設定する必要があります。 . したがって、基本的には、レンダリングごとに 880 万の数字をすべて更新しています。これらの数値を更新するには、レンダリングごとに約 0.3 秒かかります。

質問番号 1: これは、opengl でポイントのラベル付けを処理する正しい/必要な方法のように聞こえますか? 「このモデル ポイントにリンクされているが、投影されたモデル ポイントからのスクリーン オフセットとして扱われる、この長方形ポイントのセットに自動的にレンダリングする」と言う方法があれば理想的です。そうすれば、レンダリングごとに描画四角形を更新する必要がなくなります。でもそんなことないですよね?

質問 2: 各レンダリングの前にこれらすべての画面四角形を更新する時間に加えて、158k のすべてのラベルが画面に表示されると、レンダリング自体に約 1 秒かかります (これは明らかに有用なユーザー エクスペリエンスではありませんが、私はここで速度を理解しようとしているだけです)。ズームインすると、実際に画面に描画されるポイント/ラベルが少なくなり、レンダリング時間はそれに比例して短くなります。平均的/最新の GPU を搭載した私の平均的/最新のラップトップで、1 秒が 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
4

1 に答える 1

0

投影モードと画面座標は2つの異なるものです。OpenGLユニットが画面のピクセルと一致するように投影パラメータを選択することはできますが、これは必須ではありません。明確にするためだけに。

質問の1つ:OpenGLは単なる描画APIであり、より高いレベルの機能はありません。そうです、それらの仲間を同期させるのはあなたの負担です。幸いなことに、あなたは一度だけ数学をしなければなりません。ズーム、変換、回転などはすべて、変換行列を操作することで実行できます。ただし、ビューを変更するたびに、完全に再描画する必要があります。

質問2:それはすべて、目に見えないものを処理するのではなく、埋めるために要約されます。興味深い点の1つは、GPUは1秒間に数百万の三角形を処理できますが、簡単に消化できるチャンクで提供される場合、つまり、すべてがキャッシュに収まるバッチで提供される場合に最適に処理されることです。1000から3000の頂点のバッチがそれぞれ最適に機能することがわかりました。また、実際にアクセスしている部分だけでなく、アクセスされたテクスチャの合計サイズからも影響があります。ただし、最適化されていない描画方法では、数値は妥当に聞こえます。

于 2011-05-06T12:35:31.683 に答える