深度测试与alpha混合(1)

在绘制复杂的三维场景时,不可避免地会出现物体间的相互遮挡,在这种情况下,为了正确地绘制场景需要使用深度测试。半透明物体的绘制不同于不透明物体,Direct3D通过alpha混合实现半透明物体的绘制。深度测试可以简化复杂场景的绘制,alpha混合可以使绘制的三维场景更完整、更逼真。

在复杂的场景中,通常有多个物体需要绘制,这些物体之间通常会存在遮挡关系,离观察点较远的物体会因为近处物体的者的遮挡而不可见或只有部分可见,Direct3D图形系统提供了深度测试功能来实现这种效果。

深度缓冲区与深度测试

要理解深度测试,首先需要理解深度缓冲区。深度缓冲区是Direct3D用来存储绘制到屏幕上的每个像素点的深度信息的一块内存缓冲区。当Direct3D将一个场景渲染到目标表面上时,它使用深度缓冲区来决定光栅化后各个多边形的像素的前后遮挡关系,最终决定哪个颜色值被绘制出来。也就是说,Direct3D通过比较当前绘制的像素点的深度和对应深度缓冲区的点的深度值来决定是否绘制当前像素。如果深度测试结果为TRUE,则绘制当前像素,并用当前像素点的深度来更新深度缓冲区,反之则不予绘制。通常情况下,深度缓冲区对应于屏幕大小的一块二维区域。

对一个启用了深度缓冲区的场景进行光栅化操作时,渲染表面上的每个点都要进行深度测试。在深度测试开始时,深度缓冲区的深度值被设置为该场景可能出现的最大值,渲染表面上的颜色值被设置为背景颜色值。然后测试场景内即将绘制的每个多边形,看它是否小于存储在深度缓冲区中的深度值,如果该多边形的深度值更小,则该深度值被更新到深度缓冲区中,并将渲染表面上当前点的颜色值替换为该多边形的颜色。如果多边形在这一点的深度值更大,将继续测试列表中的下一个多边形。

创建深度缓冲区

若要在Direct3D图形程序中应用深度测试,首先必须在创建Direct3D渲染设备时创建深度缓冲区,示例代码如下:

D3DPRESENT_PARAMETERS d3dpp;ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed         = TRUE;d3dpp.SwapEffect          = D3DSWAPEFFECT_DISCARD;d3dpp.BackBufferFormat       = D3DFMT_UNKNOWN;d3dpp.EnableAutoDepthStencil    = TRUE;                   // 表示由Direct3D创建并管理一个深度缓冲区d3dpp.AutoDepthStencilFormat = D3DFMT_D16;     // 表示深度缓冲区中每一个像素的深度值由16位的二进制数表示
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,                               &d3dpp, &g_device))){ return false;}

激活深度测试

深度缓冲区随Direct3D渲染设备创建好后,调用Direct3D渲染状态设置函数IDirect3DDevice9::SetRenderState(),将第一个参数设为D3DRS_ZENABLE,第二个参数设为TRUE,激活深度测试:

g_device->SetRenderState(D3DRS_ZENABLE,       TRUE);

设置深度测试函数

接下来依然调用IDirect3DDevice9::SetRenderState()函数设置深度测试函数,第一个参数设置为D3DRS_ZFUNC:

D3DRS_ZFUNC
One member of the D3DCMPFUNC enumerated type. The default value is D3DCMP_LESSEQUAL. This member enables an application to accept or reject a pixel, based on its distance from the camera.

The depth value of the pixel is compared with the depth-buffer value. If the depth value of the pixel passes the comparison function, the pixel is written.

The depth value is written to the depth buffer only if the render state is TRUE.

Software rasterizers and many hardware accelerators work faster if the depth test fails, because there is no need to filter and modulate the texture if the pixel is not going to be rendered.

第二个参数设置为想要设置的深度测试函数,它属于D3DCMPFUNC枚举类型,定义如下:

Defines the supported compare functions.

typedef enum D3DCMPFUNC{    D3DCMP_NEVER = 1,    D3DCMP_LESS = 2,    D3DCMP_EQUAL = 3,    D3DCMP_LESSEQUAL = 4,    D3DCMP_GREATER = 5,    D3DCMP_NOTEQUAL = 6,    D3DCMP_GREATEREQUAL = 7,    D3DCMP_ALWAYS = 8,    D3DCMP_FORCE_DWORD = 0x7fffffff,} D3DCMPFUNC, *LPD3DCMPFUNC;

Constants

