6

私は現在、Qtを使用して3Dシーンを視覚化するためのGUIソフトウェアプロジェクトに取り組んでいます。GUIを使用すると、ユーザーは、.mtlをサポートする.objや.stlなどの3Dデータファイルのバッチと、QGLWidgetから派生したウィジェットでレンダリングされるSceneObjectクラスのオブジェクトとして2D画像ファイルをシーンにロードできます。

ただし、メインGUIスレッドにバッチでロードすると、ロード時間が長くなるとGUIがフリーズし、見苦しくなります。別のスレッドでロードを実行しようとしましたが、大きな問題が1つあります。.objテクスチャまたは画像ファイルをロードする場合、各画像またはテクスチャをロードした直後にOpenGL glBindtexture()を使用してバインドも実行するため、保存するだけで済みます。各SceneObjectインスタンスのテクスチャID。ワーカースレッドでロードを実行しようとすると、プログラム全体がクラッシュしました。

各スレッドは1つのOGLコンテキストにしかアクセスできず、スレッド間のコンテキスト切り替えは、私がやりたかったことを達成するための1つの危険な方法であることを読みました。別の可能な方法は、ロードが完了した後にGUIスレッドでテクスチャバインディングを実行することですが、それは私のSceneObjectクラスで完全な再設計を意味します:(

アセットをOpenGLシーンにロードするためのロードスレッドを実装する方法について誰かにアドバイスをいただけますか?

4

1 に答える 1

5

また、各画像またはテクスチャをロードした直後にOpenGL glBindtexture()を使用してバインドを実行するため、各SceneObjectインスタンスにテクスチャIDを保存するだけで済みます。ワーカースレッドでロードを実行しようとすると、プログラム全体がクラッシュしました。

OpenGLコンテキストは、一度に1つのスレッドでのみアクティブにできます。一般に、マルチスレッドのOpenGL操作は、正しく行うために、通常、大きな悪夢になります。あなたの場合、あなたがやろうとしていることは、リソースのロードを委任することです。昔は、バッファオブジェクトが存在する前は、ヘルパーコンテキストを作成し、その「リスト」をメインコンテキストと共有することでこれを行っていました。

今日はもっと良いものがあります:バッファオブジェクト。バッファオブジェクトを使用すると、非同期でOpenGLにデータを送信できます。それはのようなものに沿っています

glGenBuffers(...);
glBindBuffer(...);
glBufferData(..., size, usage);
void *p = glMapBuffer(...);
memcpy(p, data, size);
glUnmapBuffer(...);
glTexImage / glDrawPixels / etc.

理解しておくべき重要な部分は、glMapBufferによって割り当てられたアドレス空間がスレッド間で共有されるということです。したがって、メインスレッドのOpenGLコンテキストに、バッファオブジェクトをマップし、割り当てを使用してワーカースレッドにシグナルを送信するように指示できます。次に、ワーカースレッドがデータを入力し、終了時にOpenGLコンテキストスレッドにシグナルを送信してマップを解除します。

マルチスレッド用に編集

したがって、これを行うには、両側にいくつかの信号ハンドラーを実装します(擬似コード)

signal OpenGLThread::mapPixelBufferObjectForWrite(ImageLoader il):
    glGenBuffers(1, &self.bufferId)
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self.bufferId)
    glBufferData(GL_PIXEL_UNPACK_BUFFER, il.unpackedImageSize, NULL, GL_STATIC_DRAW)
    BufferObjectMapping map(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY))
    send_signal(target_thread = workerthread, target_signal_handler = workerthread::loadImageToBuffer(map, il), signal_on_finish = self.unmapPixelBufferObjectWriteFinishedGenTexture(map))

signal IOThread::loadImageToBuffer(BufferObjectMapping map, ImageLoader il):
    /* ... */

signal OpenGLThread::unmapPixelBufferObjectWriteFinishedGenTexture(BufferObjectMapping map, ImageLoader il):
    if(map.mapping_target == GL_PIXEL_UNPACK_BUFFER)
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self.bufferId)
    glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)
    glGenTextures(1, &il.textureId)
    glBindTexture(il.target, il.textureId)
    for mipmaplevel in il.levels
        glTexImage2D(il.target, mipmaplevel, il.internalformat, il.width, il.height, il.border, il.format, il.type, mipmaplevel.offset)
于 2011-09-13T09:59:33.037 に答える