0

複雑なジオメトリの可視性テストに OpenGL を使用しようとしています。私がやりたいことは簡単です: 各プリミティブに整数 ID を割り当て、その ID を持つピクセルの数を数えます。これにより、各プリミティブの相対的な可視領域を計算できます。(最終的に、これは可視領域でのいくつかのマイナーな有限要素計算に拡張されます。)

私の問題はこれです。フラグメント シェーダーの出力をアプリケーション メモリに読み込もうとしています。具体的には、プリミティブ ID の出力です。QT 4.7.4 とその OpenGL ラッパー クラスを使用しています。バッファ (「PixelPack」バッファ) をバインドして有効にし、OpenGL バッファからメモリに読み込もうとすると、読み込みが成功したと報告されます。しかし、配列に格納されている値は、私が期待したものではありません。テスト目的で、すべてのプリミティブの ID を 1 に設定したにもかかわらず、それらはすべて 0 です。

これが私のフラグメントシェーダーです:

#version 130

in vec4 Color;
flat in uint VertId;

out vec4 FragColor;
out uint FragId;

void main()
{
   FragColor = Color;

   // Changed to simpler version for debugging.
   //   FragId = VertId;
   FragId = uint( 1 );
}

そして、これが私のアプリケーション コードで、関係のない部分 (テスト ハーネスの接続など) が取り除かれています。

#include <QtOpenGL/QGLShader>
#include <QtOpenGL/QGLShaderProgram>
#include <QtOpenGL/QGLBuffer>

using namespace std;

string loadSource( string file );

int
testSelfShadow::
shader( ostream& error )
{
   bool fail = false;

   // Create the OpenGL context.
   int argc = 0;
   char* argv;
   QApplication* app = new QApplication( argc, &argv );
   QGLWidget* widget = new QGLWidget();
   widget->makeCurrent();

   // Create the shader program.
   QGLShaderProgram* prog = new QGLShaderProgram();
   bool success = false;
   success = prog->addShaderFromSourceCode( QGLShader::Vertex,
                                            loadSource( "vertex.glsl" ).c_str() );     
   if ( ! success )
   {
      ErrorOStream msg;
      msg << "Error trying to load vertex shader into a shader program.\n"
          << prog->log().toStdString();
      throw ERRORLOG( msg.str() );
   }
   success = prog->addShaderFromSourceCode( QGLShader::Fragment,
                                            loadSource( "fragment.glsl" ).c_str() );   
   if ( ! success )
   {
      ErrorOStream msg;
      msg << "Error trying to load fragment shader into a shader program.\n"
          << prog->log().toStdString();
      throw ERRORLOG( msg.str() );
   }
   success = prog->link();

   if ( ! success )
   {
      ErrorOStream msg;
      msg << "Error trying to link shaders into a shader program.\n"
          << prog->log().toStdString();
      throw ERRORLOG( msg.str() );
   }

   prog->bind();

   // Create the buffer for vertex position.
   QGLBuffer* vBuf = new QGLBuffer( QGLBuffer::VertexBuffer );
   vBuf->create();
   vBuf->setUsagePattern( QGLBuffer::DynamicDraw );
   vBuf->bind();

   GLfloat vertices[] = {
      -1.0f, -1.0f, 0.0f, 1.0f,
      -1.0f, 0.0f, 0.0f, 1.0f,
      1.0f, 0.0f, 0.0f, 1.0f,
      1.0f, -1.0f, 0.0f, 1.0f,
      -1.0f, 0.0f, 0.1f, 1.0f,
      -1.0f, 1.0f, 0.1f, 1.0f,
      1.0f, 1.0f, 0.1f, 1.0f,
      1.0f, 0.0f, 0.1f, 1.0f };

   vBuf->allocate( vertices, sizeof( vertices ) );

   prog->setAttributeBuffer( "Vertex", GL_FLOAT, 0, 4, 0 );
   prog->enableAttributeArray( "Vertex" );

   // Create the buffer for Grayscale brightness value.
   // Not important for final program, just for debugging during
   // development.
   QGLBuffer* bBuf = new QGLBuffer( QGLBuffer::VertexBuffer );
   bBuf->create();
   bBuf->bind();

   GLfloat brightness[] = {
      1.0, 0.9, 0.8, 0.7,
      0.5, 0.4, 0.3, 0.2 
 };

   bBuf->allocate( brightness, sizeof( brightness ) );

   prog->setAttributeBuffer( "Brightness", GL_FLOAT, 0, 1, 0 );
   prog->enableAttributeArray( "Brightness" );

   // Create the buffer for polygon ID.
   QGLBuffer* idBuf = new QGLBuffer( QGLBuffer::VertexBuffer );
   idBuf->create();
   idBuf->bind();
   GLuint polyId[] = {
      1, 1, 1, 1, 
      2, 2, 2, 2
   };

   idBuf->allocate( polyId, sizeof( polyId ) );
   prog->setAttributeBuffer( "PolyId", GL_UNSIGNED_INT, 0, 1, 0 );
   prog->enableAttributeArray( "PolyId" );

   // Create the index buffer.  Not trying to do any optimization
   // here yet.
   QGLBuffer* iBuf = new QGLBuffer( QGLBuffer::IndexBuffer );
   iBuf->create();
   iBuf->bind();
   GLuint indices[] = {
      0, 1, 2, 3, 4, 5, 6, 7
   };
   iBuf->setUsagePattern( QGLBuffer::StaticDraw );
   iBuf->allocate( indices, sizeof( indices ) );

   // Create the buffer for reading back polygon id per fragment.
   QGLBuffer* fBuf = new QGLBuffer( QGLBuffer::PixelPackBuffer );
   fBuf->create();
   fBuf->setUsagePattern( QGLBuffer::DynamicRead );
   fBuf->bind();
   fBuf->allocate( 640 * 480 * sizeof( GLuint ) );

   prog->setAttributeBuffer( "FragId", GL_UNSIGNED_INT, 0, 1, 0 );
   prog->enableAttributeArray( "FragId" );

   GLuint* fBufData = new GLuint[ 640 * 480 * sizeof( GLuint ) ];

   glDrawElements( GL_QUADS, 8, GL_UNSIGNED_INT, 0 );
   widget->show();
   widget->updateGL();

   // Trying this two different ways; neither way works.
   bool readSuccess = fBuf->read( 0, fBufData, 640 * 480 * sizeof( GLuint ) );
   GLuint* fBufMap = 
      static_cast< GLuint* >( fBuf->map( QGLBuffer::ReadOnly ) );

   cout << "\n"
        << "Read Successful: " << readSuccess << endl;
   cout << "Buffer map location and sample data: " 
        << fBufMap << ":" << fBufMap[640] << endl;
   cout << "Read data pointer: " << fBufData << endl;
   cout << "Sample fragment ID: " << fBufData[ 640 * 480 / 2 ] << endl;

   app->exec();

   return fail;
}

