Sign in to follow this  
supersonicstar

Can alpha channel be accumulated?

Recommended Posts

I set render states as following: SourceBlendFactor = D3DBLEND_ONE Description: (1, 1, 1, 1) DestinationBlendFactor= D3DBLEND_ONE according to dx docs, FinalColor = ObjectColor * SourceBlendFactor + PixelColor *destinationBlendFactor, So FinalColor.a should equal ObjectColor.a + PixelColor.a, But it seems from my program that FinalColor.a=255 (I used the A8R8G8B8 format). The rgb channels work fine. It seems that it is easier for alpha channel to saturate. Even if I set the alpha channels of the two textures I used to be zero, the rendering result is 255. My video card is Quadro FX 4400, and this is the code I used: AlphaBlendEnable = true; SrcBlend=ONE; DestBlend = ONE; I also try to add: SeparateAlphaBlendEnable=true; SrcBlendAlpha=ONE; DestBlendAlpha=ONE; BlendOpAlpha=ADD; But it doesn't help. Anyone experienced the same problem? Thanks!

Share this post


Link to post
Share on other sites
In this example, I have three quads. Most distant is red, then green, then blue.

Red is (1, 0, 0, 0.25)
Green is (1, 0, 0, 0.5)
Blue is (1, 0, 0, 0.25) (though it's alpha doesn't matter).

First I draw additive red and green, then use the backbuffer alpha to blend in the blue. Alpha appears to accumulate and blend as expected.

#ifdef _DEBUG
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9d.lib")
#else
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#endif

#if 1
#include "windows.h"
#include "d3d9.h"
#include "d3dx9.h"

HINSTANCE g_3DhInst;
ATOM g_3DWinClass;
HWND g_3DWindow=0;
HWND g_3DFocusWindow=0;
DWORD g_3DWindowStyleWin;
DWORD g_3DWindowStyleFullScreen;
DWORD g_3DWindowStyleExWin;
DWORD g_3DWindowStyleExFullScreen;
D3DPRESENT_PARAMETERS g_d3dpp;
LPDIRECT3D9 g_pD3D=0;
LPDIRECT3DDEVICE9 g_pDev=0;
bool g_bResetDevice = false;
char g_strWinClass[] = "QuickDX9";
char g_strWinTitle[] = "TestApp";

LRESULT WINAPI TestWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg==WM_CLOSE)
{
PostQuitMessage(0);
}
else if (msg==WM_SIZE)
{
g_bResetDevice = true;
}
else if (msg==WM_KEYDOWN && wParam == VK_ESCAPE)
{
PostQuitMessage(0);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

bool RegisterWin()
{
WNDCLASSEX wndclass;

memset(&wndclass, 0, sizeof(wndclass));
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_OWNDC;
wndclass.lpfnWndProc = TestWinProc;
wndclass.hInstance = g_3DhInst;
wndclass.lpszClassName = g_strWinClass;
g_3DWinClass = RegisterClassEx(&wndclass);
return g_3DWinClass != 0;
}

bool CreateWin()
{
RECT rc;

g_3DWindowStyleFullScreen = g_3DWindowStyleWin = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
g_3DWindowStyleExFullScreen = g_3DWindowStyleExWin = WS_EX_OVERLAPPEDWINDOW;
rc.left = 0;
rc.top = 0;
rc.right = 800;
rc.bottom = 600;
AdjustWindowRectEx(&rc, g_3DWindowStyleWin, false, g_3DWindowStyleExWin);
g_3DFocusWindow = CreateWindowEx(g_3DWindowStyleExWin, g_strWinClass, g_strWinTitle, g_3DWindowStyleWin, 0, 0, rc.right - rc.left, rc.bottom - rc.top, 0, 0, g_3DhInst, 0);
g_3DWindow = g_3DFocusWindow;
return g_3DWindow != 0;
}

bool MsgPump()
{
MSG msg;
static bool exit = false;

if (exit)
return false;

while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
exit = true;
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}

void Cleanup()
{
if (g_pDev)
g_pDev->Release();
if (g_pD3D)
g_pD3D->Release();
if (g_3DWindow)
DestroyWindow(g_3DWindow);
}


bool CreateD3D()
{
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
return g_pD3D != 0;
}

bool CreateDevice()
{
RECT rc;

GetClientRect(g_3DWindow, &rc);
memset(&g_d3dpp, 0, sizeof(g_d3dpp));
g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
g_d3dpp.EnableAutoDepthStencil = true;
g_d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
g_d3dpp.hDeviceWindow = g_3DWindow;
g_d3dpp.BackBufferWidth = rc.right - rc.left;
g_d3dpp.BackBufferHeight = rc.bottom - rc.top;
g_d3dpp.BackBufferCount = 1;
g_d3dpp.Windowed = true;
g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ;
if (FAILED(g_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, g_3DFocusWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pDev)))
return false;
return true;
}

bool ResetDevice()
{
if (FAILED(g_pDev->Reset(&g_d3dpp)))
return false;
return true;
}

bool TestDevice()
{
HRESULT hr = g_pDev->TestCooperativeLevel();

if (hr == D3DERR_DEVICENOTRESET || (hr == S_OK && g_bResetDevice))
{
g_bResetDevice = false;
if (!ResetDevice())
return false;
}
else if (hr == D3DERR_DEVICELOST)
return false;

return true;
}

class TestVert
{
public:
float x,y,z;
float nx,ny,nz;
DWORD color;
};

TestVert g_aoVerts[4];
D3DXMATRIX w,v,p;

void TestUpdate()
{
g_aoVerts[0].x = -1;
g_aoVerts[0].y = -1;
g_aoVerts[0].z = 0;
g_aoVerts[0].nx = 0;
g_aoVerts[0].ny = 0;
g_aoVerts[0].nz = -1;
g_aoVerts[0].color = 0xFFFF0000;

g_aoVerts[1].x = -1;
g_aoVerts[1].y = 1;
g_aoVerts[1].z = 0;
g_aoVerts[1].nx = 0;
g_aoVerts[1].ny = 0;
g_aoVerts[1].nz = -1;
g_aoVerts[1].color = 0xFFFFFF00;

g_aoVerts[2].x = 1;
g_aoVerts[2].y = -1;
g_aoVerts[2].z = 0;
g_aoVerts[2].nx = 0;
g_aoVerts[2].ny = 0;
g_aoVerts[2].nz = -1;
g_aoVerts[2].color = 0xFFFF00FF;

g_aoVerts[3].x = 1;
g_aoVerts[3].y = 1;
g_aoVerts[3].z = 0;
g_aoVerts[3].nx = 0;
g_aoVerts[3].ny = 0;
g_aoVerts[3].nz = -1;
g_aoVerts[3].color = 0xFFFFFFFF;

POINT pt;
GetCursorPos(&pt);
D3DXMatrixLookAtLH(&v, &D3DXVECTOR3((pt.x -400)/200.0f, (pt.y - 300)/200.0f, 0), &D3DXVECTOR3(0,0,10), &D3DXVECTOR3(0,1,0));
g_pDev->SetTransform(D3DTS_VIEW, &v);
D3DXMatrixPerspectiveFovLH(&p, D3DX_PI/4, 1.0, 0.1f, 500.0f);
g_pDev->SetTransform(D3DTS_PROJECTION, &p);
}

void TestRender()
{
g_pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
g_pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
g_pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
g_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);

g_pDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
g_pDev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

g_pDev->SetRenderState(D3DRS_LIGHTING, true);

D3DMATERIAL9 mat;

D3DLIGHT9 light;

memset(&light, 0, sizeof(light));
light.Direction.x = 0;
light.Direction.y = 0;
light.Direction.z = 1;
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = 1;
light.Diffuse.g = 1;
light.Diffuse.b = 1;
light.Diffuse.a = 1;
g_pDev->LightEnable(0, false);
g_pDev->SetLight(0, &light);
g_pDev->LightEnable(1, true);

g_pDev->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE);
g_pDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pDev->SetRenderState(D3DRS_COLORVERTEX, true);

if (GetKeyState(VK_SPACE) & 0x80)
g_pDev->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
else
g_pDev->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);

D3DXMatrixIdentity(&w);

g_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
g_pDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
g_pDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

memset(&mat, 0, sizeof(mat));
mat.Diffuse.r = 1.0f;
mat.Diffuse.g = 0.0f;
mat.Diffuse.b = 0.0f;
mat.Diffuse.a = 0.25f;
g_pDev->SetMaterial(&mat);
w._43 = 15;
g_pDev->SetTransform(D3DTS_WORLD, &w);
g_pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, g_aoVerts, sizeof(TestVert));

memset(&mat, 0, sizeof(mat));
mat.Diffuse.r = 0.0f;
mat.Diffuse.g = 1.0f;
mat.Diffuse.b = 0.0f;
mat.Diffuse.a = 0.50f;
g_pDev->SetMaterial(&mat);
w._43 = 10;
g_pDev->SetTransform(D3DTS_WORLD, &w);
g_pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, g_aoVerts, sizeof(TestVert));

memset(&mat, 0, sizeof(mat));
mat.Diffuse.r = 0.0f;
mat.Diffuse.g = 0.0f;
mat.Diffuse.b = 1.0f;
mat.Diffuse.a = 0.25f;
g_pDev->SetMaterial(&mat);
g_pDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTALPHA);
g_pDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVDESTALPHA);
w._43 = 5;
g_pDev->SetTransform(D3DTS_WORLD, &w);
g_pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, g_aoVerts, sizeof(TestVert));

}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdLine, int cmdShow)
{

g_3DhInst = hInst;
do
{
if (!RegisterWin())
break;
if (!CreateWin())
break;
if (!CreateD3D())
break;
if (!CreateDevice())
break;
while (MsgPump())
{
if (TestDevice())
{
TestUpdate();
g_pDev->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x111111, 1.0f, 0);
g_pDev->BeginScene();
TestRender();
g_pDev->EndScene();
g_pDev->Present(0,0,0,0);
}
};
} while (0);

Cleanup();

return 0;
}
#endif

Share this post


Link to post
Share on other sites
Thank you very much for your help! I am thrilled that the problem has been solved! I have been working on it for several days, but found no solutions. I compared your program with mine line by line, and I found that in my program:
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
should be changed to
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
0x00000000, 1.0f, 0 );//or D3DCOLOR_ARGB(0,0,0,0)

Because #define D3DCOLOR_XRGB(r,g,b) D3DCOLOR_ARGB(0xff,r,g,b)

Thank you again!

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