Sign in to follow this  

2D blending not work with DXUT

Recommended Posts

Hi All,
I have built a simple library which worked perfectly for 2D sprites. However when I ported this over to DXUT I am getting strange blending problems. At first everything seemed fine as the alpha channels for the sprites were transparent against the background, but when the sprites crossed each other the bounding box of the sprite became visible. See file attached.

I have created the simplest piece of code I can to demonstrate how I am doing things. I have based this on EmptyProject10.cpp that is comes with the DirectX SDK:


within this there are only two callback functions that I use OnD3D10ResizedSwapChain() and OnD3D10FrameRender(). All the code and the variables are below.

Any help would be greatly appreciated as I have been stuck on this for a long time.

Edit: I have also just realised that the colours are washed out when I am using DXUT. I have read somewhere that this is related to DXUT using DXGI_FORMAT_R8G8B8A8_UNORM_SRGB. However I have already spent ages tinkering with either trying to get DXUT to use DXGI_FORMAT_R8G8B8A8_UNORM or to get my textures to be DXGI_FORMAT_R8G8B8A8_UNORM_SRGB.

ID3DX10Sprite *pSpriteObject = NULL;
ID3D10ShaderResourceView *gSpriteTextureRV = NULL;
#define MAX_SPRITES 4
// Sprite structure
typedef struct
// sprite details
float width;
float height;
// sprite position
float posX;
float posY;
// sprite movement
float moveX;
float moveY;
BOOL visible;
GameSprite2 sprites[MAX_SPRITES] = {0};
// the number of active sprites
int numActiveSprites = 0;

HRESULT CALLBACK GameApplication::OnD3D10ResizedSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
// create and set the viewport
D3D10_VIEWPORT viewPort;
viewPort.Width = DXUTGetWindowHeight();
viewPort.Height = DXUTGetWindowWidth();
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0;
viewPort.TopLeftY = 0;
DXUTGetD3D10Device()->RSSetViewports(1, &viewPort);
// Create the default projection matrix

ID3D10Texture2D* texture = NULL;
ID3D10Resource* pRes = NULL;
//HRESULT hr = D3DX10CreateTextureFromFile(DXUTGetD3D10Device(), TEXT("./brick.bmp"), NULL, NULL, &pRes, NULL);
HRESULT hr = D3DX10CreateTextureFromFile(DXUTGetD3D10Device(), TEXT("./bitmaps/spheremapsmall.png"), NULL, NULL, &pRes, NULL);

// Translates the ID3D10Resource object into a ID3D10Texture2D object
pRes->QueryInterface(__uuidof( ID3D10Texture2D ), (LPVOID*)&texture);
if (texture == NULL)
CLogger::WriteInfoLog("failed to create texture");
return false;
// Get the texture details
// Create a shader resource view of the texture
ZeroMemory(&SRVDesc, sizeof(SRVDesc));
SRVDesc.Format = desc.Format;
SRVDesc.Texture2D.MipLevels = desc.MipLevels;
hr=DXUTGetD3D10Device()->CreateShaderResourceView(texture, &SRVDesc, &gSpriteTextureRV);
// release the texture
// Create the Sprite Batch, all sprite drawing is done through
// this object
hr = D3DX10CreateSprite(DXUTGetD3D10Device(), 0, &pSpriteObject);