D3DCMP_NEVER
Always fail the test.
D3DCMP_LESS
Accept the new pixel if its value is less than the value of the current pixel.
D3DCMP_EQUAL
Accept the new pixel if its value equals the value of the current pixel.
D3DCMP_LESSEQUAL
Accept the new pixel if its value is less than or equal to the value of the current pixel.
D3DCMP_GREATER
Accept the new pixel if its value is greater than the value of the current pixel.
D3DCMP_NOTEQUAL
Accept the new pixel if its value does not equal the value of the current pixel.
D3DCMP_GREATEREQUAL
Accept the new pixel if its value is greater than or equal to the value of the current pixel.
D3DCMP_ALWAYS
Always pass the test.
D3DCMP_FORCE_DWORD
Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used.

Remarks

The values in this enumerated type define the supported compare functions for the D3DRS_ZFUNC, D3DRS_ALPHAFUNC, and D3DRS_STENCILFUNC render states.

通常情况下,深度测试函数设置为D3DCMP_LESS,表示当测试点深度值小于深度缓冲区中相应值时,通过深度测试并绘制相关像素,这样没有被遮挡的物体才显示,而被遮挡的物体就不显示。示例代码如下:

g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);

更新深度缓冲区

设置了深度测试函数后,还需要设置深度测试成功时对深度缓冲区如何操作,是保持原来的深度值,还是用当前像素的深度值更新对应的数值。

D3DRS_ZWRITEENABLE
TRUE to enable the application to write to the depth buffer. The default value is TRUE. This member enables an application to prevent the system from updating the depth buffer with new depth values. If FALSE, depth comparisons are still made according to the render state D3DRS_ZFUNC, assuming that depth buffering is taking place, but depth values are not written to the buffer.

示例代码如下:

g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);

表示如果通过测试,则用当前像素的深度值更新深度缓冲区中对应的数值,这是最常用的设置,也是默认设置。

示例程序

该示例程序绘制了一个矩形和一个坦克模型,其中先绘制矩形,再绘制坦克模型,而且坦克模型在矩形的后面被遮挡住。如果按下"1"键,则禁用深度测试,这时坦克虽然被矩形遮挡住,但仍然被绘制出来了;如果按下"2"键,则启用深度测试,这时坦克模型被矩形遮挡住,没有绘制出来。

按下数字键"1",禁用深度测试,被矩形部分遮住的坦克被绘制出来。

按下数字键"2",启用深度测试,被矩形部分遮住的坦克没有被绘制出来。

源程序:

#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;
IDirect3DVertexBuffer9* g_shutter_vb;

D3DXMATRIX                g_mat_tank;
D3DXMATRIX                g_mat_shutter;

struct sCustomVertex
{   
    float x, y, z;   
    DWORD color;     
};

#define D3DFVF_CUSTOM_VERTEX   (D3DFVF_XYZ | D3DFVF_DIFFUSE)

void setup_matrices()
{
    // setup world matrix
    D3DXMATRIX mat_world;
    D3DXMatrixIdentity(&mat_world);
    g_device->SetTransform(D3DTS_WORLD, &mat_world);

// setup view matrix

D3DXVECTOR3 eye(0.0f, 2.0f, -30.0f);
    D3DXVECTOR3 at(0.0f,  2.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("tank.x", D3DXMESH_SYSTEMMEM, g_device, NULL, &material_buffer, NULL,
                                &g_num_materials, &g_mesh)))
    {
        MessageBox(NULL, "Could not find tank.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();

// create shutter vertex buffer

sCustomVertex vertices[] =
    {
        { -8,   -2,  -10.0f,   0xFFFFFF00},     
        { -8,    6,  -10.0f,   0xFFFFFF00},    
        {  8,   -2,  -10.0f,   0xFFFFFF00},    
        {  8,    6,  -10.0f,   0xFFFFFF00}
    };

g_device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT, &g_shutter_vb, NULL);
    
    void* ptr;
    g_shutter_vb->Lock(0, sizeof(vertices),  &ptr, 0);
    memcpy(ptr, vertices, sizeof(vertices));
    g_shutter_vb->Unlock();

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

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

g_device->SetRenderState(D3DRS_AMBIENT, 0xFF00BB00);

// rotate tank

D3DXQUATERNION quat;
    D3DXMATRIX mat_rotation;

D3DXMatrixIdentity(&g_mat_tank);

D3DXQuaternionRotationYawPitchRoll(&quat, D3DX_PI/4, -D3DX_PI/4, 0.0f);
    D3DXMatrixRotationQuaternion(&mat_rotation, &quat);
    D3DXMatrixMultiply(&g_mat_tank, &mat_rotation, &g_mat_tank);

D3DXMatrixIdentity(&g_mat_shutter);
    
    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_shutter_vb);
    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();

