Alpha Blending of D3DTexture9

Started by
3 comments, last by odyodyodys 15 years, 5 months ago
Hi all, I have a texture (IDirect3DTexture9) and want to alpha blend an image on it.. I thought this would be an easy part, but I am in trouble now... What I am trying to do is simple: Copy an alpha blended image on top of that texture

// Get the texture from the Allcator presenter (Because Im using Vmr9 + allocator presenter)
CComPtr<IDirect3DTexture9> texture;
presentationInfo->lpSurf->GetContainer( IID_IDirect3DTexture9, (LPVOID*) &(texture.p) );

// Create a surface from that texture
CComPtr<IDirect3DSurface9> baseSurface;
texture->GetSurfaceLevel(0, &baseSurface);


// Create a surface from the image file
CComPtr<IDirect3DSurface9> imageSurface;

direct3DDevice->CreateOffscreenPlainSurface(640, 480, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &imageSurface, NULL);

D3DXLoadSurfaceFromFile(imageSurface.p, NULL, NULL, L"c:\\1.bmp", NULL, D3DX_DEFAULT, 0, NULL);


// Stretch images
direct3DDevice->StretchRect(imageSurface.p, NULL, baseSurface.p, NULL, D3DTEXF_NONE );


This works ok, but I don't have alpha blending.. (No errors returned) The image covers the whole texture.. (The bmp has an alpha channel of course..) I read that this can also be done with ID3DXSprite, but I don't know where to start. Are there any easy or difficult ways to copy an image onto a texture with alpha? P.S. Everything uses D3DPOOL_DEFAULT. Also, on the D3DDevice initialization: direct3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); direct3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); direct3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); direct3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); direct3DDevice->SetRenderState(D3DRS_ALPHAREF, 0x00); direct3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
Advertisement
You can't copy onto a texture and do alpha blending since the pixels are just replaced.

If you want to alpha blend two or more images, you'll have to do a render-to-texture, using the target texture as a render target.
However, it'll be far easier to just alpha blend to the backbuffer using ID3DXSprite. You'd just render all your textures on top of each other as seperate Draw() calls.
Quote:Original post by Evil Steve
If you want to alpha blend two or more images, you'll have to do a render-to-texture, using the target texture as a render target.
However, it'll be far easier to just alpha blend to the backbuffer using ID3DXSprite. You'd just render all your textures on top of each other as seperate Draw() calls.


Thanks for your reply,
but it was not that helpful cause I am beginner in d3d!

Is it possible to explain some more?
Quote:Original post by odyodyodys
Quote:Original post by Evil Steve
If you want to alpha blend two or more images, you'll have to do a render-to-texture, using the target texture as a render target.
However, it'll be far easier to just alpha blend to the backbuffer using ID3DXSprite. You'd just render all your textures on top of each other as seperate Draw() calls.


Thanks for your reply,
but it was not that helpful cause I am beginner in d3d!

Is it possible to explain some more?
Use D3DXCreateSprite to get an ID3DXSprite interface at load time, and then load any textures you want using D3DXCreateTextureFromFile or D3DXCreateTextureFromFileEx. Then, to alpha blend the textures together, just render them on top of each other:
LPD3DXSPRITE pSprite; // Your sprite, initialised from D3DXCreateSpriteLPDIRECT3DTEXTURE9 pTex1, pTex2, pTex3; // Your textures, initialised from D3DXCreateTextureFromFile[Ex]// Begin sprite renderingif(SUCCEEDED(pSprite->Begin(D3DXSPRITE_ALPHABLEND))){   D3DXVECTOR3 vPos(0, 0, 0); // Position to draw the blended textures at   pSprite->Draw(pTex1, NULL, NULL, &vPos, D3DCOLOR_RGBA(255, 255, 255, 255));   pSprite->Draw(pTex2, NULL, NULL, &vPos, D3DCOLOR_RGBA(255, 255, 255, 255));   pSprite->Draw(pTex3, NULL, NULL, &vPos, D3DCOLOR_RGBA(255, 255, 255, 255));   pSprite->End();}

That'll draw all three textures, alpha blended together in the top left of the backbuffer.
Thank you!

That was really helpful..

Unfortunately, I cannot use this method cause I have implemented an Allocator-Presenter filter to use with VMR9 in a custom video player.
This brings me a texture with the current frame on it.
I want to draw an image (eg. logo) on top of this frame..

What I've done till now is the following:
// I have the texture (frame) in the "texture" variable which is a ID3DTexture9.// 1. Get the surface description from the texture.D3DSURFACE_DESC surfaceInfo;texture->GetLevelDesc(0, &surfaceInfo);//2. Create a new surfaceCComPtr<IDirect3DSurface9> firstSurface;hr = _direct3DDevice->CreateOffscreenPlainSurface(surfaceInfo.Width, surfaceInfo.Height, surfaceInfo.Format, D3DPOOL_SYSTEMMEM, &(firstSurface.p), NULL );//3. get the surface from the texturehr = texture->GetSurfaceLevel(0, &(firstSurface.p));//3.a  Create a surface on the System memory (the previous one is on the Device)CComPtr<IDirect3DSurface9> systemSurface;hr = _direct3DDevice->CreateOffscreenPlainSurface(surfaceInfo.Width, surfaceInfo.Height, surfaceInfo.Format, D3DPOOL_SYSTEMMEM, &(systemSurface.p), NULL );// a. Copy from DeviceMem to SystemMemhr = this->_direct3DDevice->GetRenderTargetData(firstSurface.p, systemSurface.p );//4. Lock the surfaceD3DLOCKED_RECT lockedRect;hr = systemSurface->LockRect(&lockedRect, NULL, D3DLOCK_DONOTWAIT | D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK);//5. Create another surface with alpha format in the system memory (so it is possible to blit between alpha surfaces)CComPtr<IDirect3DSurface9> alphaSystemSurface;hr = _direct3DDevice->CreateOffscreenPlainSurface(surfaceInfo.Width, surfaceInfo.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &(alphaSystemSurface.p), NULL );//6. Lock the alphaSurface before blittingD3DLOCKED_RECT alphaLockedRect;hr = alphaSystemSurface->LockRect(&alphaLockedRect, NULL, D3DLOCK_DONOTWAIT | D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK);//7. blit using BitBltFromRGBToRGB function from MediaPlayerClassic source code.// Dont care about this at the moment. The original surface can be the same as the last one.//8. Create another surface that does not has alpha color format (this will be updated)CComPtr<IDirect3DSurface9> noAlphaSystemSurface;hr = _direct3DDevice->CreateOffscreenPlainSurface(surfaceInfo.Width, surfaceInfo.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &(noAlphaSystemSurface.p), NULL );// 9. Update the surface (copy the noAlpha system surface to device surface) both are of the same format and size.hr = this->_direct3DDevice->UpdateSurface(noAlphaSystemSurface.p , NULL, firstSurface.p, NULL ); // FAILS with D3DERR_INVALIDCALL (0x8876086c)// 10. Present the texture. (works ok)Any suggestions on what am I doing wrong?

This topic is closed to new replies.

Advertisement