深度测试与alpha混合(5)

透过那些透明度非常高的物体看其他物体,例如透过几乎完全透明的玻璃看其他物体,会感到玻璃好像不存在,在三维图形程序中渲染时就可以不渲染这些透明度非常高的物体,从而可以提高渲染速度,这可以通过alpha测试来实现。

alpha测试根据当前像素是否满足alpha测试条件(即是否达到一定的透明度)来控制是否绘制该像素,图形程序应用alpha测试可以有效地屏蔽某些像素颜色。与alpha混合相比,alpha测试不将当前像素的颜色与颜色缓冲区中像素的颜色混合,像素要么完全不透明,要么完全透明。由于无需进行颜色缓冲区的读操作和颜色混合,因此alpha测试在速度上要优于alpha混合。

alpha测试通过激活渲染状态D3DRS_ALPHATESTENABLE来设置,示例代码如下:

g_device->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);

渲染状态D3DRS_ALPHAREF用来设置alpha测试的参考值,alpha测试函数比较当前绘制的像素的alpha值和参考值,如果返回TRUE,则通过测试并绘制像素,反之不予绘制。参考值的取值范围是0x00000000到0x000000ff。

渲染状态D3DRS_ALPHAFUNC用来设置alpha测试函数,alpha测试函数属于D3DCMPFUNC枚举类型,默认状态为D3DCMP_ALWAYS。下列代码设置alpha测试函数为D3DCMP_GREATER,表示测试点像素的alpha值大于设置的alpha参考值时则返回TRUE:

g_device->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
g_device->SetRenderState(D3DRS_ALPHAREF, 0x00000081);
g_device->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);

已知蓝色玻璃的alpha值为浮点值0.5f,等价于两位16进制数0x80,小于程序中设置的alpha测试参考值0x81,并且alpha测试函数被设为D3DCMP_GREATER,所以蓝色玻璃的颜色不会被绘制出来。

按下数字键"1",启用alpha测试。

 

按下数字键"0",禁用alpha测试。

 

源程序:

#include  < d3dx9.h >

#pragma warning(disable : 
4127 )

#define  CLASS_NAME    "GameApp"

#define  release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

IDirect3D9
*                 g_d3d;
IDirect3DDevice9
*         g_device;

ID3DXMesh
*                 g_mesh;
D3DMATERIAL9
*             g_mesh_materials;
IDirect3DTexture9
**         g_mesh_textures;
DWORD                    g_num_materials;

void  setup_world_matrix()
{
    D3DXMATRIX mat_world;
    D3DXMatrixRotationY(
& mat_world, timeGetTime()  /   1000.0f );
    g_device
-> SetTransform(D3DTS_WORLD,  & mat_world);
}

void  setup_view_proj_matrices()
{
    
//  setup view matrix

    D3DXVECTOR3 eye(
0.0f 15.0f - 20.0f );
    D3DXVECTOR3 at(
0.0f ,   0.0f ,    0.0f );
    D3DXVECTOR3 up(
0.0f ,   1.0f ,    0.0f );

    D3DXMATRIX mat_view;
    D3DXMatrixLookAtLH(
& mat_view,  & eye,  & at,  & up);
    g_device
-> SetTransform(D3DTS_VIEW,  & mat_view);

    
//  setup projection matrix
    D3DXMATRIX mat_proj;
    D3DXMatrixPerspectiveFovLH(
& mat_proj, D3DX_PI / 4 1.0f 1.0f 500.0f );
    g_device
-> SetTransform(D3DTS_PROJECTION,  & mat_proj);
}

bool  init_geometry()
{
    ID3DXBuffer
*  material_buffer;

    
/*
     D3DXLoadMeshFromXA(
        LPCSTR pFilename, 
        DWORD Options, 
        LPDIRECT3DDEVICE9 pD3DDevice, 
        LPD3DXBUFFER *ppAdjacency,
        LPD3DXBUFFER *ppMaterials, 
        LPD3DXBUFFER *ppEffectInstances, 
        DWORD *pNumMaterials,
        LPD3DXMESH *ppMesh);
    
*/

    
if (FAILED(D3DXLoadMeshFromX( " heli.x " , D3DXMESH_SYSTEMMEM, g_device, NULL,  & material_buffer, NULL,
                                
& g_num_materials,  & g_mesh)))
    {
        MessageBox(NULL, 
" Could not find heli.x " " ERROR " , MB_OK);
        
return   false ;
    }

    D3DXMATERIAL
*  xmaterials  =  (D3DXMATERIAL * ) material_buffer -> GetBufferPointer();

    g_mesh_materials 
=   new  D3DMATERIAL9[g_num_materials];
    g_mesh_textures     
=   new  IDirect3DTexture9 * [g_num_materials];

    
for (DWORD i  =   0 ; i  <  g_num_materials; i ++ )
    {
        g_mesh_materials[i] 
=  xmaterials[i].MatD3D;

        
//  set ambient reflected coefficient, because .x file do not set it.
        g_mesh_materials[i].Ambient  =  g_mesh_materials[i].Diffuse;

        g_mesh_textures[i] 
=  NULL;

        
if (xmaterials[i].pTextureFilename  !=  NULL  &&  strlen(xmaterials[i].pTextureFilename)  >   0 )    
            D3DXCreateTextureFromFile(g_device, xmaterials[i].pTextureFilename, 
& g_mesh_textures[i]);    
    }

    material_buffer
-> Release();

    
return   true ;
}

bool  init_d3d(HWND hwnd)
{
    g_d3d 
=  Direct3DCreate9(D3D_SDK_VERSION);

    
if (g_d3d  ==  NULL)
        
return   false ;

    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;

    
if (FAILED(g_d3d -> CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                  
& d3dpp,  & g_device)))
    {
        
return   false ;
    }
    
    
if ( !  init_geometry())
        
return   false ;

    setup_view_proj_matrices();    

    g_device
-> SetRenderState(D3DRS_ZENABLE,            TRUE);
    g_device
-> SetRenderState(D3DRS_ZFUNC,            D3DCMP_LESS);
    g_device
-> SetRenderState(D3DRS_ZWRITEENABLE,    TRUE);

    g_device
-> SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
    g_device
-> SetRenderState(D3DRS_ALPHAREF,         0x00000081 );
    g_device
-> SetRenderState(D3DRS_ALPHAFUNC,        D3DCMP_GREATER);    

    g_device
-> SetRenderState(D3DRS_AMBIENT,  0xFFFFBB55 );
    
    
return   true ;
}

void  cleanup()
{
    delete[] g_mesh_materials;

    
if (g_mesh_textures)
    {
        
for (DWORD i  =   0 ; i  <  g_num_materials; i ++ )
            release_com(g_mesh_textures[i]);

        delete[] g_mesh_textures;
    }
    
    release_com(g_mesh);
    release_com(g_device);
    release_com(g_d3d);
}

void  render()
{
    g_device
-> Clear( 0 , NULL, D3DCLEAR_TARGET  |  D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 5 5 5 ),  1.0f 0 );

    g_device
-> BeginScene();

    setup_world_matrix();

    
//  render opaque object first
     for (DWORD i  =   0 ; i  <  g_num_materials; i ++ )
    {
        
if (g_mesh_materials[i].Diffuse.a  ==   1.0f )
        {
            g_device
-> SetMaterial( & g_mesh_materials[i]);
            g_device
-> SetTexture( 0 , g_mesh_textures[i]);

            g_mesh
-> DrawSubset(i);
        }        
    }        

    
//  render transparent object second
     for (DWORD i  =   0 ; i  <  g_num_materials; i ++ )
    {
        
if (g_mesh_materials[i].Diffuse.a  !=   1.0f )
        {
            g_device
-> SetMaterial( & g_mesh_materials[i]);
            g_device
-> SetTexture( 0 , g_mesh_textures[i]);

            g_mesh
-> DrawSubset(i);
        }        
    }        
    
    g_device
-> EndScene();

    g_device
-> Present(NULL, NULL, NULL, NULL);
}

LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    
switch (msg)
    {
    
case  WM_KEYDOWN:
        
switch (wParam)
        {
        
case   48 //  press key "0", disable alpha test.
            g_device -> SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
            
break ;

        
case   49 //  press key "1", enable alpha test.
            g_device -> SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
            
break ;

        
case  VK_ESCAPE:
            DestroyWindow(hwnd);
            
break ;
        }    

        
break ;

    
case  WM_DESTROY:
        PostQuitMessage(
0 );
        
return   0 ;
    }

    
return  DefWindowProc(hwnd, msg, wParam, lParam);
}

int  WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
    WNDCLASSEX wc;

    wc.cbSize            
=   sizeof (WNDCLASSEX);
    wc.style            
=  CS_CLASSDC;
    wc.lpfnWndProc        
=  WinProc;
    wc.cbClsExtra        
=   0 ;
    wc.cbWndExtra        
=   0 ;
    wc.hInstance        
=  inst;
    wc.hIcon            
=  NULL;
    wc.hCursor            
=  NULL;
    wc.hbrBackground    
=  NULL;
    wc.lpszMenuName        
=  NULL;
    wc.lpszClassName    
=  CLASS_NAME;
    wc.hIconSm            
=  NULL;

    
if ( !  RegisterClassEx( & wc))
        
return   - 1 ;

    HWND hwnd 
=  CreateWindow(CLASS_NAME,  " Direct3D App " , WS_OVERLAPPEDWINDOW,  200 100 640 480 ,
                             NULL, NULL, wc.hInstance, NULL);    

    
if (hwnd  ==  NULL)
        
return   - 1 ;

    
if (init_d3d(hwnd))
    {
        ShowWindow(hwnd, SW_SHOWDEFAULT);
        UpdateWindow(hwnd);

        MSG msg;
        ZeroMemory(
& msg,  sizeof (msg));

        
while (msg.message  !=  WM_QUIT)
        {
            
if (PeekMessage( & msg, NULL,  0 0 , PM_REMOVE))
            {
                TranslateMessage(
& msg);
                DispatchMessage(
& msg);
            }
                
            render();
            Sleep(
10 );
        }
    }

    cleanup();
    UnregisterClass(CLASS_NAME, wc.hInstance);    

    
return   0 ;
}

 

下载示例工程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值