Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 1 of 1

Thread: Deferred shading implementation

  1. #1
    Newbie Newbie
    Join Date
    Jun 2018
    Posts
    2

    Deferred shading implementation

    Hi,

    I have implemented simple deferred rendering.
    Here is the render loop:
    Code :
    for (auto cam : EntitySystem::instance()->_cameras) {
    	perCameraUpdate(cam);		//shadowMaps, frustum update, terrain lod, camera ubo
    	drawToGBuffer(cam);
     
    	//write to lightmap
    	applyDirectionalLights(cam);
    	applySpotlights(cam);
    	applyPointLights(cam);
     
    	deferredShading(cam);
    }
    This is the gBuffer:
    Code :
    _depthComponentTexture = new Texture(_width, _height, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_NEAREST);		
    _worldNormalSpecPower = new Texture(_width, _height, GL_RGBA16F, GL_RGBA, GL_NEAREST);
    _albedoSpecularIntensity = new Texture(_width, _height, GL_RGBA8, GL_RGBA, GL_NEAREST);
    _3unusedShaderless = new Texture(_width, _height, GL_RGBA8, GL_RGBA, GL_NEAREST);
    I don't know if gBuffer internal format is correct. Should bytes of internal format add up? GL_RGBA16F = 8 bytes and GL_RGBA8 is 4 bytes.
    Position is reconstructed from depth like this:
    Code :
    vec3 worldSpaceFromDepth(in float depth) {
        float z = depth * 2.0 - 1.0;
     
        vec4 clipSpacePosition = vec4(uv0 * 2.0 - 1.0, z, 1.0);
        vec4 direct = pc.projectionCameraMatInverse * clipSpacePosition;
        return direct.xyz / direct.w;
    }
    If _3unusedShaderless.a is 1 lighting is discarded and its used for debug lines, skybox etc.
    The lighting is done in world space. If i do lighting in view space then normal can be encoded with spheremap transform to vec2, it might be worth it.

    Point light pass, same for other lights:
    Code :
    void DeferredRenderer::applyPointLights(Camera* cam) {
    	auto shader = _pointLightShader;
    	auto pointLightsArray = Scene::instance()->_inFrustum_pointsLights;
     
    	shader->bind();
    	shader->updateUniforms();
    	shader->setBlend(1);
    	cam->_fbo->bindFbo();
    	cam->getGBuffer().bindGBufferReadAt(0);
    	cam->_fbo2->getTexture().bind(4);  //read previous lights and add to current
     
    	unsigned i = 0;
    	while (true) {
    		if (i == pointLightsArray.size()) break;
     
    		//glClear(GL_COLOR_BUFFER_BIT);  //it works without clearing fbo1 for some reason
     
    		unsigned j = 0;
    		for (; i < pointLightsArray.size() && j < 50; ++i, ++j) {//batch of 50 shadowless lights
    			auto pl = pointLightsArray[i];
    			UniformBufferObjects::instance()->pushPointLightToUBO(pl, j);
    		}
    		UniformBufferObjects::instance()->setPointLightsCount(j);
    		UniformBufferObjects::instance()->updatePointLightUBO();
     
    		_ndsQuad->draw();
    		Graphics::instance()->fboToFbo(cam->_fbo->getFramebufferID(), cam->_fbo2->getFramebufferID()); //fbo blit, copy cur lightmap to fbo2
    	}
    }
    Light shader:
    Code :
    #version 330
    out vec4 outColor;
    void main(){
    	if(int(texture2D(g_unusedShadeless, uv0).a) == 1) return;
    	initData();
     
    	vec3 result = CalcDirLight();
    	outColor = vec4(result + texture2D(previousDraw, uv0).xyz * blend, 1.0);
    }
    Position is reconstructed and if fragment is not in lights range its discarded.
    Point and spot lights have no shadow maps for now. Lights are rendered in batches, 4 textures from gbuffer + shadowMap + lightMap = 6 textures -> 5 lights with shadows per batch.
    Batching lights is way faster then rendering one by one. Blitting fbos to accumulate light seems like a hack, can this be done any other way?

    I cant get transparency for sun to work. It worked it forward rendering, does it have something to do with MRTs?
    Skybox is just a cube and sun a plane.
    Draw sun:
    Code :
    glEnable(GL_BLEND);
    glBlendEquation(GL_FUNC_ADD);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    Assets::instance()->fetchMesh("NDS_QUAD")->draw();
    glDisable(GL_BLEND);
    Skybox shader:
    Code :
    #version 330
    int main(){
    vec4 color = texture(diffuse, uv0);
    out_g_worldNormalSpecPower = vec4(0.0, 0.0, 0.0, 0.0);
    out_g_albedoSpecIntesity = vec4(color);
    out_g_unusedShadeless = vec4(0,0,0,1);
    }
    Sun shader:
    Code :
    #version 330
    int main(){
    vec4 difColor = texture2D(diffuseTex, uv0) * sunColor;		//sun color = glm::vec4(1, 1, 0.6, 1), diffuseTex = white halo
    out_g_worldNormalSpecPower = vec4(0);
    out_g_albedoSpecIntesity = vec4(difColor.xyz, 0);
    out_g_unusedShadeless = vec4(0,0,0,1);
    }
    Have yet to implement transparency.
    Transparency:
    - sort transparent objects by z axis
    - draw them in forward rendering
    - discard every pixels by comparing them with depth from gBuffer
    - calculate all lights in frustum
    Is this a good idea?
    Thanks for reading!
    Click image for larger version. 

Name:	deferred.jpg 
Views:	54 
Size:	19.7 KB 
ID:	2794
    Click image for larger version. 

Name:	sun.jpg 
Views:	47 
Size:	15.8 KB 
ID:	2795
    Click image for larger version. 

Name:	sun.png 
Views:	37 
Size:	15.0 KB 
ID:	2796
    Last edited by someRand; 06-30-2018 at 03:52 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •