Sign in to follow this  
sofakng

Do I need to enable D3DRS_ALPHABLENDENABLE to use D3DRS_SRCBLEND? (Newbie question)

Recommended Posts

For some reason, blending modes are really, really confusing to me. According to the MSDN documentation, D3DRS_SRCBLEND and D3DRS_DESTBLEND are used to determine the "blending mode". Do I need to enable D3DRS_ALPHABLENDENABLE for D3DRS_SRCBLEND/D3DRS_DESTBLEND to have any meaning? When the term "blending" is used, does it always mean "alpha blending"? I was thinking that blending simply meant you look at the source pixel color (RGB) and the destination pixel color (RGB) and then you can add them together, multiply them, etc. Is this correct or this different from "alpha blending"?

Share this post


Link to post
Share on other sites
Quote:
Original post by sofakng
Do I need to enable D3DRS_ALPHABLENDENABLE for D3DRS_SRCBLEND/D3DRS_DESTBLEND to have any meaning?

Yes, SRC/DEST blend only actually matter when alphablending is enabled. If alphablending is disabled, they are ignored.

Quote:
Original post by sofakng
When the term "blending" is used, does it always mean "alpha blending"?

no, but GPUs are geared heavily towards alpha blending, and not towards regular blending. That is, all colors are blended, but the keys used for doing the actual blending are pretty much restricted to alpha values (or some derivative of the alpha value, like INV).

Quote:
Original post by sofakng
I was thinking that blending simply meant you look at the source pixel color (RGB) and the destination pixel color (RGB) and then you can add them together, multiply them, etc. Is this correct or this different from "alpha blending"?

GPUs are a bit more limited than that. IIRC, you can't do multiply at all in D3D9, and MAX and MIN are there in theory, but I don't think they are actually supported.
You are pretty much restricted to using SRCBLEND * SRCCOLOR + DESTBLEND * DESTCOLOR if you want to use the built in hardware that handles alpha blending. If you want to do something else, you might be able to pull something off with shaders, but that wouldn't utilize the hardware blending, most likely.

Hope this helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by sofakng
For some reason, blending modes are really, really confusing to me.

According to the MSDN documentation, D3DRS_SRCBLEND and D3DRS_DESTBLEND are used to determine the "blending mode".

Do I need to enable D3DRS_ALPHABLENDENABLE for D3DRS_SRCBLEND/D3DRS_DESTBLEND to have any meaning?

When the term "blending" is used, does it always mean "alpha blending"?

I was thinking that blending simply meant you look at the source pixel color (RGB) and the destination pixel color (RGB) and then you can add them together, multiply them, etc. Is this correct or this different from "alpha blending"?
Yes, D3DRS_ALPHABLENDENABLE enables the blending stages. That means you can set up D3DRS_SRCBLEND and D3DRS_DESTBLEND however you like, and then turn it on and off with D3DRS_ALPHABLENDENABLE.

No, the blending can affect colour as well as alpha.

A couple of examples...

1. Adding colour together (E.g. fire particle effects):

pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);




2. "Classic" alpha blending; higher alpha means more opaque

pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);




I'm useless at explaining this sort of stuff [smile]

Lets say you have a red texture at one quarter alpha (ARGB(0.25, 1, 0, 0)) which you're putting on a quad and rendering onto a blue backbuffer (ARGB(0, 0, 0, 1)).

The first example works like so:
Source_colour = RGB(1, 0, 0)
Source_factor = D3DBLEND_ONE (Alpha = 1)
Dest_colour = RGB(0, 0, 1)
Dest_factor = D3DBLEND_ONE (Alpha = 1)

Output = Source_colour * Source_factor + Dest_colour * Dest_factor
> Output = RGB(1, 0, 0) * 1 + RGB(0, 0, 1) * 1
> Output = RGB(1, 0, 0) + RGB(0, 0, 1)
> Output = RGB(1, 0, 1)


So you end up with a magenta colour.

The second example works like so:
Source_colour = RGB(1, 0, 0)
Source_factor = D3DBLEND_SRCALPHA (Alpha = 0.25)
Dest_colour = RGB(0, 0, 1)
Dest_factor = D3DBLEND_INVSRCALPHA (Alpha = 1 - 0.25 = 0.75)

Output = Source_colour * Source_factor + Dest_colour * Dest_factor
> Output = RGB(1, 0, 0) * 0.25 + RGB(0, 0, 1) * 0.75
> Output = RGB(0.25, 0, 0) + RGB(0, 0, 0.75)
> Output = RGB(0.25, 0, 0.75)


So you end up with a blue colour with a tint of red (Which makes sense, since you're blending a slightly opaque red quad onto a blue background).


Hope that helps.

Share this post


Link to post
Share on other sites
Thanks for the information.

It seems odd that I have to enable alpha-blending if I just want to multiply the source and destination colors. I understand if I multiply source*destination that alpha will be included, but suppose I'm only using an RGB format instead of RGB8? ...or suppose I don't care about alpha and just want to blend the colors together?

Are there any examples of how each of the blending modes actually look? (the standard ones... not the crazy stuff, heh)

Share this post


Link to post
Share on other sites
Quote:
Original post by sofakng
It seems odd that I have to enable alpha-blending if I just want to multiply the source and destination colors. I understand if I multiply source*destination that alpha will be included, but suppose I'm only using an RGB format instead of RGB8? ...or suppose I don't care about alpha and just want to blend the colors together?
That's what texture stage states are for. You can tell D3D to take the alpha values from the vertex colour instead of the texture, or from some constant value.

From my previous example, the alpha is only used in the second one, which only requires source alpha. So you could use:

// Take alpha from the constant, not the texture
pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_CONSTANT);

