Render cubemap to another cubemap with transparancy?

Started by
15 comments, last by Paul Griffiths 7 years, 3 months ago

I wish to have shadows with multiple lights.

Each light's shadow rendered to a depth cubemap.

How do I render each cubemap onto a single cubemap with transparency so have a cubemap with all the shadows?

This is how i'm setting up the cubemaps: code based on tutorial https://learnopengl.com/#!Advanced-Lighting/Shadows/Point-Shadows


const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
    const int totalLights = 4;
    GLuint depthMapFBO[totalLights];
    GLuint depthCubemap[totalLights];

for (GLuint light = 0; light < totalLights; ++light)
    {
        glGenFramebuffers(1, &depthMapFBO[light]);
        // Create depth cubemap texture
        glGenTextures(1, &depthCubemap[light]);
        glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap[light]);
        for (GLuint i = 0; i < 6; ++i)
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
        // Attach cubemap as depth map FBO's color buffer
        glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO[light]);
        glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap[light], 0);
        glDrawBuffer(GL_NONE);
        glReadBuffer(GL_NONE);
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "Framebuffer not complete!" << std::endl;
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

And this is the code to render a single cubemap:


// 1. Render scene to depth cubemap
            glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
            glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO[0]);
            glClear(GL_DEPTH_BUFFER_BIT);

            // Set texture samples
            simpleDepthShader.Use();

            // 0. Create depth cubemap transformation matrices
            GLfloat aspect = (GLfloat)SHADOW_WIDTH / (GLfloat)SHADOW_HEIGHT;

            glm::mat4 shadowProj = glm::perspective(90.0f, aspect, fNear, fFaar);
            std::vector<glm::mat4> shadowTransforms;
            shadowTransforms.push_back(shadowProj * glm::lookAt(lightPositions[light], lightPositions[light] + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));
            shadowTransforms.push_back(shadowProj * glm::lookAt(lightPositions[light], lightPositions[light] + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));
            shadowTransforms.push_back(shadowProj * glm::lookAt(lightPositions[light], lightPositions[light] + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0)));
            shadowTransforms.push_back(shadowProj * glm::lookAt(lightPositions[light], lightPositions[light] + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0)));
            shadowTransforms.push_back(shadowProj * glm::lookAt(lightPositions[light], lightPositions[light] + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
            shadowTransforms.push_back(shadowProj * glm::lookAt(lightPositions[light], lightPositions[light] + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0)));

            for (GLuint i = 0; i < 6; ++i)
                glUniformMatrix4fv(glGetUniformLocation(simpleDepthShader.Program, ("shadowTransforms[" + std::to_string(i) + "]").c_str()), 1, GL_FALSE, glm::value_ptr(shadowTransforms[i]));
            glUniform1f(glGetUniformLocation(simpleDepthShader.Program, "far_plane"), fFaar);
            glUniform3fv(glGetUniformLocation(simpleDepthShader.Program, "lightPos"), 1, &lightPositions[light][0]);
            RenderScene(simpleDepthShader);
            glBindFramebuffer(GL_FRAMEBUFFER, 0);

Advertisement

I really need help with this...It's essential to my project.

I wish to have shadows with multiple lights. Each light's shadow rendered to a depth cubemap. How do I render each cubemap onto a single cubemap with transparency so have a cubemap with all the shadows?

It's not clear what you want.

Shadow mapping works only for the single position of a single point light. You can not combine shadowmaps from multiple lights if they have different positions. (Cubemaps have 6 maps, but they are all relative to the same position.)

https://www.community.arm.com/graphics/b/blog/posts/dynamic-soft-shadows-based-on-local-cubemap

https://www.assetstore.unity3d.com/en/#!/content/61640

I am curious if this is somewhat related.

This is what I have so far;

Geometry shader:


#version 330 core

layout (triangles) in;

layout (triangle_strip, max_vertices=3) out;

 

uniform mat4 transform;

uniform int face;

out vec3 TexCoords;



void main()

{

    gl_Layer = face;

    for(int i = 0; i < 3; ++i) // for each triangle's vertices

    {

        gl_Position = transform * gl_in[i].gl_Position;

        TexCoords = gl_in[i].gl_Position.xyz;

        EmitVertex();

    }    

    EndPrimitive();

}

I think for my shadows the vertex shader should be this?
Is this correct?


#version 330 core

layout (location = 0) in vec3 position;



void main()

{

    gl_Position =   vec4(position, 1.0);

}

And Ifor the fragment shader.


#version 330 core



in vec3 TexCoords;

out vec4 FragColor;

uniform samplerCube depthMap;



void main()

{

    FragColor = texture(depthMap, TexCoords);

}

And this so far for the render code(1 cubemap);


            glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO[combineCubemapBuffer]);

            glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



            shaderCombineShadows.Use();

            // 0. Create depth cubemap transformation matrices

            GLfloat aspect = (GLfloat)SHADOW_WIDTH / (GLfloat)SHADOW_HEIGHT;

            glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f);

            glm::mat4 shadowProj = glm::perspective(90.0f, aspect, fNear, fFaar);

            glm::mat4 shadowTransform;



            for (int face = 0; face < 6; face++)

            {

                switch (face)

                {

                case 0:

                    shadowTransform = glm::mat4(shadowProj * glm::lookAt(position, position + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));

                    break;



                case 1:

                    shadowTransform = glm::mat4(shadowProj * glm::lookAt(position, position + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, -1.0, 0.0)));

                    break;



                case 2:

                    shadowTransform = glm::mat4(shadowProj * glm::lookAt(position, position + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0)));

                    break;



                case 3:

                    shadowTransform = glm::mat4(shadowProj * glm::lookAt(position, position + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, -1.0)));

                    break;



                case 4:

                    shadowTransform = glm::mat4(shadowProj * glm::lookAt(position, position + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));

                    break;



                case 5:

                    shadowTransform = glm::mat4(shadowProj * glm::lookAt(position, position + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, -1.0, 0.0)));

                    break;

                }



                glActiveTexture(GL_TEXTURE0);

                glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap[0]);

                glUniform1i(glGetUniformLocation(shaderCombineShadows.Program, "face"), face);

                glUniformMatrix4fv(glGetUniformLocation(simpleDepthShader.Program, "transform"), 1, GL_FALSE, glm::value_ptr(shadowTransform));

                glUniform1i(glGetUniformLocation(shaderCombineShadows.Program, "depthMap"), 0);

                RenderQuad();

                glBindFramebuffer(GL_FRAMEBUFFER, 0);

            }

