複雑なジオメトリの可視性テストに 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コードを使用したいと思います。