プログラム実行の出力例を次に示します。

Read Successful: true
Buffer map location and sample data: 0x5a5d9000:0
Read data pointer: 0x59e48008
Sample fragment ID: 0

それは私が期待するものではありません。フラグメント シェーダーで FragId = uint( 1 ) を明示的に設定しているため、すべてのフラグメント ID が 1 であると予想されます。読み取りの設定が間違っていますか? バッファのバインド、または名前の有効化に何か問題がありますか?

この質問の範囲を超えた理由から、可能であればQTコードを使用したいと思います。

4

1 に答える 1

1

ここには非常に多くの Qt が含まれているため、実際の OpenGL 呼び出しを見つけることはほとんど不可能です。しかし、あなたには2つの問題があるようです:

  1. 画面にレンダリングしています。画面では、ある種の正規化された整数画像形式が使用されています。これは基本的に「フロートしますが、8ビットを占有する」ことを意味します。シェーダーから整数を書き込んでいます。これらは一致しません。したがって、レンダリングによって未定義の動作が発生します。

    GL_R8UIテクスチャを含む FBO にレンダリングする必要があります。次に、uintフラグメント シェーダーの出力タイプがバッファーと一致します。おそらく深度バッファも必要になるでしょう。

  2. 実際にピクセルデータを読み取ることはありません。バッファ オブジェクトQGLBuffer::readから読み取ります。しかし、まだバッファ オブジェクトには何も入れていません。レンダリングしたフレームバッファ データをコピーしてバッファ オブジェクトに格納するように OpenGL に指示したことはありません。最初にそれを行う必要があります。それを行った後、それから読み取ることができます。

    FBO にレンダリングした後、 を呼び出すglReadPixels必要があります。その場合、レンダリングしたものに正しいピクセル転送パラメーターを指定する必要があります。GL_RED_INTEGERつまり、 forとtypeを使用する必要があります。また、ピクセル バッファーに読み込んでいるため、読み込む前にバインドされていることを確認する必要があります。GL_UNSIGNED_BYTE

于 2013-02-02T02:23:43.610 に答える