OpenGL / GLSL:キューブマップにレンダリングしますか?


13

シーンをキューブマップにレンダリングする方法を見つけようとしています。私はこれに少し立ち往生しており、皆さんに助けを求めると思いました。OpenGLは初めてで、FBOを使用するのは初めてです。

現在、キューブマップbmpファイルの使用例があり、フラグメントシェーダーのsamplerCubeサンプルタイプがGL_TEXTURE1にアタッチされています。シェーダーコードはまったく変更していません。キューブマップbmpファイルをロードしていた関数を呼び出さず、以下のコードを使用してキューブマップにレンダリングしようとしているという事実を変更しているだけです。

以下のように、GL_TEXTURE1にもテクスチャを再度アタッチしています。これは、ユニフォームを設定したときです。

glUniform1i(getUniLoc(myProg, "Cubemap"), 1);

フラグメントシェーダーでにアクセスできますuniform samplerCube Cubemap

私は次のような関数を呼び出しています:

cubeMapTexture = renderToCubeMap(150, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);

ここで、下の描画ループで、+ x、-x、+ y、-y、+ z、-z軸を見下ろすようにビューの方向を変更していないことに気付きます。私は本当にそれを実装する前に何かが最初に動作するのを見たいだけでした。私は少なくとも、コードが今のようにオブジェクト上に何かを見るべきだと考えました。

私は何も見ていません、ただ真っ黒です。背景を白にしましたが、オブジェクトは黒です。キューブマップテクスチャをサンプリングするために照明と色を削除しましたが、まだ黒です。

GL_RGB8、GL_RGBAのテクスチャを設定するときの問題は、フォーマットのタイプかもしれないと思っていますが、私も試しました:

GL_RGBA、GL_RGBA GL_RGB、GL_RGB

フレームバッファにアタッチされたテクスチャにレンダリングするので、これは標準だと思いましたが、異なる列挙値を使用する異なる例を見てきました。

また、キューブマップを使用するすべての描画呼び出しでキューブマップテクスチャをバインドしようとしました。

glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexture);

また、ほとんどの例で見たFBO用の深度バッファーを作成していません。これは、キューブマップのカラーバッファーのみが必要だからです。実際にそれを追加して、それが問題かどうかを確認しましたが、それでも同じ結果が得られました。試してみたときに、それを少しでもおかしくすることができました。

正しい方向に私を向けることができる助けはありがたいです。

GLuint renderToCubeMap(int size, GLenum InternalFormat, GLenum Format, GLenum Type)
    {

    // color cube map
    GLuint textureObject;
    int face;
    GLenum status;

    //glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE1);
    glGenTextures(1, &textureObject);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureObject);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    for (face = 0; face < 6; face++) {
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, InternalFormat, size, size, 0, Format, Type, NULL);
    }

    // framebuffer object
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, textureObject, 0);

    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    printf("%d\"\n", status);
        printf("%d\n", GL_FRAMEBUFFER_COMPLETE);

    glViewport(0,0,size, size);

    for (face = 1; face < 6; face++) {

        drawSpheres();
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, textureObject, 0);

    }

     //Bind 0, which means render to back buffer, as a result, fb is unbound
       glBindFramebuffer(GL_FRAMEBUFFER, 0);

       return textureObject;
    }

drawSpheres関数が実際に目に見えるものを描画することを確認するためにテストしましたか?関数は実際に何かを描画しますか?drawSpheresフレームバッファをクリアするように変更するとどうなりますか?
ニコルボーラス

はい。2つのパスを実行しています。上記のコードの1つ、実際には上記の6つの呼び出し。次に、フレームバッファ0にレンダリングするときにdrawSpheresを呼び出していますが、表示されません。
ジョーイグリーン

また、背景を白に設定しました。白色は少なくともテクスチャに現れませんか?
ジョーイグリーン

コードは通常のFBOで正常に機能しますか?私はそれを理解する方法、キューブマップは、わずか6つのテクスチャであるべきであり、あなたが個別にレンダリングする必要があるだろう...
ヤリKomppa

回答:


10

まあ、私はこれがあなたが何が起こっているかを理解するのに役立つことを保証することはできません。特定のエラーを追跡するために何をしているのかについて十分な情報を投稿していないだけです。私はあなたのものの1つを本当に迅速に修正できますが:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, textureObject, 0);

...

for (face = 1; face < 6; face++) {
    drawSpheres();
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, textureObject, 0);
}

これはdrawSpheres 5回だけ呼び出します。私はあなたがそれを6回呼ぶことを望んでいたと推測しています。

しかし、私は実用的な答えを投稿することができます。このコードは、チュートリアルシリーズと並行して実行されるように設計されているため、存在しないコードを参照することに注意してください。ただし、これは主にメッシュの作成などです。本当に重要なことは何もありません。

ここに顕著なポイントがあります。メイン球体オブジェクトのシェーダー。

頂点シェーダー:

#version 330

layout(std140) uniform;

layout(location = 0) in vec4 position;
layout(location = 2) in vec3 normal;

out vec3 modelSpaceNormal;

uniform Projection
{
    mat4 cameraToClipMatrix;
};

