Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am new to DirectX development and I am wondering if I am taking the wrong route to achieve the following:

I would like to mix three textures which contain transparent areas and some solid areas (Red, Blue, Green). The three textures should blend like shown in this example:

enter image description here

How can I achieve that in DirectX (preferably in directx9)?

A link or example code would be nice.

Update:

My rendering method looks like this and I still think I am doing it wrong, because the sprite only shows the last texture (nothing is rendered transparent or blended):

void D3DTester::render()
{
d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
d3ddevice->BeginScene();

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

LPD3DXSPRITE sprite=NULL;
HRESULT hres = D3DXCreateSprite(d3ddevice, &sprite);
if(hres != S_OK)
{
    throw std::exception(); 
}

sprite->Begin(D3DXSPRITE_ALPHABLEND);

std::vector<LPDIRECT3DTEXTURE9>::iterator it;
for ( it=textures.begin() ; it < textures.end(); it++ )
{
    sprite->Draw(*it, NULL, NULL, NULL, 0xFFFFFFFF);
}

sprite->End();

d3ddevice->EndScene();
d3ddevice->Present(NULL, NULL, NULL, NULL);
}

The resulting image looks like this:

enter image description here

But I need it to look like this instead:

enter image description here

Update2: I figured out that I have to SetRenderState after I use sprite->Begin(D3DXSPRITE_ALPHABLEND); thanks to the hint by Josh Petrie. However, by using this:

    sprite->Begin(D3DXSPRITE_ALPHABLEND);

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

std::vector<LPDIRECT3DTEXTURE9>::iterator it;
for ( it=textures.begin() ; it < textures.end(); it++ )
{   
    sprite->Draw(*it, NULL, NULL, NULL, 0xFFFFFFFF);
}
sprite->End();      

The sprites colors are becoming transparent towards the background scene e.g.: if I use d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,100,21), 1.0f, 0); the result looks like:

enter image description here

Is there any way to avoid that? I would like the sprites be transparent to each other but to be still solid to the background.

Update3: After having sombody explained to me, how to do what @LaurentCouvidou and @JoshPetrie suggested, I have a working solution and therfore accept the answer:

d3ddevice->BeginScene();

D3DCOLOR white = D3DCOLOR_RGBA((UINT)255, (UINT)255, (UINT)255, 255);
D3DCOLOR black = D3DCOLOR_RGBA((UINT)0, (UINT)0, (UINT)0, 255);

sprite->Begin(D3DXSPRITE_ALPHABLEND);
sprite->Draw(pTextureRed, NULL, NULL, NULL, black);
sprite->Draw(pTextureGreen, NULL, NULL, NULL, black);
sprite->Draw(pTextureBlue, NULL, NULL, NULL, black);
sprite->End();       


sprite->Begin(D3DXSPRITE_ALPHABLEND);
d3ddevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
d3ddevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
sprite->Draw(pTextureRed, NULL, NULL, NULL, white);
sprite->Draw(pTextureGreen, NULL, NULL, NULL, white);
sprite->Draw(pTextureBlue, NULL, NULL, NULL, white);
sprite->End();

d3ddevice->EndScene();
d3ddevice->Present(NULL, NULL, NULL, NULL);
share|improve this question

2 Answers 2

up vote 1 down vote accepted

The ID3DXSprite interface will modify the render states of the device when you call the Begin method. The specifics of the state modifications that will be performed are detailed in the method's documentation. In particular, note that the source and destination blend modes are set to 'source alpha' and 'inverse source alpha,' respectively. This enables the typical blending behavior wherein the alpha component of the color is used to control how transparent a pixel is.

Since this isn't what you want, you should pass the D3DXSPRITE_DONOTMODIFY_RENDERSTATE flag to Begin and ensure, as the documentation notes, that

The device is assumed to be in a valid state to draw vertices containing UsageIndex = 0 in the D3DDECLUSAGE_POSITION, D3DDECLUSAGE_TEXCOORD, and D3DDECLUSAGE_COLOR data.

By doing this, the render states you set up to blend the way you want will be preserved. You may note that doing this changes some other aspect of your render behavior, and that is probably due to your not setting other render states to the values described in the documentation for Begin.

As an aside, you shouldn't test HRESULT values against specific constants (like S_OK) if all you want to know is success or failure -- as is the case in your code. There are multiple success or failure codes. Prefer the SUCCEEDED or FAILED macro as appropriate.

share|improve this answer
    
Thanks for the hint to those SUCCEEDED/FAILED marcos (+1 for that) I will try out your suggestion and have a look into the docs first. –  tobsen May 24 '12 at 15:37
    
I tried your suggestions but now the three sprites are not only transparent towards each other but also transparent in regards to the "background scene". Any idea how to avoid that and to have the output as shown in the first picture? –  tobsen May 25 '12 at 9:02
    
That's, uh, weird looking. I'm not sure how you get that greenish hue for the background -- are you rendering fullscreen quads for all of these? Could you update/post more of your code? –  Josh Petrie May 25 '12 at 14:34
2  
I don't think that's possible in one pass, you'll have to render your 3 sprites first as complete black, and then re-render using additive blending. –  Laurent Couvidou May 28 '12 at 14:20
2  
Ah, I see, yes, I missed that your background was no longer a solid black. Because you are blending additively your sprites will add their color to the background color already present in the frame buffer, so a two-pass solution as lorancou describes should solve it. –  Josh Petrie May 28 '12 at 14:22

This is known as Additive Blending.

In DirectX9, you use a few render states to set that up:

pDirect3DDevice9->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pDirect3DDevice9->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
pDirect3DDevice9->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
share|improve this answer
    
I updated the question showing the sample code. –  tobsen May 24 '12 at 14:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.