关于DirectX9如何消除Alpha混合中出现的亮度溢出

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于DirectX9如何消除Alpha混合中出现的亮度溢出相关的知识,希望对你有一定的参考价值。

本人需要实现几片云朵图像的3D叠加,使其成为大的云团。使用D3D9实现,代码如下:

//-----------------------------------------------------------------------------
#include <tchar.h>
#include <d3d9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe.h>
#pragma warning( default : 4996 )
#include <d3dx9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
//-----------------------------------------------------------------------------
// 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; // Used to create the DDeviceD3
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
LPDIRECT3DTEXTURE9 g_pTexture = NULL;
//float fAngle =D3DX_PI/2.0f;
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)

struct CUSTOMVERTEX

D3DXVECTOR3 position;
D3DCOLOR color;
FLOAT u,v;
;

参考技术A //-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )

// 建立一个D3D对象。
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;

// Set up the structure used to create the D3DDevice. Most parameters are
// zeroed out. We set Windowed to TRUE, since we want to do D3D in a
// window, and then set the SwapEffect to "discard", which is the most
// efficient method of presenting the back buffer to the display. And
// we request a back buffer format that matches the current desktop display
// format.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

// Create the Direct3D device. Here we are using the default adapter (most
// systems only have one, unless they have multiple graphics hardware cards
// installed) and requesting the HAL (which is saying we want the hardware
// device rather than a software one). Software vertex processing is
// specified since we know it will work on all cards. On cards that support
// hardware vertex processing, though, we would see a big performance gain
// by specifying hardware vertex processing.
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )

return E_FAIL;


// Device state would normally be set here
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

return S_OK;

//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: 释放之前初始化的对象。
//-----------------------------------------------------------------------------
VOID Cleanup()

if( g_pd3dDevice != NULL)
g_pd3dDevice->Release();

if( g_pD3D != NULL)
g_pD3D->Release();

if( g_pVB != NULL)
g_pVB->Release();

if( g_pTexture != NULL)
g_pTexture->Release();

VOID Mar(HWND hWnd)


D3DXMATRIX World_T,World_RX,World_RY,World_RZ,World_S,World;//定义世界变换矩阵等等
D3DXMatrixTranslation(&World_T, 0.0f, 0.0f, 0.0f);//生成一个平移量为0,0,0的平移矩阵
D3DXMatrixRotationX(&World_RX,0);//设置x方向旋转角度为0的旋转变换矩阵
D3DXMatrixRotationY(&World_RY,0);//设置y方向旋转角度为0的旋转变换矩阵
D3DXMatrixRotationZ(&World_RZ,0);//设置z方向旋转角度为0的旋转变换矩阵
D3DXMatrixScaling(&World_S,2.0f,2.0f,2.0f);//设置x,y,z方向放大2倍的缩放矩阵
D3DXMatrixMultiply(&World,&World_T,&World_RX );//将平移矩阵和x方向旋转矩阵相乘放入矩阵world
D3DXMatrixMultiply(&World,&World,&World_RY );//将上面得到的矩阵world与y旋转矩阵相乘再放入world
D3DXMatrixMultiply(&World,&World,&World_RZ );//将上面world与z方向矩阵相乘放入world
D3DXMatrixMultiply(&World,&World,&World_S );//将上述world矩阵与缩放矩阵相乘再放入world矩阵
g_pd3dDevice->SetTransform(D3DTS_WORLD, &World);//进行world矩阵变换,第一个参数意义为识别要进行变换的矩阵为世界变换矩阵,
//第二个参数为world矩阵的地址
D3DXVECTOR3 a( 2.0f, 2.0f,-2.0f ),b(0,0,0),c(0,0.1,0);//定义结构体D3DVECTOR3的三个成员a,b,c
D3DXMATRIXA16 View;//定义结构体实例 View;
D3DXMatrixLookAtLH(&View, &a, &b, &c); //该函数建立一个左手系的取景矩阵,第一个参数为所得到的矩阵的指针,
//2,3,4参数分别为观察点,被观察点,和向上向量的矢量的指针
g_pd3dDevice->SetTransform(D3DTS_VIEW, &View);//进行取景变换

D3DXMATRIXA16 Pro;//定义结构体实例 Pro;
D3DXMatrixPerspectiveFovLH(&Pro, D3DX_PI/4,1.0f, 1.0f, 100.0f);//该函数建立一个左手系的透视投影矩阵,参数1为结果矩阵指针
//参数2为在y轴上的成像角度(弧度),参数3为截头体的纵横比,
//参数4为截头体距离相机最近距离,参数5为最远距离
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &Pro); //进行透视投影变换
RECT rect;//定义了结构体的实例rect,这个结构体定义了一个矩形的左上和右下坐标,包含4个成员left(左上x)top(左上y)right(右下x)bottom(右下y)
GetClientRect(hWnd,&rect);//该函数把客户区的坐标复制到一个由&rect指向的结构体
D3DVIEWPORT9 vp;//定义结构体实例vp,这个结构体定义了渲染目标表面的窗口维度,成员1:渲染目标表面的左上角象素x坐标,成员2:左上角y坐标
//
vp.X = 0;//除非只要渲染表面的子集,此外这个值都被设为0
vp.Y = 0;//除非只要渲染表面的子集,此外这个值都被设为0
vp.Width = rect.right;//除非只要渲染表面的子集,这个值都被设为目标的长
vp.Height = rect.bottom;//除非只要渲染表面的子集,这个值都被设为目标的宽
vp.MinZ = 0.0f;//MinZ和MaxZ一起来描述渲染目标的深的,通常一个设为0,一个设为1
vp.MaxZ = 1.0f;
g_pd3dDevice->SetViewport(&vp);//设置视区变换参数


//-------------------------------------------------------------------------
//Name: BeforeR
//Desc: 读入纹理并建立顶点缓冲区
//-----------------------------------------------------------------------
BOOL BeforeR( CUSTOMVERTEX *g_Vertices)

if( FAILED(D3DXCreateTextureFromFileExW(g_pd3dDevice, L"13.bmp", D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_FROM_FILE, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &g_pTexture)))

MessageBox(NULL, "Could not find 13.bmp", "Textures.exe", MB_OK);
return E_FAIL;

if(FAILED(g_pd3dDevice->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX),//建立顶点缓冲区.参数1:缓冲区长度参数3:描述顶点格式参数5:指针地址
0,D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL)))
return 0;
VOID *pVertices;
if(FAILED( g_pVB->Lock( 0, 0, (void**)&pVertices, 0)))//Lock函数对顶点缓冲区进行内存操作,并获得顶点缓冲区的内存指针
return 0;
memcpy(pVertices,g_Vertices,4*sizeof(CUSTOMVERTEX));//内存拷贝
g_pVB->Unlock();//通知D3D操作结束
return 1;



//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
BOOL Render(HWND hWnd)

if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )//这个函数如果在一对开始和结束场景中使用会产生错误,除非没用过endscene,开始可以用两次

Mar(hWnd);//调用一个矩阵变换函数,参数为句柄
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE,TRUE);//该函数用于用户设置渲染状态:参数1 设置渲染状态 参数2 状态值,本句使透明度混合可用
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);//该函数用于用户设置渲染状态:参数1 设置渲染状态 参数2 状态值,本句使透明度混合可用
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,D3DBLEND_DESTALPHA );
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,150), 1.0f, 0 );//清理渲染目标的表明.
CUSTOMVERTEX g_Vertices[4] = D3DXVECTOR3(0.1f, 0.1f, 0.0f), 0xffffffff, 0.f, 0,
D3DXVECTOR3(0.8f, 0.1f, 0.0f), 0xffffffff, 1.0f, 0,
D3DXVECTOR3(0.1f, 0.8f, 0.0f), 0xffffffff, 0, 1.0f,
D3DXVECTOR3(0.8f, 0.8f, 0.0f), 0xffffffff, 1.0f, 1.0f;//给g_Vertices中填入四个图元的顶点
if(!BeforeR((CUSTOMVERTEX*)g_Vertices))//做渲染之前的读入纹理及建立顶点缓冲区操作
return E_FAIL;
g_pd3dDevice->SetTexture(0,g_pTexture); //将纹理分配给设备,参数2是指向 IDirect3DBaseTexture9接口函数的指针
g_pd3dDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_MODULATE);//该函数主要用于指定纹理颜色和顶点颜色的混合方法,参数1:指定当前的贴图纹理层ID,共有0到7八个..参数2:设置纹理状态类型枚举值,参数3:纹理渲染状态值
g_pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);//这句是说纹理颜色将作为颜色混合的第一个参数.
g_pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE);//像素的漫反射颜色值将作为颜色混合的第二个参数
g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE);//指明纹理层的Alpha混合方法,此处禁用α混合
g_pd3dDevice->SetStreamSource(0,g_pVB,0,sizeof(CUSTOMVERTEX));//该函数将数据流与顶点缓冲区联系起来.参数1指定数据流,参数2是接口函数的指针.参数3:缓存区和数据流开始位置的偏移量.参数4:分量的幅度
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);//设置当前顶点流的声明,???????????????
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);//渲染当前数据流的图元
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCCOLOR);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_DESTALPHA);
g_Vertices[0].position = D3DXVECTOR3(0.1f, 0.1f, -0.01f);
g_Vertices[1].position = D3DXVECTOR3(0.5f, 0.1f, -0.01f);
g_Vertices[2].position = D3DXVECTOR3(0.1f, 0.5f, -0.01f);
g_Vertices[3].position = D3DXVECTOR3(0.5f, 0.5f, -0.01f);//读入另外四个图元的顶点
if(!BeforeR((CUSTOMVERTEX*)g_Vertices))//准备工作
return E_FAIL;
g_pd3dDevice->SetTexture(0,g_pTexture); //将纹理分配给设备,参数2是指向 IDirect3DBaseTexture9接口函数的指针
g_pd3dDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_MODULATE);//该函数主要用于指定纹理颜色和顶点颜色的混合方法,参数1:指定当前的贴图纹理层ID,共有0到7八个..参数2:设置纹理状态类型枚举值,参数3:纹理渲染状态值
//此处是值将纹理层颜色混合的第一个参数和第二个参数颜色相乘输出.
g_pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);//这句是说纹理颜色将作为颜色混合的第一个参数.
g_pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE);//像素的漫反射颜色值将作为颜色混合的第二个参数
g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE);//指明纹理层的Alpha混合方法,此处禁用α混合
g_pd3dDevice->SetStreamSource(0,g_pVB,0,sizeof(CUSTOMVERTEX));//该函数将数据流与顶点缓冲区联系起来.参数1指定数据流,参数2是接口函数的指针.参数3:缓存区和数据流开始位置的偏移量.参数4:分量的幅度
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);//设置当前顶点流的声明,???????????????
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2);//渲染当前数据流的图元
g_pd3dDevice->EndScene();

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );//参数1指向一个rect型结构体(包含源矩形信息),此处必须为NULL(除非)参数2:同样指向目标矩形,如果为NULL,那么整个客户区都被填满,如果源矩形比目标矩形大,则源矩形被裁减成一样大
//参数3:指向一个窗体,该窗体的客户区是显示区,如果为NULL,那么将选择一个D3DPRESENT_PARAMETERS的成员hDeviceWindow,对于全屏应用,它是顶层窗口的句柄
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: windows 消息处理
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )

switch( msg )

case WM_DESTROY:
PostQuitMessage( 0 );
return 0;

case WM_PAINT:
Render(hWnd);
ValidateRect( hWnd, NULL );//检查特定事件的句柄是否有效
return 0;


return DefWindowProc( hWnd, msg, wParam, lParam );

//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )

// 注册窗口类
WNDCLASSEX wc = sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"chengnan", NULL ;
RegisterClassEx( &wc );
// 建立应用窗口
HWND hWnd = CreateWindow( "chengnan", "chengnan 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 600,
NULL, NULL, wc.hInstance, NULL );
// 初始化 Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )

Render(hWnd); //渲染
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
MSG msg;
ZeroMemory( &msg, sizeof(msg));
while( msg.message!=WM_QUIT )

if(PeekMessage(&msg, NULL,0U,0U,PM_REMOVE))

TranslateMessage( &msg );
DispatchMessage( &msg );



Cleanup();
UnregisterClass( "chengnan", wc.hInstance );
return 0;


做出的结果如图
http://photo.163.com/photos/xxxx3837142/125755208/3309269425/
它是两个32位的:
http://photo.163.com/photos/xxxx3837142/125755208/3309269459/
经过Alpha混合而成的,问题是,结果在两幅图重叠的部分,有明显的亮度溢出的区域,而且两个元图的alpha图层也没有显示出来应有的效果,如何解决此问题,急!!
麻烦大家了!!
解决再加分!!本回答被提问者采纳

以上是关于关于DirectX9如何消除Alpha混合中出现的亮度溢出的主要内容,如果未能解决你的问题,请参考以下文章

消除文法左递归

关于 Alpha is Transparency 到底需不需要勾的最终结论

关于 Alpha is Transparency 到底需不需要勾的最终结论

如何在手动“叠加”混合操作中处理 alpha?

如何防止 Qt 对 QListView 中的图标进行 alpha 混合选择?

转载Alpha混合物体的深度排序