// Set the constant to 0.25 alpha (0x40 = 64 = 64/256 = 0.25)
pDevice->SetTextureStageState(0, D3DTSS_CONSTANT, 0x40000000);



Not all cards support D3DTSS_CONSTANT though, I'm not sure exactly what cards don't support it. There's a bunch of information in the above link anyway.

Share this post


Link to post
Share on other sites
Thanks for all of the excellent information! This really helps!

Now I think I understand how blending works but can you verify my examples below: (?)

(Using 0-255 scale instead of 0-1)

Example #1

Source Color: ARGB (150, 50, 50, 5)
Source Factor: D3DBLEND_SRCCOLOR = (150, 50, 50, 5)
Destination Color: ARGB (20, 10, 10, 100)
Destination Factor: D3DBLEND_SRCCOLOR = (150, 50, 50, 5)

Result: (150, 50, 50, 5) * (150, 50, 50, 5) + (20, 10, 10, 100) * (150, 50, 50, 5)

What would the result look like? Do you multiple each channel (?) together? (eg. the result would be: (150*150, 50*50, 50*50, 5*5) + (20*150, 10*50, 10*50, 100*5), or am I mistaken? That seems to generate HUGE numbers out of the valid range)

---

Example #2

Source Color: ARGB (150, 50, 50, 5)
Source Factor: D3DBLEND_SRCALPHA = (5, 5, 5, 5)
Destination Color: ARGB (20, 10, 10, 100)
Destination Factor: D3DBLEND_INVSRCCOLOR = (250, 250, 250, 250) [255-5?]

Result: (150, 50, 50, 5) * (5, 5, 5, 5) + (20, 10, 10, 100) * (250, 250, 250, 250)

What would this result look like? If my above understanding (from example #1) is correct, this would also generate huge, invalid, numbers. I'd also like to verify that source alpha is really (5, 5, 5, 5) instead of just (5), right?

Sorry for the long post...

Share this post


Link to post
Share on other sites
Blending is:

final = newcolor * srcblend [blendop] oldcolor * destblend.

Colors and alphas aren't treated as 0..255, but 0..1. Anything times white is unchanged. 50% grey times 50% grey is 25% grey, etc.

To perform a multiply blend you want the following:
D3DRS_SRCBLEND = D3DBLEND_DESTCOLOR
D3DRS_BLENDOP = D3DBLENDOP_ADD
D3DRS_DESTBLEND = D3DBLEND_ZERO

final = newcolor * oldcolor + oldcolor * 0

You can get a MODULATE2X effect by setting DESTBLEND to SRCCOLOR instead of ZERO.

Share this post


Link to post
Share on other sites
All these render states and the chunks they control can be confusing. That's why I have a state and a CAPS column in my pipeline poster. You can see the whole data flow and find a particular functional block, like alpha blending, and then look over in the state and CAPS column to see which portion of the device to manipulate to control that block.

I also wrote a C++ sample that lets you interactively explore all the blending capabilities on your card.

I also have a detailed discussion of alpha blending in my chapter on the frame buffer.

Share this post


Link to post
Share on other sites
Ok, I think my confusion is that alpha can only be between 0..1 BUT it is stored as 0..255. (0x00 to 0xFF)

So when doing the math for these blending operations, do I first normalize (is that the right word?) the alpha to be between 0 and 1? ...and then I use that value agains the real RGB values?

Example:

ARGB(128, 200, 0, 150) * SRC_ALPHA (0.5) = (200*0.5, 0*0.5, 150*0.5) = (100, 0, 75)

Is that correct?

Share this post


Link to post
Share on other sites
YOU don't have to do anything, Direct3D will know how to turn the values from 0-255 to 0-1. But if you want to make some calculations by urself (like when using shaders) you will get the values as floats between 0-1 anyway, so you don't need to make any conversions.
However, if you really need to work with these values completely manually, I would suggest to work only with integers and only convert the final result into float.
By the way, I don't think that this is called normalizing, because you do it only on the single value (the alpha), and not on a vector.

Share this post


Link to post
Share on other sites
Quote:
Original post by UriKiller
However, if you really need to work with these values completely manually, I would suggest to work only with integers and only convert the final result into float.


My suggestion is to do any work in floats and scale to the range 0-255 when you are done. I've seen too many people write incorrect calculations because they thought they were being clever by doing everything in integers. Your mileage may vary.

Quote:

By the way, I don't think that this is called normalizing, because you do it only on the single value (the alpha), and not on a vector.


Its not normalization (which makes things a unit length), but range conversion. You're mapping the integers in the range [0,255] to floating-point values in the range [0,1].

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this