// Initialize the blend state for alpha drawing
D3D10_BLEND_DESC StateDesc;
ZeroMemory(&StateDesc, sizeof(D3D10_BLEND_DESC));
StateDesc.AlphaToCoverageEnable = FALSE;
StateDesc.BlendEnable[0] = TRUE;
StateDesc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
StateDesc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
StateDesc.BlendOp = D3D10_BLEND_OP_ADD;
StateDesc.SrcBlendAlpha = D3D10_BLEND_ZERO;
StateDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
StateDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
StateDesc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
hr=DXUTGetD3D10Device()->CreateBlendState(&StateDesc, &pBlendState10);
// Loop through and set the defaults for the
// sprites in the pool
for (int i = 0; i < NUM_POOL_SPRITES; i++)
// Texture for this sprite to use
spritePool[i].pTexture = gSpriteTextureRV;
spritePool[i].TextureIndex = 0;
// top-left location in U,V coords
spritePool[i].TexCoord.x = 0;
spritePool[i].TexCoord.y = 0;
// Determine the texture size in U,V coords
spritePool[i].TexSize.x = 1;
spritePool[i].TexSize.y = 1;
spritePool[i].ColorModulate = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
// Create a diagonal line of overlapping sprites
for (int curSprite = 0; curSprite < MAX_SPRITES-1; curSprite++)
// Set the width and height of the sprite
sprites[curSprite].width = 64.0f;
sprites[curSprite].height = 64.0f;
// position in a diagonal so you can see overlap
sprites[curSprite].posX = 300+(curSprite*15);
sprites[curSprite].posY = 100+(curSprite*15);

sprites[curSprite].moveX = 0;
sprites[curSprite].moveY = 0;
// This sprite is visible
sprites[curSprite].visible = TRUE;

//create a single sprite on its own
sprites[MAX_SPRITES-1].width = 64.0f;
sprites[MAX_SPRITES-1].height = 64.0f;
sprites[MAX_SPRITES-1].posX = 100;
sprites[MAX_SPRITES-1].posY = 100;
sprites[MAX_SPRITES-1].visible = TRUE;

D3DXMATRIX matScaling;
D3DXMATRIX matTranslation;
int curPoolIndex = 0;
// Loop through the sprites
for (int i = 0; i < MAX_SPRITES; i++)
// only update visible sprites
if (sprites[i].visible)
CLogger::WriteInfoLog("OnFrameMove: moving sprites");
// set the proper scale for the sprite
D3DXMatrixScaling(&matScaling, sprites[i].width, sprites[i].height, 1.0f);
// Move the sprite to spritePosX, spritePosY
// SpriteWidth and SpriteHeight are divided by 2 to move the
// translation point to the top-left sprite corner instead of
// the center of the sprite.
(float)sprites[i].posX + (sprites[i].width/2),
(float)(DXUTGetWindowHeight() - sprites[i].posY - (sprites[i].height/2)), 0.1f);
// Update the sprites position and scale
spritePool[curPoolIndex].matWorld = matScaling * matTranslation;
// Increment the pool index
// set the number of active sprites
numActiveSprites = curPoolIndex;
return S_OK;

void CALLBACK GameApplication::OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
float ClearColor[4] = { 0.176f, 0.196f, 0.667f, 0.0f };

pd3dDevice->ClearRenderTargetView( DXUTGetD3D10RenderTargetView(), ClearColor );
//pd3dDevice->ClearRenderTargetView( DXUTGetD3D10RenderTargetView(), D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f) );
pd3dDevice->ClearDepthStencilView( DXUTGetD3D10DepthStencilView(), D3D10_CLEAR_DEPTH, 1.0, 0 );
FLOAT OriginalBlendFactor[4];
UINT OriginalSampleMask = 0;
if (DXUTGetD3D10Device() != NULL)
// clear the target buffer
//pD3DDevice->ClearRenderTargetView(pRenderTargetView, D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f));
if (pSpriteObject != NULL)

HRESULT hr = pSpriteObject->SetProjectionTransform(&matProjection);
// start drawing the sprites
// Draw all the sprites in the pool

hr=pSpriteObject->DrawSpritesBuffered(spritePool, numActiveSprites);
// Save the current blend state
DXUTGetD3D10Device()->OMGetBlendState(&pOriginalBlendState10, OriginalBlendFactor, &OriginalSampleMask);
// Set the blend state for alpha drawing
FLOAT NewBlendFactor[4] = {0,0,0,0};
DXUTGetD3D10Device()->OMSetBlendState(pBlendState10, NewBlendFactor, 0xffffffff);
// Finish up and send the sprites to the hardware
// Restore the previous blend state
DXUTGetD3D10Device()->OMSetBlendState(pOriginalBlendState10, OriginalBlendFactor, OriginalSampleMask);
[/CODE] Edited by benp444

Share this post

Link to post
Share on other sites
Alpha blended sprites need to be sorted back to front.

The problem lies in the fact that the depth buffer values for a pixel get written even though said pixel would appear to be transparent due to its alpha value.

Share this post

Link to post
Share on other sites
Thanks for your response. I changed the code above from




However this hasn't changed the result in any way. I still get the image attached to the OP.

Is there something else I need to be doing?

Share this post

Link to post
Share on other sites
If you don't care about the sprite ordering, disable depth testing (and don't sort). If you do care about the ordering, assign meaningful depth values to the sprites for the depth sort to work :)

Share this post

Link to post
Share on other sites
Thanks Niko for your help. I have disabled the depth and the the bounding boxes are no longer visible.

To fix the issue I have added the following code to the OnD3D10ResizedSwapChain() method:

D3D10_DEPTH_STENCIL_DESC depthDisabledStencilDesc;
ZeroMemory(&depthDisabledStencilDesc, sizeof(depthDisabledStencilDesc));

depthDisabledStencilDesc.DepthEnable = false;
depthDisabledStencilDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
depthDisabledStencilDesc.DepthFunc = D3D10_COMPARISON_LESS;
depthDisabledStencilDesc.StencilEnable = true;
depthDisabledStencilDesc.StencilReadMask = 0xFF;
depthDisabledStencilDesc.StencilWriteMask = 0xFF;
depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_INCR;
depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
depthDisabledStencilDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
depthDisabledStencilDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_DECR;
depthDisabledStencilDesc.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
depthDisabledStencilDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;

hr = DXUTGetD3D10Device()->CreateDepthStencilState(&depthDisabledStencilDesc, &g_pDepthDisabledStencilState);
DXUTGetD3D10Device()->OMSetDepthStencilState(g_pDepthDisabledStencilState, 1);

The colours are still washed out, but this is a separate issue may raise seperately.

Ben. Edited by benp444

Share this post

Link to post
Share on other sites
Color washout is a separate issue. It is usually related to color space and/or gamma issues. Search for "srgb d3d" to find more info ;)

Share this post

Link to post
Share on other sites
Great! and the solution to the washed out colour is to create a new SRGB texture in memory (not from file), copy the non-SRGB texture (from file) into it and use that to create the texture resource. See method below. Now my balls are perfect!

ID3D10Texture2D* GameManager::convertTextureToSRGB(ID3D10Texture2D* srcTexture){
if(srcTexture==NULL) {
throw GameException(E_POINTER,"GameManager::convertTextureToSRGB: srcTexture was null");
D3D10_TEXTURE2D_DESC origDesc;
D3D10_TEXTURE2D_DESC srgbDesc;
ZeroMemory( &srgbDesc, sizeof(srgbDesc));
srgbDesc.Width = origDesc.Width;
srgbDesc.Height = origDesc.Height;
srgbDesc.MipLevels = 1;
srgbDesc.ArraySize = 1;
srgbDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
srgbDesc.SampleDesc.Count = 1;
srgbDesc.Usage = D3D10_USAGE_DYNAMIC;
srgbDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
srgbDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
ID3D10Texture2D *pSRGBTexture = NULL;
HRESULT hr=DXUTGetD3D10Device()->CreateTexture2D( &srgbDesc, NULL, &pSRGBTexture );
//copy the original texture in the into the SRGB texture
D3D10_BOX sourceRegion;
sourceRegion.left = 0;
sourceRegion.right = origDesc.Width; = 0;
sourceRegion.bottom = origDesc.Height;
sourceRegion.front = 0;
sourceRegion.back = 1;
DXUTGetD3D10Device()->CopySubresourceRegion(pSRGBTexture, 0, 0, 0, 0, srcTexture, 0,&sourceRegion);
return pSRGBTexture;

Share this post

Link to post
Share on other sites
This process (in general) is usually called "color space conversion" and can be avoided if you author the textures in the destination space to begin with. Alternatively, you can specify a destination format manually (via the pLoadInfo parameter of the load function) when you load the texture.

Glad to hear you got your balls working [img][/img] Edited by Nik02

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