uniform mat4 modelToCameraMatrix;

void main()
{
    gl_Position = cameraToClipMatrix * (modelToCameraMatrix * position);
    modelSpaceNormal = normal;
}

フラグメントシェーダー:

#version 330

in vec3 modelSpaceNormal;

uniform samplerCube cubeTexture;

out vec4 outputColor;

void main()
{
    outputColor = texture(cubeTexture, modelSpaceNormal);
//  outputColor = vec4(normalize(modelSpaceNormal), 1.0);
}

レンダーターゲットとして使用されるキューブマップテクスチャの作成:

void CreateCubeTexture()
{
    glGenTextures(1, &g_cubeTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    std::vector<GLubyte> testData(CUBE_TEXTURE_SIZE * CUBE_TEXTURE_SIZE * 256, 128);
    std::vector<GLubyte> xData(CUBE_TEXTURE_SIZE * CUBE_TEXTURE_SIZE * 256, 255);

    for(int loop = 0; loop < 6; ++loop)
    {
        if(loop)
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGBA8,
                CUBE_TEXTURE_SIZE, CUBE_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &testData[0]);
        }
        else
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGBA8,
                CUBE_TEXTURE_SIZE, CUBE_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &xData[0]);
        }
    }

    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

実際には、デバッグの補助としてテクスチャをデータで満たします(glTexImage2DにNULLを渡すのではなく)。テクスチャをレンダーターゲットとして使用する前に、すべてが機能していたことを確認します。

また、BASE_LEVELとMAX_LEVELを指定していることに注意してください。私は常に作成直後にテクスチャでそれを行います。OpenGLは、テクスチャの完全性とミップマップピラミッドについて時々うるさいので、それはちょうど良い習慣です。規則を覚えるのではなく、宗教的に正しい値に設定するだけです。

主な描画関数は次のとおりです。

void display()
{
    //Draw the cubemap.
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_framebuffer);
    glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, g_depthbuffer);

    for(int loop = 0; loop < 6; ++loop)
        DrawFace(loop);

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

    //Draw the main scene.
    //The projection matrix is in a uniform buffer.
    ProjectionBlock projData;
    projData.cameraToClipMatrix = glm::perspective(90.0f,
        (g_viewportSize.x / (float)g_viewportSize.y), g_fzNear, g_fzFar);

    glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, (GLsizei)g_viewportSize.x, (GLsizei)g_viewportSize.y);

    glClearColor(0.75f, 0.75f, 1.0f, 1.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack modelMatrix;
    modelMatrix.ApplyMatrix(g_viewPole.CalcMatrix());

    if(g_pSphere)
    {
        glutil::PushStack push(modelMatrix);

        glUseProgram(g_progMain.theProgram);
        glUniformMatrix4fv(g_progMain.modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelMatrix.Top()));

        glActiveTexture(GL_TEXTURE0 + g_cubeTexUnit);
        glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

        g_pSphere->Render("lit");

        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

        glUseProgram(0);
    }

    glutPostRedisplay();
    glutSwapBuffers();
}

これにより、への参照が作成されDrawFace、キューブマップの指定された面が描画されます。次のように実装されます。

void DrawFace(int iFace)
{
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + iFace, g_cubeTexture, 0);

    GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
    if(status != GL_FRAMEBUFFER_COMPLETE)
        printf("Status error: %08x\n", status);

    //The projection matrix is in a uniform buffer.
    ProjectionBlock projData;
    projData.cameraToClipMatrix = glm::perspective(90.0f, 1.0f, g_fzNear, g_fzFar);

    glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, (GLsizei)CUBE_TEXTURE_SIZE, (GLsizei)CUBE_TEXTURE_SIZE);

    const glm::vec4 &faceColor = g_faceColors[iFace];
    glClearColor(faceColor.x, faceColor.y, faceColor.z, faceColor.w);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(g_pSphere)
    {
        glutil::MatrixStack modelMatrix;
        modelMatrix.Translate(g_faceSphereLocs[iFace]);

        glUseProgram(g_progUnlit.theProgram);
        glUniformMatrix4fv(g_progUnlit.modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelMatrix.Top()));

        const glm::vec4 &sphereColor = g_faceSphereColors[iFace];
        glUniform4fv(g_progUnlit.objectColorUnif, 1, glm::value_ptr(sphereColor));

        glActiveTexture(GL_TEXTURE0 + g_cubeTexUnit);
        glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

        g_pSphere->Render("flat");

        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
        glUseProgram(0);
    }
}

この関数は、各面に個別の背景色、個別の球体色を与え、その面に球体を(カメラ空間で)適切に配置するために使用する一連のグローバルテーブルを参照します。

の顕著な点DrawFaceはこれらです。

原則として、状態が設定されているという特定の知識がない限り、その状態を設定します。呼び出すたびにビューポートを設定しますDrawFace。毎回投影行列を設定します。それらは不要です。現在のFBOとデプスレンダーバッファーで行うように、displayを呼び出すループの前にそれらを戻すこともできますDrawFace

ただし、顔ごとに異なるバッファークリアします(顔ごとに色が異なるため)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.