render quad function:


    

// RenderQuad() Renders a 1x1 quad in NDC, best used for framebuffer color targets

// and post-processing effects.

GLuint quadVAO = 0;

GLuint quadVBO;

void RenderQuad()

{

    if (quadVAO == 0)

    {

        GLfloat quadVertices[] = {

            // Positions        // Texture Coords

            -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,

            -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,

            1.0f, 1.0f, 0.0f, 1.0f, 1.0f,

            1.0f, -1.0f, 0.0f, 1.0f, 0.0f,

        };

        // Setup plane VAO

        glGenVertexArrays(1, &quadVAO);

        glGenBuffers(1, &quadVBO);

        glBindVertexArray(quadVAO);

        glBindBuffer(GL_ARRAY_BUFFER, quadVBO);

        glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);

        glEnableVertexAttribArray(0);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);

        glEnableVertexAttribArray(1);

        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));

    }

    glBindVertexArray(quadVAO);

    glBindBuffer(GL_ARRAY_BUFFER, quadVBO);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindVertexArray(0);

}

Not copying the texture though , whats wrong?


Yes but I need multiple lights.


I wish to have shadows with multiple lights. Each light's shadow rendered to a depth cubemap. How do I render each cubemap onto a single cubemap with transparency so have a cubemap with all the shadows?

It's not clear what you want.

Shadow mapping works only for the single position of a single point light. You can not combine shadowmaps from multiple lights if they have different positions. (Cubemaps have 6 maps, but they are all relative to the same position.)

How is shadows with multiple lights done? That is what I need.



How is shadows with multiple lights done? That is what I need.

You have one shadow map for each light and iterate over all potential lights affecting a pixel.

Directional and spotlights need only a single shadowmap.

Only lights shining in every direction need a cubemap (rarely used).

We still use a lot of lights that don't cast any shadow at all.

For your usecase you should also read about shadow volumes (used in Doom 3, uncommon today but very accurate. Frictional Games also released their older engine source for the game Pemumbra which used it too).

How is shadows with multiple lights done? That is what I need.

You have one shadow map for each light and iterate over all potential lights affecting a pixel.

Directional and spotlights need only a single shadowmap.

Only lights shining in every direction need a cubemap (rarely used).

We still use a lot of lights that don't cast any shadow at all.

For your usecase you should also read about shadow volumes (used in Doom 3, uncommon today but very accurate. Frictional Games also released their older engine source for the game Pemumbra which used it too).

Thanks, I've looked into shadow volumes but can't find an example I can use for multi lighting.

Been going over Google for days, I'm getting tired.

Try shadow maps first, and only if it does not work look for shadow volumes.

I expected a problem with portals and shadow maps, but after thinking of it i guess i'm just wrong and shadow maps will work as expected if you render them with geometry seen through portals.

There is no big difference between multiple lights or a single light with any method, so tutorials focus mostly only a single light.

It's always the same: You iterate over all lights, check shadow for each, sum up received light if unshadowed.

(There are methods that cluster multiple lights as an optimization, but that's not fundamental tech you want to start with)

How you do this iteration depends on rendering techniques (forward vs. deferred), but determinating if in shadow or not is pretty independent of that.

Start with a single light. After you have this add shadowing, and finally move on to multiple lights - no need to learn all at once.

Also notice that shadowing == determinating visibilty of the light source. And visibility is THE primary problem in computer graphics, so don't expect perfect results in one day ;)

Try shadow maps first, and only if it does not work look for shadow volumes.

I expected a problem with portals and shadow maps, but after thinking of it i guess i'm just wrong and shadow maps will work as expected if you render them with geometry seen through portals.

There is no big difference between multiple lights or a single light with any method, so tutorials focus mostly only a single light.

It's always the same: You iterate over all lights, check shadow for each, sum up received light if unshadowed.

(There are methods that cluster multiple lights as an optimization, but that's not fundamental tech you want to start with)

How you do this iteration depends on rendering techniques (forward vs. deferred), but determinating if in shadow or not is pretty independent of that.

Start with a single light. After you have this add shadowing, and finally move on to multiple lights - no need to learn all at once.

Also notice that shadowing == determinating visibilty of the light source. And visibility is THE primary problem in computer graphics, so don't expect perfect results in one day ;)

I don't want to reinvent the wheel. Theres a book called opengl insights, chapter on multi lighting cubemaps with huge count. But it's for a version my laptop does not support, so ill have to buy a new pc.

Starting with the basics is not reinventing. (IIRC you are the guy said being new to OpenGL?)

The problem is, it's still unclear what you want. I even looked up the Insights book - there is no chapter about cube map lighting. Only about generating multiple shadow maps 'at once' using geometry shaders.

You need to describe the algorithm - what does it achieve and how does it get there? (Or give a proper reference to the right book / paper / tutorial)

And what harware limitation has your laptop? There might be a way around...

This topic is closed to new replies.

Advertisement