Jump to content

  • Log In with Google      Sign In   
  • Create Account


2D blending not work with DXUT


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 benp444   Members   -  Reputation: 177

Like
0Likes
Like

Posted 01 May 2012 - 04:01 AM

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:

..\MicrosoftDirectXSDKJune2010\Samples\C++\Direct3D10\EmptyProject10

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.

#define NUM_POOL_SPRITES 32
D3DX10_SPRITE			spritePool[NUM_POOL_SPRITES];
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;
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
D3DXMatrixOrthoOffCenterLH(&matProjection,
  (float)viewPort.TopLeftX,
  (float)viewPort.Width,
  (float)viewPort.TopLeftY,
  (float)viewPort.Height,
  0.1f,
  10);


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);
testHr("OnD3D10ResizedSwapChain:D3DX10CreateTextureFromFile",hr);

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

// 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);
testHr("OnD3D10ResizedSwapChain:CreateBlendState",hr);
// 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.
   D3DXMatrixTranslation(&matTranslation,
	(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
   curPoolIndex++;
  }
}
// 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);
   testHr("OnD3D10FrameRender:SetProjectionTransform",hr);
   // start drawing the sprites
   hr=pSpriteObject->Begin(D3DX10_SPRITE_SORT_TEXTURE);
   testHr("OnD3D10FrameRender:Begin",hr);
   // Draw all the sprites in the pool
  
   hr=pSpriteObject->DrawSpritesBuffered(spritePool, numActiveSprites);
   testHr("OnD3D10FrameRender:DrawSpritesBuffered",hr);
   // Save the current blend state
   DXUTGetD3D10Device()->OMGetBlendState(&pOriginalBlendState10, OriginalBlendFactor, &OriginalSampleMask);
   // Set the blend state for alpha drawing
   if(pBlendState10)
   {
	FLOAT NewBlendFactor[4] = {0,0,0,0};
	DXUTGetD3D10Device()->OMSetBlendState(pBlendState10, NewBlendFactor, 0xffffffff);
   }
   // Finish up and send the sprites to the hardware
   hr=pSpriteObject->Flush();
   testHr("OnD3D10FrameRender:Flush",hr);
   hr=pSpriteObject->End();
   testHr("OnD3D10FrameRender:End",hr);
  }
  // Restore the previous blend state
  DXUTGetD3D10Device()->OMSetBlendState(pOriginalBlendState10, OriginalBlendFactor, OriginalSampleMask);
}
}

Attached Thumbnails

  • BlendingProblem.jpg
  • spheremapsmall.png

Edited by benp444, 01 May 2012 - 04:36 AM.


Sponsor:

#2 Nik02   Crossbones+   -  Reputation: 2647

Like
1Likes
Like

Posted 01 May 2012 - 06:46 AM

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.

Niko Suni


#3 benp444   Members   -  Reputation: 177

Like
0Likes
Like

Posted 01 May 2012 - 07:52 AM

Thanks for your response. I changed the code above from

hr=pSpriteObject->Begin(D3DX10_SPRITE_SORT_TEXTURE);

to

hr=pSpriteObject->Begin(D3DX10_SPRITE_SORT_DEPTH_BACK_TO_FRONT);

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?

#4 Nik02   Crossbones+   -  Reputation: 2647

Like
1Likes
Like

Posted 01 May 2012 - 11:36 AM

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 :)

Niko Suni


#5 benp444   Members   -  Reputation: 177

Like
0Likes
Like

Posted 01 May 2012 - 03:26 PM

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:

//START NEW CODE
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);
testHr("CreateDepthStencilState",hr);
//END NEW CODE

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

Cheers,
Ben.

Edited by benp444, 01 May 2012 - 03:27 PM.


#6 Nik02   Crossbones+   -  Reputation: 2647

Like
0Likes
Like

Posted 02 May 2012 - 03:55 AM

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 ;)

Niko Suni


#7 benp444   Members   -  Reputation: 177

Like
0Likes
Like

Posted 03 May 2012 - 07:03 AM

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;
srcTexture->GetDesc(&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 );
testHr("CreateTexture2D:CreateTexture2D",hr);
//copy the original texture in the into the SRGB texture
D3D10_BOX sourceRegion;
sourceRegion.left = 0;
sourceRegion.right = origDesc.Width;
sourceRegion.top = 0;
sourceRegion.bottom = origDesc.Height;
sourceRegion.front = 0;
sourceRegion.back = 1;
DXUTGetD3D10Device()->CopySubresourceRegion(pSRGBTexture, 0, 0, 0, 0, srcTexture, 0,&sourceRegion);
return pSRGBTexture;
}


#8 Nik02   Crossbones+   -  Reputation: 2647

Like
0Likes
Like

Posted 04 May 2012 - 02:09 AM

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 Posted Image

Edited by Nik02, 04 May 2012 - 02:16 AM.

Niko Suni





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS