Game Development Community

glBlendFunc(GL_SRC_ALPHA, GL_ONE) for TGEA?

by Steven Peterson · in Torque Game Engine Advanced · 02/11/2009 (5:07 pm) · 12 replies

I'm porting a bit of rendering code from TGE-1.5.2 to TGEA-1.8.0. The top piece of code works great. The second block of code comes close, but does not give the exact same result.

I believe the issue is in the "else" statement but am not sure. Does anyone know what the proper GFX code should be to match these openGL statements?

old code:
if (mIsAlpha)
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
else
   glBlendFunc(GL_SRC_ALPHA, GL_ONE);

new code:
if (mIsAlpha) {
   clouddesc.blendSrc = GFXBlendSrcAlpha;
   clouddesc.blendDest = GFXBlendInvSrcAlpha;
} else {
   clouddesc.blendSrc = GFXBlendSrcAlpha;
   clouddesc.blendDest = GFXBlendOne;
}

#1
02/11/2009 (9:41 pm)
It might just be that your aren't enabling the blending.

You should try "clouddesc.setBlend(true,GFXBlendSrcAlpha,GFXBlendInvSrcAlpha);" for the first and something similar for the second. That function just adds "clouddesc.blendDefined = true;" and "clouddesc.blendEnable = true;" to what you've already done.
#2
02/12/2009 (8:57 am)
William, very good thought! Unfortunately I already have enabled them. What else can I try?

- I will try adding your suggestion just in case.
- What are the 3 'zDefined', 'zEnabled', 'zWriteEnabled' lines for?
- Follows is the exact same code as above, with more context included.

TGE (excerpt of renderObject() )
if(!outlineOn)
   {
      glBindTexture(GL_TEXTURE_2D, mCloudHandle.getGLName());
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
      glEnable(GL_BLEND);

       if (mIsAlpha)
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
       else
         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   }

TGEA (excerpt of renderObject() )
if(!outlineOn)
   {
      if ( mCloudSB.isNull() ) {
         GFXStateBlockDesc clouddesc;
         clouddesc.samplersDefined = true;
         clouddesc.samplers[0] = GFXSamplerStateDesc::getWrapLinear();
         clouddesc.zDefined = true;
         clouddesc.zEnable = false;
         clouddesc.zWriteEnable = false;
         clouddesc.blendDefined = true;
         clouddesc.blendEnable = true;

         if (mIsAlpha) {
            clouddesc.blendSrc = GFXBlendSrcAlpha;
            clouddesc.blendDest = GFXBlendInvSrcAlpha;

         } else {
            clouddesc.blendSrc = GFXBlendSrcAlpha;
            clouddesc.blendDest = GFXBlendOne;
         }
         
         mCloudSB = GFX->createStateBlock(clouddesc);
      }
      GFX->setStateBlock(mCloudSB);
      GFX->setTexture(0,mCloudHandle);
   }
#3
02/12/2009 (10:43 am)
The next thing to try might be "clouddesc.zEnable = true;". From my experience, that will do a depth check before writing (as long as zDefined = true). The zWriteEnable tells the engine whether you want the new polygons to be added to the depth buffer.

Can you describe the way in which the new rendering looks different from the old?
#4
02/12/2009 (12:15 pm)
We are generating cloud layers. This is a compoisit effect where "x" number of layers (usually 3) are generated and rendered separately but treated as a single cloud layer.

IF (IsAlpha == true): These layers (usually just the bottom one, but shouldn't matter) has an alpha channel. The RGB for every pixele is a fixed grey-color and all variation happens in the alpha-channel. This creates a thin dark cloud-layer making the other layers look more gritty.

IF (IsAlpha == false): These layers ONLY have RGB channels. The brightness/color of each pixel is generated by the fractal-algorithm. However the transparency is also determined by the RGB brightness.
#FFFFFF == Solid White Pixel
#000000 == 100% Transparent Pixel
Thus the clouds "Fade-to-Transparent" rather than "Fade-to-black".

- I now believe it is the ELSE statement I actually have correct.

- It seems that on the (isAlpha == true) layers have cloudy and non-cloudy regions correctly determined by the alpha value. However, the opacity of the *cloudly* regions is being determined by the fixed RGB color. It's as if transparency is being calculated in two passes: first using the alpha channel, and second using the RGB intensity to operate on whats left over.

- With 1 & 2 layers this is working very close to correctly. Once I add 3 layers, flipping the isAlpha switch on different layers is causing some of the layers to fade-to-black...

All of this logic worked perfect in TGE, we're simply replacing the openGL ==> GFX for rendering and blending. I'm amazed at how many variations of "wrong" i'm getting by tweaking the parameters though.

Here's the bitmaps being declared.
if ( isAlpha )
         pBitmap = new GBitmap( MAP_SIZE, MAP_SIZE, false, GFXFormatR8G8B8A8 );
      else 
         pBitmap = new GBitmap( MAP_SIZE, MAP_SIZE, false, GFXFormatR8G8B8 );
      clampRGB(fractalMap, pBitmap, density, darkness, isAlpha);

#5
02/12/2009 (12:36 pm)
Screenshots:

3-Layers: bottom one (isAlpha == true)
Broken: with 3 layers on TGEA-1.8

TGE: Everything blends together seamlessly
CirrusSkies Fractal Clouds

OLD screenshot - clearly shows the dark "isAlpha" layer below other cloud layers
Orignal Effect

#6
02/12/2009 (6:37 pm)
Well... I've looked over your code and I'm stumped. I'm just gonna throw out some stuff and question to you and maybe somebody from GG familiar with the new StateBlock system will have an answer.

As I understand it, you have one "cloud" class? You make 3 instances like this (as seen from the side)?

~~~~~~~~~~~~  <- Top Layer (Pre-made fractal, no alpha)
~~~~~~~~~~~~  <- Middle Layer (Pre-made fractal, no alpha)
------------  <- Bottom Layer (Pre-made, alpha set)

When you say that 2 layers work "very close to correctly", do they look darker than they should? It looks like you have some kind of subtraction between the layers instead of a modulation.
#7
02/12/2009 (8:09 pm)
Good ASCII diagram .. In practice that's the idea exactly. Now in TGE I can have an arbitrary number of layers and alpha could be set on any or all of them, there's no hard-limitations and it all just works.

Now I actually have:
- Cloud-Layer Class (analogous to the quote-block you made)
- Cloud-SubLayer Class (analogous to the the 3 lines you drew IN the quote block)

Thus in the engine we instantiate a "cloud-layer" and manipulate it as a single object. But it actually contains "3" or "n" - "sublayers".

Quote:subtraction between the layers instead of a modulation.
They look ok, except when i have 3 layers and they start turning black on me. I'm not sure what you mean here though.
#8
02/12/2009 (9:31 pm)
In your class that has all 3 layers in one class, do you call the renderObject() function separately for each layer? Or does this function render all 3 layers in one call? Finally, do you only have only one GFXStateBlockRef in your class? Or do you have two, one for each type of render? (I ask becuase you'll probably need a separate GFXStateBlockRef for each type of layer.)

On the "subtraction", I was just noting that as you add layers, it appears to get darker. Like additive blending, there is a subtractive blending that starts to remove color and makes everything look darker. Nowhere does it look like you are setting up subtractive blending, but I thought I'd throw something out there.
#9
02/18/2009 (7:31 am)
Will,

Thanks for the tips. Don't think we're doing additive or subtractive blending.

the container-object has a renderObject() which sets up and closes the render state. In the middle is a for-loop that calls render() on each of the sub-layer objects. Which contains just that object-specific middle portion of the render routine.
#10
02/18/2009 (10:09 am)
SoneofaBitch! i *KNEW* it had to be a logic error!

mIsAlpha for each sublayer is set as an initPersistField{} member in the container-class and *is* ghosted to client and passed to the sub-layer objects. Thus I can change the value from the in-game editor.

However this new line (line #1 below) causes the world-editor changes to isAlpha to be ignored and the render-state for each layer is never updated.

Without adding a bool 'isDirtyFlag' I don't know how to check to see if isAlpha has changed since the last frame in this section of code .. :(

if ( mCloudSB.isNull() ) {
 
         ...

         if (mIsAlpha) {
            clouddesc.blendSrc = GFXBlendSrcAlpha;
            clouddesc.blendDest = GFXBlendInvSrcAlpha;

         } else {
            clouddesc.blendSrc = GFXBlendSrcAlpha;
            clouddesc.blendDest = GFXBlendOne;
         }
        
         mCloudSB = GFX->createStateBlock(clouddesc);
      }
      GFX->setStateBlock(mCloudSB);
      GFX->setTexture(0,mCloudHandle);
   }



[edit]
hmm it seems i can set mCloudSB to NULL at the time mIsAlpha changes. don't know if this is a memory leak .. but it works. :)
[/edit]

#11
02/18/2009 (10:21 am)
Could you check the bit change during the unpackUpdate call and re-create the state block there?
#12
02/18/2009 (10:41 am)
Yup .. that's exactly what I do .. I set it to NULL if the bit change is true in upackUpdate.

Thanks.