many people are saying defered shader is not accurate for transparency. I've done some with a small demo (Directx11) and would like to know the limit of this strategy when rendering opaque+transparent objects in deferred shaders. I would also like to know if it is possible to draw the shadow maps in the same MRT pass (provided there is 4 rendertargets) using maybe geometry shaders to change the transformed vertex output from world to light space? Note: because there's only one light i've found convenient to optimize one MRT as a single 8 bit (R8_UNIFORM) containing already calculated Dot3(N.L) and a specific blend ops for (let say ) good results. The colored shadow map comes from an explained demo seen somewhere in the web. The white color is needed to have correct colors for transparent shadows (otherwise they look darker). This technique is convenient for distant objects but not when they are too close because of possible self shadowing that is visible with transparent objects.

As I mention there is only one light used for this demo. This is why I'm using only R8 chanel to store dot3NL instead of the normal. This may save some resources and bandwitdh. Of course for many lights this will be a limitation of up to 4 lights per texture if you use RGBA chanels. regarding the code it's quite simple in VSchader output.norm = mul(input.norm, (float3x3(world)) in pShader flot L = dot(input.norm, lightdir) Output.Color1 (dot3map) = (Input.Col.a==1)?L:Input.Col.a*(1+L0.5f) here for opaque object the dot3 is taken as such. for transparent object the dot result is modulated to take into account the transparency. Using just L value gives to transparent object an opaque darkness where light is not facing. Using Input.Col.a(1+L*0.5f) insures that the dark part of the transparent object is still transparent. Modulating the 1 and 0.5 value gives different transparent lighting results.
This result is also dependent on the blending operation. Using Op ONE/ZERO Add and AlphaOp SRC_ALPH/INV_SRC_ALPHA Max gives darker blending than the one I used previously. As a result the object looks more like its shadow.This is what I'm using in the second image demo2 (with bump and reflexion added) demo2

Everything is explianed on it

  • \$\begingroup\$ It looks like you have a somewhat unconventional deferred rendering setup here. To make sure we're understanding your setup correctly, can you edit your question to walk through the steps of how your renderer works for a scene with multiple lights? What passes do you perform, and what outputs do you write from each? \$\endgroup\$
    – DMGregory
    Feb 18, 2022 at 18:29

1 Answer 1


What you are doing here is not deferred rendering. It is forward rendering with extra steps.

In deferred rendering, we do not consider lights during the G-Buffer pass. At all. All lighting calculations are delayed (deferred) to follow-up passes. This way, we spend no time computing lighting on surfaces that end up occluded by other opaque objects by the time all the geometry has been drawn.

Instead, a deferred renderer stores the normal direction into a G-Buffer texture, not the \$\vec n \cdot \vec l \$ term, along with the unlit, unshadowed, raw albedo colour of the objects.

We then follow up by rendering the bounding volumes of each light visible in the camera frustum, and performing our lighting computations only on the pixels in that volume that pass the depth test. This way, the lighting costs are proportionate to the number of unoccluded pixels those light volumes occupy on the screen. We've decoupled the lighting cost from the geometry complexity of the scene, since by the time we do lighting, the scene geometry is just a raster, and it doesn't matter how many different objects or triangles went into it. Lights that affect only a small part of the scene have only a small cost, even if they shine onto many objects in that small area.

But of course, doing lighting after the fact like this only works on opaque objects — otherwise you'd need to store layers of information in a single pixel, to be able to light the surface behind the transparency and the transparent surface in front of it independently. For that reason, deferred renderers usually use a forward pass at the end to layer any transparent objects on top.

Because your approach needs to consider all the lights at the time it builds the G-Buffer, it's effectively a forward renderer: your complexity scales as the product of the number of objects times the number of lights, rather than the sum. Not a big deal when you have only 1-4 lights, but it doesn't give you the ability to scale to very large numbers of lights like a deferred renderer does.

Storing only the \$\vec n \cdot \vec l \$ term is also only good for rendering the diffuse component of the lighting. Specular components will need a reflection vector too. So, you could either devote more G-Buffer space to storing specular info, or just accept that what you have is forward rendering and scrap the G-Buffer altogether. Use the dot products you've computed for your 1-4 lights and write the full shaded result straight to the frame buffer in one pass, as a normal forward renderer would. If you need to add extra lights, you can re-render the objects with your new light set, blending the results additively to account for the extra illumination these other lights provide on top of the first set.

  • \$\begingroup\$ Hi DMG. Thanks for the advice. I use now normal map which is simpler a the end, I have to check this story of light volume and depth. I'm currently doing this on all the quad. I mantain the shadow as forward mainly because I have transparent shadows. BUt i did it deferred as start. if you consider color1*src_alpha blend to color2*(1-src-alpha). if color1 and color2 are RGB1*dot(L.N1) and RGB2*dot(L.N2) is it possible to find any math equivalence to end up with blending of (RGB1,RGB2)*blending of dot(L, normalize(N1*N2)) or something like that. \$\endgroup\$
    – philB
    Mar 3, 2022 at 12:05
  • \$\begingroup\$ You can post that as a question if you like. \$\endgroup\$
    – DMGregory
    Mar 3, 2022 at 12:06
  • \$\begingroup\$ ok. sorry I'm new comer. I'm starting to better understand the phylosophy of this exchange site. \$\endgroup\$
    – philB
    Mar 3, 2022 at 12:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .