web-dev-qa-db-ja.com

OpenGL:テクスチャとフレームバッファオブジェクトへのレンダリングに関する問題

シーンを最初は空のテクスチャにレンダリングしたいと思います。そのために、空の2Dテクスチャとデプスバッファをアタッチするフレームバッファオブジェクトを使用します。セットアップ後、テストに関しては、単純なクワッドをシーンに描画します。頂点ごとに色が異なるため、最終的にはテクスチャに色が補間されたクワッドが期待されます。次に、クワッドを含むテクスチャを使用して、別のクワッドにマップします。そのため、デフォルトのフレームバッファには、色付きのクワッドを含むテクスチャを持つクワッドがあります。これがあまり混乱しないことを願っています...

とにかく、私が得るのは灰色のテクスチャに過ぎないので、私はここで何かが欠けているに違いありません。私は基本的に this 非常に簡単な指示に従いました。しかし、ここで何が欠けているのかよくわかりません。誰かが私に手がかりを与えてくれたらありがたいです。

ありがとうウォルター


これは私がこれまでに持っているコードです://フレームバッファオブジェクトを作成しますglGenFramebuffers(1、&frameBufferObject);

// create depth buffer
glGenRenderbuffers(1, &depthAttachment);

// create empty texture
int width = 512;
int height = 512;
int numberOfChannels = 3;
GLuint internalFormat = GL_RGB;
GLuint format = GL_RGB;

unsigned char* texels = new unsigned char[width * height * numberOfChannels];

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, texels);

glGenerateMipmap(GL_TEXTURE_2D);

delete[] texels;
texels = NULL;

// activate & bind empty texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

// attach empty texture to framebuffer object
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

// define render targets (empty texture is at GL_COLOR_ATTACHMENT0)
glDrawBuffers(1, GL_COLOR_ATTACHMENT0);

// attach depth buffer
glBindRenderbuffer(GL_RENDERBUFFER, depthAttachment);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthAttachment);

// use framebuffer object
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject);

// draw the colored quad into the initially empty texture
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);

// store attibutes
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// reset viewport
glViewport(0, 0, width, height);

// make background yellow
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);

// draw quad into texture attached to frame buffer object
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glVertex2f(0.0f, 100.0f); // top left
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); // bottom left
    glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glVertex2f(100.0f, 0.0f); // bottom right
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glVertex2f(100.0f, 100.0f); // top right
glEnd();

// restore attributes
glPopAttrib();

glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);

// use default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// clear default framebuffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// draw the scene
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glColor4f(1.0, 1.0, 1.0, 1.0);

// begin texture mapping
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

glBegin(GL_QUADS);
    glNormal3d(0.0f, 0.0f, 1.0f);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 50.0f, -100.0f);    // top left
    glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, -100.0f);     // bottom left
    glTexCoord2f(1.0f, 1.0f); glVertex3f(50.0f, 0.0f, -100.0f);    // bottom right
    glTexCoord2f(1.0f, 0.0f); glVertex3f(50.0f, 50.0f, -100.0f);   // top right
glEnd();

glDisable(GL_TEXTURE_2D);

glPopMatrix();

// swap buffers (I forgot to mention that I use SDL)
SDL_GL_SwapBuffers();

期待される結果:

  • 黄色の背景に色付きのクワッドのテクスチャ
  • そのテクスチャは別のクワッドにマッピングされます

実結果:

  • 灰色のテクスチャ
  • テクスチャは他のクワッドに正常にマッピングできます

編集:私はエラー処理について言及するのを逃しました。これが私がエラーをチェックする方法です。これには、PaulSが提案した追加のケースが含まれています。それをありがとう。

GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch(status) {
    case GL_FRAMEBUFFER_COMPLETE:
        return;
        break;

case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
    throw FramebufferIncompleteException("An attachment could not be bound to frame buffer object!");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
    throw FramebufferIncompleteException("Attachments are missing! At least one image (texture) must be bound to the frame buffer object!");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
    throw FramebufferIncompleteException("The dimensions of the buffers attached to the currently used frame buffer object do not match!");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
    throw FramebufferIncompleteException("The formats of the currently used frame buffer object are not supported or do not fit together!");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
    throw FramebufferIncompleteException("A Draw buffer is incomplete or undefinied. All draw buffers must specify attachment points that have images attached.");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
    throw FramebufferIncompleteException("A Read buffer is incomplete or undefinied. All read buffers must specify attachment points that have images attached.");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
    throw FramebufferIncompleteException("All images must have the same number of multisample samples.");
    break;

case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS :
    throw FramebufferIncompleteException("If a layered image is attached to one attachment, then all attachments must be layered attachments. The attached layers do not have to have the same number of layers, nor do the layers have to come from the same kind of texture.");
    break;

case GL_FRAMEBUFFER_UNSUPPORTED:
    throw FramebufferIncompleteException("Attempt to use an unsupported format combinaton!");
    break;

default:
    throw FramebufferIncompleteException("Unknown error while attempting to create frame buffer object!");
    break;
}

編集2:これは私がGLエラーをチェックするために使用する方法です

checkForGLErrors(string sourceFile, int line)
    GLenum error = glGetError();
    ostringstream o;

    switch(error) {
        case GL_NO_ERROR:
            return;
            break;

        case GL_INVALID_ENUM:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Invalid enum!"<<endl;
            throw GLErrorException(o.str());
            break;

        case GL_INVALID_VALUE:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Invalid value!"<<endl;
            throw GLErrorException(o.str());
            break;

        case GL_INVALID_OPERATION:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Invalid operation!"<<endl;
            throw GLErrorException(o.str());
            break;

        case GL_STACK_OVERFLOW:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Stack overflow!"<<endl;
            throw GLErrorException(o.str());
            break;

        case GL_STACK_UNDERFLOW:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Stack underflow!"<<endl;
            throw GLErrorException(o.str());
            break;

        case GL_OUT_OF_MEMORY:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Out Of memory!"<<endl;
            throw GLErrorException(o.str());
            break;

        case GL_TABLE_TOO_LARGE:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Table too large!"<<endl;
            throw GLErrorException(o.str());
            break;

        default:
            o<<"OpenGL Error in "<<sourceFile<<" at line "<<line<<": Unknown error!"<<endl;
            throw GLErrorException(o.str());
            break;
    }
}
15
Walter

この問題を解決しました。

だからここに私がすることです。たぶんそれを行うためのより良い/よりスマートな方法がいくつかありますが、今では完全にうまく機能しています。適応を提案してください...

以下にエラー処理をリストしません。あなたはこの質問でそれをさらに上に見つけることができます。


// create frame buffer object
glGenFramebuffers(1, frameBufferObject);

// create empty texture
int width = 512;
int height = 512;
int numberOfChannels = 3;
GLuint internalFormat = GL_RGB8;
GLuint format = GL_RGB;

unsigned char* texels = new unsigned char[width * height * numberOfChannels];

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, texels);

delete[] texels;
texels = NULL;

// draw the colored quad into the initially empty texture
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);

// store attibutes
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// reset viewport
glViewport(0, 0, width, height);

// setup modelview matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

// setup projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

// setup orthogonal projection
glOrtho(-width / 2, width / 2, -height / 2, height / 2, 0, 1000);

// bind framebuffer object
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject);

// attach empty texture to framebuffer object
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

// check framebuffer status (see above)

// bind framebuffer object (IMPORTANT! bind before adding color attachments!)
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject);

// define render targets (empty texture is at GL_COLOR_ATTACHMENT0)
glDrawBuffers(1, GL_COLOR_ATTACHMENT0); // you can of course have more than only 1 attachment

// activate & bind empty texture
// I figured activating and binding must take place AFTER attaching texture as color attachment
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

// clear color attachments
glClear(GL_COLOR_BUFFER_BIT);

// make background yellow
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);

// draw quad into texture attached to frame buffer object
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glVertex2f(0.0f, 100.0f); // top left
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); // bottom left
    glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glVertex2f(100.0f, 0.0f); // bottom right
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glVertex2f(100.0f, 100.0f); // top right
glEnd();

// reset projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();

// reset modelview matrix
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

// restore attributes
glPopAttrib();

glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);

// I guess, now it's OK to create MipMaps

// draw the scene
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glColor4f(1.0, 1.0, 1.0, 1.0);

// begin texture mapping
glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // normal faces "camera"
    glNormal3d(0.0f, 0.0f, 1.0f);

    glBegin(GL_QUADS);
        glNormal3d(0.0f, 0.0f, 1.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 50.0f, -100.0f);    // top left
        glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, -100.0f);     // bottom left
        glTexCoord2f(1.0f, 1.0f); glVertex3f(50.0f, 0.0f, -100.0f);    // bottom right
        glTexCoord2f(1.0f, 0.0f); glVertex3f(50.0f, 50.0f, -100.0f);   // top right
    glEnd();

glDisable(GL_TEXTURE_2D);

glPopMatrix();

// finish rendering
glFlush();
glFinish();

// swap buffers (I forgot to mention that I use SDL)
SDL_GL_SwapBuffers();

// do the clean up!

ご覧のとおり、デプスバッファのアタッチメントを削除しました。私は自分の仕事には本当にそれを必要としないと思いました。実際に物を描くことができたらすぐに、正射影を追加しました。それがないと、テクスチャに描画するとかなり厄介な画像になります...

これがウォルターの誰かに役立つことを願っています

5
Walter

奇妙なことに、 glDrawBuffersglFramebufferTexture2D の両方が仕様のようには見えません!最初のものは、GLenumではなくGLenumのarrayを取ります(警告を確認してください:サイレントキャストできます!)。そして2番目のものはスペックに関して4つの引数しか取りません!

編集:

void glDrawBuffers(GLsizei  n,  const GLenum * bufs);
4
tibur

私はどちらかが起こっていることを期待しています:

  • 未入力のミップマップレベルからレンダリングしています。色付きのクワッドをレンダリングするかなり前に、glGenerateMipmapを呼び出しています。今はGL_NEARESTを試してみてください。
  • フレームバッファオブジェクトを作成するときにエラーが発生します。それが起こった場合、あなたのレンダリングはブラックホールに落ちるでしょう。

これは、フレームバッファのステータスを確認するために使用するコードスニペットです。 FBOのEXTバージョンを使用し、Objective-C(したがって、@ ""文字列)にありますが、それは明らかなはずです。これは、glBindFramebuffer、glFramebufferTexture2D、およびglDrawBuffersを呼び出した後に発生します。

    GLenum framebufferStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

    switch (framebufferStatus) {
        case GL_FRAMEBUFFER_COMPLETE_EXT: break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
            NSLog(@"Framebuffer Object %d Error: Attachment Point Unconnected", i);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
            NSLog(@"Framebuffer Object %d Error: Missing Attachment", i);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
            NSLog(@"Framebuffer Object %d Error: Dimensions do not match", i);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
            NSLog(@"Framebuffer Object %d Error: Formats", i);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
            NSLog(@"Framebuffer Object %d Error: Draw Buffer", i);
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
            NSLog(@"Framebuffer Object %d Error: Read Buffer", i);
            break;
        case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
            NSLog(@"Framebuffer Object %d Error: Unsupported Framebuffer Configuration", i);
            break;
        default:
            NSLog(@"Framebuffer Object %d Error: Unkown Framebuffer Object Failure", i);
            break;
    }

ドライバーはこれについてかなりうるさい傾向があるため、問題は深度バッファーである可能性があります。このテストでは、深度は必要ないため、問題が発生している場合は、レンダーバッファーのものを削除できます。

別の注意点として、テクスチャをレンダリングするために、テクスチャをバインドしてアクティブにする必要はありません。最終的な画像をレンダリングするために使用するまで、そのコードを延期することができます。

1
Paul S