OpenGL / GLSL: แสดงแผนที่เป็นคิวบ์หรือไม่


13

ฉันพยายามหาวิธีทำให้ฉากของฉันเป็นแผนที่ลูกบาศก์ ฉันติดอยู่กับเรื่องนี้และคิดว่าฉันจะขอความช่วยเหลือจากพวกคุณ ฉันใหม่กับ OpenGL และนี่เป็นครั้งแรกที่ฉันใช้ FBO

ขณะนี้ฉันมีตัวอย่างการทำงานของการใช้ไฟล์ cubemap bmp และประเภทตัวอย่าง samplerCube ใน shader ที่ต่อกับ GL_TEXTURE1 ฉันไม่ได้เปลี่ยนรหัส shader เลย ฉันแค่เปลี่ยนความจริงที่ว่าฉันจะไม่เรียกฟังก์ชันที่โหลดไฟล์ cubemap bmp และพยายามใช้โค้ดด้านล่างเพื่อแสดงผลเป็น cubemap

คุณสามารถเห็นด้านล่างว่าฉันยังแนบพื้นผิวอีกครั้งกับ GL_TEXTURE1 นี่คือเมื่อฉันตั้งเครื่องแบบ:

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

มันสามารถเข้าถึงได้ในส่วน Shader uniform samplerCube Cubemapของฉันผ่านทาง

ฉันกำลังเรียกใช้ฟังก์ชันด้านล่างดังนี้:

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

ตอนนี้ฉันรู้แล้วในลูปการวาดด้านล่างว่าฉันไม่ได้เปลี่ยนทิศทางมุมมองเพื่อดูแกน + x, -x, + y, -y, + z, -z ฉันแค่อยากเห็นบางสิ่งบางอย่างที่ทำงานก่อนที่จะดำเนินการนั้น ฉันคิดว่าอย่างน้อยฉันควรเห็นบางสิ่งบางอย่างบนวัตถุของฉันอย่างที่เป็นตอนนี้

ฉันไม่เห็นอะไรเลยดำดิ่งเลย ฉันทำให้พื้นหลังเป็นสีขาววัตถุก็ยังเป็นสีดำ ฉันลบแสงและระบายสีเพื่อลองชิมพื้นผิว cubemap แล้วยังเป็นสีดำ

ฉันคิดว่าปัญหาอาจเป็นรูปแบบประเภทเมื่อตั้งค่าพื้นผิวของฉันซึ่งก็คือ GL_RGB8, GL_RGBA แต่ฉันก็ลองด้วย:

GL_RGBA, GL_RGBA GL_RGB, GL_RGB

ฉันคิดว่านี่จะเป็นมาตรฐานเนื่องจากเราแสดงผลพื้นผิวที่แนบมากับ framebuffer แต่ฉันเห็นตัวอย่างที่แตกต่างกันซึ่งใช้ค่า enum ที่แตกต่างกัน

ฉันยังได้ลองเชื่อมแผนที่พื้นผิวของคิวบ์ในทุกการโทรที่ฉันต้องการใช้แผนที่ลูกบาศก์:

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เป็นแค่เคลียร์เฟรมเฟรม?
Nicol Bolas

ใช่. ฉันทำสองรอบ หนึ่งในรหัสข้างต้นจริง 6 สายด้านบน จากนั้นฉันก็เรียก drawSpheres เมื่อเรนเดอร์ไปที่ framebuffer 0 และมันจะปรากฏขึ้น
Joey Green

นอกจากนี้ฉันได้ตั้งพื้นหลังเป็นสีขาว อย่างน้อยสีขาวจะปรากฏในพื้นผิวหรือไม่
Joey Green

รหัสของคุณใช้งานได้ดีกับ FBO ปกติหรือไม่ วิธีที่ฉันเข้าใจแผนที่ลูกบาศก์ควรเป็นพื้นผิวหกแบบและคุณจะต้องแสดงผลแยกกัน ..
Jari Komppa

คำตอบ:


10

ฉันไม่สามารถรับประกันได้ว่าสิ่งนี้จะช่วยให้คุณทราบว่าเกิดอะไรขึ้น คุณไม่ได้โพสต์ข้อมูลเพียงพอเกี่ยวกับสิ่งที่คุณทำเพื่อติดตามข้อผิดพลาดเฉพาะ แม้ว่าฉันจะสามารถแก้ไขสิ่งหนึ่งของคุณได้อย่างรวดเร็วจริงๆ:

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 ห้าครั้งเท่านั้น ฉันเดาว่าคุณต้องการเรียกมัน 6 ครั้ง

แต่ฉันสามารถโพสต์คำตอบที่ทำงานได้ โปรดทราบว่ารหัสนี้ออกแบบมาเพื่อให้ทำงานควบคู่กับชุดการสอนของฉันดังนั้นจึงอ้างอิงถึงรหัสที่ไม่มีอยู่ แต่นี่เป็นสิ่งสำคัญเช่นการสร้างตาข่ายเป็นต้น ไม่มีอะไรสำคัญอย่างแท้จริง

นี่คือจุดสำคัญ เฉดสีสำหรับวัตถุทรงกลมหลัก

Vertex shader:

#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;
}

ชิ้นส่วน shader:

#version 330

in vec3 modelSpaceNormal;

uniform samplerCube cubeTexture;

out vec4 outputColor;

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

การสร้างพื้นผิว cubemap ที่จะใช้เป็นเป้าหมายการเรนเดอร์:

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);
}

ฉันเติมพื้นผิวด้วยข้อมูล (แทนที่จะส่งผ่าน NULL ไปยัง glTexImage2D) เป็นเครื่องมือช่วยในการดีบั๊ก ทำให้มั่นใจได้ว่าทุกอย่างทำงานก่อนที่จะเริ่มใช้พื้นผิวเป็นเป้าหมายการแสดงผล

นอกจากนี้โปรดสังเกตว่าฉันให้ BASE_LEVEL และ MAX_LEVEL ฉันมักจะทำกับพื้นผิวของฉันทันทีหลังจากการสร้าง มันเป็นนิสัยที่ดีเนื่องจากบางครั้ง OpenGL อาจดูพิถีพิถันเกี่ยวกับความสมบูรณ์ของพื้นผิวและปิรามิด mipmap แทนที่จะจดจำกฎฉันเพิ่งตั้งค่าให้ถูกต้องตามหลักศาสนา

นี่คือฟังก์ชั่นการวาดภาพหลัก:

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ซึ่งดึงใบหน้าของ cubemap ที่จะดำเนินการดังนี้:

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ผมตั้งค่าวิวพอร์ตการโทรแต่ละครั้งผมเวลา ฉันตั้งค่าเมทริกซ์การฉายในแต่ละครั้ง สิ่งเหล่านั้นไม่จำเป็น ฉันสามารถตั้งค่าพวกเขากลับมาdisplayก่อนที่วงที่เรียกDrawFaceเช่นเดียวกับที่ฉันทำกับ FBO ปัจจุบันและ renderbuffer ลึก

แต่ฉันยังล้างบัฟเฟอร์ซึ่งแตกต่างกันไปสำหรับแต่ละหน้า (เนื่องจากแต่ละหน้ามีสีแตกต่างกัน)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.