Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualTsus

Posted 29 April 2013 - 10:04 AM

Hi,

 

Your suggestion is already the solution. So, yeah, you got it right. I'll summarize the steps briefly for you:


Your transparent rendering would happen in the rendering loop after the deferred pass:

  1. Fill your deferred buffer (color, depth, …)
  2. Do the deferred lighting
  3. Render the transparent objects

For the last step, do the following:

  1. Disable depth writing (glDepthMask) -> we want no transparent object to be culled by other transparent objects
  2. Enable depth test (glDepthTest) -> compare with your deferred depth buffer (cull by opaque geometry)
  3. Use additive blending (source: GL_ONE, dest: GL_ONE)
  4. Bind two new render targets; let’s call them AccumColors (four (half) float components) and AccumCount (single float component)
  5. Render the transparent objects into those two targets (explained in a moment)
  6. Bind deferred color buffer as render target
  7. Disable depth test (glDepthTest)
  8. Use back-to-front blending (source: GL_ONE_MINUS_SRC_ALPHA, dest: GL_SRC_ALPHA)
  9. Bind AccumColor and AccumCount as textures
  10. Full screen pass: compute the average color/transparency (explained in a moment) and blend with the deferred color buffer

The idea is to compute the average of the colors, weighted by their transparencies. For blending with the background, we additionally need the average opacity. (FYI: I assume that alpha = 1 means opaque, and alpha = 0 means transparent)

 

Step 5 computes the sums. This is what the fragment shader does:

Input: vec3 color, float alpha
Output: 
  AccumColor = vec4(color*alpha, alpha);  // color multiplied (=weighted) with alpha!
  AccumCount = 1;

 

Step 10 compute the average color. Again, the fragment shader:

Input: vec4 AccumColor, float AccumCount

if (AccumCount < 0.00001 || AccumColor.w < 0.00001)
{
  discard;  // nothing here; discard the fragment.
}
else
{
  vec4 avgColor = vec4(
  AccumColor.xyz / AccumColor.w,    // weighted average color
  AccumColor.w / AccumCount);        // average alpha
  // the alpha, used to blend with the background is computed by assuming 
  // that all transparent layers have the average alpha:
  float dstAlpha = 1-pow(max(0,1-avgColor.w), AccumCount);
  // write out the average color and the alpha, used for compositing
  result = vec4 (avgColor.xyz, dstAlpha);
}

Hope that gives some insights. smile.png

Best regards!


 


#1Tsus

Posted 21 April 2013 - 08:54 AM

Hi,

 

Your suggestion is already the solution. So, yeah, you got it right. I'll summarize the steps briefly for you:


Your transparent rendering would happen in the rendering loop after the deferred pass:

  1. Fill your deferred buffer (color, depth, …)
  2. Do the deferred lighting
  3. Render the transparent objects

For the last step, do the following:

  1. Disable depth writing (glDepthMask) -> we want no transparent object to be culled by other transparent objects
  2. Enable depth test (glDepthTest) -> compare with your deferred depth buffer (cull by opaque geometry)
  3. Use additive blending (source: GL_ONE, dest: GL_ONE)
  4. Bind two new render targets; let’s call them AccumColors (four (half) float components) and AccumCount (single float component)
  5. Render the transparent objects into those two targets (explained in a moment)
  6. Bind deferred color buffer as render target
  7. Disable depth test (glDepthTest)
  8. Use back-to-front blending (source: GL_ONE_MINUS_SRC_ALPHA, dest: GL_SRC_ALPHA)
  9. Bind AccumColor and AccumCount as textures
  10. Full screen pass: compute the average color/transparency (explained in a moment) and blend with the deferred color buffer

The idea is to compute the average of the colors, weighted by their transparencies. For blending with the background, we additionally need the average opacity. (FYI: I assume that alpha = 1 means opaque, and alpha = 0 means transparent)

 

Step 4 computes the sums. This is what the fragment shader does:

Input: vec3 color, float alpha
Output: 
  AccumColor = vec4(color*alpha, alpha);  // color multiplied (=weighted) with alpha!
  AccumCount = 1;

 

Step 10 compute the average color. Again, the fragment shader:

Input: vec4 AccumColor, float AccumCount

if (AccumCount < 0.00001 || AccumColor.w < 0.00001)
{
  discard;  // nothing here; discard the fragment.
}
else
{
  vec4 avgColor = vec4(
  AccumColor.xyz / AccumColor.w,    // weighted average color
  AccumColor.w / AccumCount);        // average alpha
  // the alpha, used to blend with the background is computed by assuming 
  // that all transparent layers have the average alpha:
  float dstAlpha = 1-pow(max(0,1-avgColor.w), AccumCount);
  // write out the average color and the alpha, used for compositing
  result = vec4 (avgColor.xyz, dstAlpha);
}

Hope that gives some insights. smile.png

Best regards!


 


PARTNERS