// render shutter
    g_device->SetRenderState(D3DRS_LIGHTING, FALSE);
    g_device->SetTransform(D3DTS_WORLD, &g_mat_shutter);
    g_device->SetStreamSource(0, g_shutter_vb, 0, sizeof(sCustomVertex));
    g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);
    g_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

// render tank
    g_device->SetRenderState(D3DRS_LIGHTING, TRUE);
    g_device->SetTransform(D3DTS_WORLD, &g_mat_tank);

for(DWORD i = 0; i < g_num_materials; i++)
    {
        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 49: // press key "1", disable depth test.
            g_device->SetRenderState(D3DRS_ZENABLE, FALSE);
            break;

case 50: // press key "2", enable depth test.
            g_device->SetRenderState(D3DRS_ZENABLE, 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();
        }
    }

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

return 0;
}

下载示例工程

转载于:https://www.cnblogs.com/wonderKK/archive/2011/11/28/2266803.html

深度测试与alpha混合(1)相关推荐

  1. 深度测试与alpha混合(3)

    alpha源混合系数通常设置为D3DBLEND_SRCALPHA,即当前绘制像素的alpha值.目标混合系数设置为D3DBLEND_INVSRCALPHA,即1减去当前绘制像素的alpha值.那么当前 ...

  2. 【浅墨Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/41923661 作者:毛星云(浅墨) ...

  3. 【Visual C++】游戏开发五十五 浅墨DirectX教程二十二 水乳交融的美学:alpha混合技术

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/15026917 作者:毛星 ...

  4. 【Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/41923661 作者:毛星云(浅墨) ...

  5. Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/41923661 作者:毛星云(浅墨) ...

  6. Windows的位图alpha混合技术

    摘 要:本文介绍了在Windows环境下对位图的图像alpha混合技术,提供了alpha混合函数的实现方法,并对Windows API提供的alpha混合函数的使用进行了介绍. 关键词:Windows ...

  7. OpenGL纹理矩阵,alpha混合和丢弃

    OpenGL纹理矩阵,alpha混合和丢弃 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include &q ...

  8. Alpha混合(二)Material Alpha

    Alpha值 Alpha混合是为了实现透明效果,透明到什么程度是由alpha值决定的,对于一个32位的ARGB格式的颜色来说,它的组成部分如下: 我们可以看到,最高位的一个byte表示alpha值,它 ...

  9. 【STM32F429开发板用户手册】第46章 STM32F429的DMA2D应用之刷色块,位图和Alpha混合

    最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255 第46章       STM32F429的DMA2D应用之刷色块, ...

最新文章

  1. python爬虫可以爬哪些山_从python爬虫,到更爱这个世界
  2. c语言cnn实现ocr字符,端到端的OCR:基于CNN的实现
  3. Oracle数据库分页的三种方法
  4. 自省:我为什么没有成功--对照35前务必完成的12跳
  5. 容器化单页面应用中RESTful API的访问
  6. Spring context命名空间
  7. Windows 控制台cmd中文乱码的解决办法
  8. jQuery--基本选择器
  9. 使用OpenCV需要注意的小细节
  10. PDF文件不支持直接编辑 PDF如何转化为可以编辑的Word文档
  11. 2018年视频云服务市场格局进入整合阶段,阿里云视频云位居市场竞争力领导者的位置... 1
  12. 第三方登录 steam_如何在Steam中激活第三方游戏代码
  13. 12306 模拟登录
  14. OpenShift免费空间申请使用教程
  15. wed基础和http
  16. CVTE实习应聘经验
  17. 罗马帝国开创了辉煌的人类文明,但他们的数字表示法的确有些繁琐,尤其在表示大数的时候,现在看起来简直不能忍受,所以在现代很少使用了。之所以这样,不是因为发明表示法的人的智力的问题,而是因为一个宗教的原因
  18. 深度学习之学习(3-4)YOLOV4
  19. 数据科学家经典20道面试题
  20. 顶点着色器和片段着色器的区别

热门文章

  1. 云计算运维累不累_要做好云计算运维管理,一定要注意这3个要点
  2. mysql未监控在3306_监控MySQL或Web服务是否正常
  3. 是指能够被程序员看到的计算机系统的属性,计算机组成原理复习范围详细.doc...
  4. pythondjango项目集成_Django集成celery实战小项目
  5. 毕业设计基础测试 定位+后端处理+退出删除
  6. 加密Python脚本
  7. poj3179 Corral the Cows(二分, 前缀和, 离散化, 双指针)
  8. Python内置函数之 range()
  9. 基于阿里云服务器使用宝塔面板搭建 Typecho 博客
  10. hihocoder第226周:打表找规律