Search code examples
openglrenderingrender-to-texture

OpenGL rendering to cubemap


I'm trying to render to cubemap. The scene that is being render is a terrain. I use latitude-longitude debug display to see what's in a certain cubemap. The two debug view on the bottom left are dummy cubemap that just shows directions and one cubemap with real pictures.

The debug view on the right bottom half show what I get rendered in a cubemap that I'm after.

I've tried many different combinations for setting up the camera, but none of them gave any logical results. I've also compared the code with several samples for implementation of the dynamic cubemap and I was still unable to spot the problem. I'm out of ideas what to even try next, so any help or suggestion is welcome.

Draw to cubemap function:

void Draw(GLuint cubemap, glm::ivec2 res, glm::vec3 position)
{

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    glBindRenderbuffer(GL_RENDERBUFFER, rb);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, res.x, res.y);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb);

    // camera
    glm::mat4 p = glm::perspective(90.0f, 1.0f, 0.01f, 10.0f);
    glm::mat4 v;

    glm::vec3 targets[6] = {
        glm::vec3(+1.0f, 0.0f, 0.0f),
        glm::vec3(-1.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, +1.0f, 0.0f),
        glm::vec3(0.0f, -1.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, +1.0f),
        glm::vec3(0.0f, 0.0f, -1.0f)
    };
    glm::vec3 ups[6] = {
        glm::vec3(0.0f, 1.0f, 0.0f),
        glm::vec3(0.0f, 1.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, 1.0f),
        glm::vec3(0.0f, 0.0f, -1.0f),
        glm::vec3(0.0f, 1.0f, 0.0f),
        glm::vec3(0.0f, 1.0f, 0.0f)
    };

    // render
    for (int i = 0; i < 6; i++)
    {
        glViewport(0, 0, res.x, res.y);
        // setup target face
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0);
        // setup camera
        v = glm::lookAt(position, position + targets[i], ups[i]);
        // draw
        DrawTerrain(terrain.heightmap, terrain.m, v, p);    // model, view, projection matrices
    }
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

screenshot


Solution

  • The matrices were wrong. After a very thorough check of the values, the values that glm was returning weren't correct, both for projection and view matrices. I will see if I'll report a request for bugfix, but for now, here's the code that actually fixed the matrices.

    // projection matrix (fov = 90 degrees, aspect = 1.0)
    glm::mat4 p;
    float n = 0.1f, f = 2.0f; // near and far
    p[0][0] = 1.0f;
    p[1][1] = 1.0f;
    p[2][2] = -f / (f - n);
    p[2][3] = -1.0f;
    p[3][2] = -(f*n) / (f - n);
    
    glm::vec3 targets[6] = {
        glm::vec3(+1.0f, 0.0f, 0.0f),
        glm::vec3(-1.0f, 0.0f, 0.0f),
        glm::vec3(0.0f, +1.0f, 0.0f),
        glm::vec3(0.0f, -1.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, +1.0f),
        glm::vec3(0.0f, 0.0f, -1.0f)
    };
    glm::vec3 ups[6] = {
        glm::vec3(0.0f, 1.0f, 0.0f),
        glm::vec3(0.0f, 1.0f, 0.0f),
        glm::vec3(0.0f, 0.0f, -1.0f),
        glm::vec3(0.0f, 0.0f, 1.0f),
        glm::vec3(0.0f, 1.0f, 0.0f),
        glm::vec3(0.0f, 1.0f, 0.0f)
    };
    for(int i=0; i<6; ++i)
    {
        // view matrix
        v = glm::lookAt(position, position + targets[i], ups[i]);
        v[0][2] *= -1.0f;
        v[1][2] *= -1.0f;
        v[2][2] *= -1.0f;
        v[3][2] *= -1.0f;   
        // render...
    }
    

    EDIT:

    After Andreas' comments I investigated a bit more.

    glm::perspective required FOV in radians, but since every single example that used that function called it with degrees, I never really suspected at it. After checking at scrathapixel I was sure that perspective matrix is right (even though the determinant is negative). So, FOV is in radiands, that was my mistake.

    However, the lookAt was wrong. I compared that function across several resources and definitely with bgfx's lookAt and indeed, the entire third column should have sign reversed. So the changes where I multiply that column of the view matrix with -1 remained.