Yui的狗窝
Yui的狗窝
directx9使用模版实现镜面效果

对于一面镜子,物体在其中所成的像,不能够在非镜面区域被看到。模版缓存可以控制像素写入后台缓存,这可以帮助我们实现相当于镜面的效果。

1.为了使用模版缓存的功能,需要在代码中显示指定渲染状态,"pd3dDevice->SetRenderState(D3DRS_STENCILENABLE,true);"在使用完成之后需要及时关闭。
2.使用模版测试可以控制像素的更新与否,表达式为(ref&mask) Operation (value&mask)。mask为掩码,可以进行设置;ref为参考值,也可自行设置;value为当前测试的像素的模版缓存中的数值。
3.运算符Operation可以显示的进行设置,具体参数可以参考D3DCMPFUNC枚举类型。
4.模版的缓存更新方式取决于两个个测试的结果,即:像素模版测试和像素深度测试。

//source.cpp
#include"header.h"
#include<time.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPWSTR cmdLine, int cmdShow)
{
    InitD3D(hInstance, cmdShow);
    Setup(800, 600);
    MSG msg = { 0 };
    float cur, pre;
    pre = (float)timeGetTime();
    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        cur = (float)timeGetTime();
        Display(cur - pre);
    }
    return 0;
}
</code>
<code lang="cpp">
#pragma once
#include<d3d9.h>
#include<d3dx9.h>
#include<windows.h>
struct Vertex
{
    float x, y, z;
    float nx, ny, nz;
    float u, v;
    Vertex(float a, float b, float c, float na, float nb, float nc, float d, float e) :x(a), y(b),
        z(c), nx(na), ny(nb), nz(nc), u(d), v(e) {};
};
const D3DXCOLOR         RED = D3DCOLOR_XRGB(255, 0, 0);
const D3DXCOLOR         WHITE = D3DCOLOR_XRGB(255, 255, 255);
const D3DXCOLOR         YELLOW = D3DCOLOR_XRGB(255, 255, 0);
const D3DXCOLOR         BLACK = D3DCOLOR_XRGB(0, 0, 0);
const WORD              FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
IDirect3D9              *pd3d;
IDirect3DDevice9        *pd3dDevice;
D3DCAPS9                caps;
IDirect3DVertexBuffer9  *vb;
ID3DXMesh               *teapot;
D3DXVECTOR3             teapotPosition(0.0f, 3.0f, -7.5f);
int                     iUseProcess;
D3DMATERIAL9            teapotMtrl;
D3DMATERIAL9            mirrorMtrl;
D3DMATERIAL9            floorMtrl;
D3DMATERIAL9            wallMtrl;
IDirect3DTexture9       *mirrorTex;
IDirect3DTexture9       *floorTex;
IDirect3DTexture9       *wallTex;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
D3DMATERIAL9 InitMtrl(D3DXCOLOR ambient, D3DXCOLOR specular, D3DXCOLOR diffuse, D3DXCOLOR emissive, float power);
D3DLIGHT9 InitDirLight(D3DXCOLOR ambient, D3DXCOLOR specular, D3DXCOLOR diffuse, D3DXVECTOR3 dir);
void RenderScene();
void RenderMirror();
bool InitD3D(HINSTANCE hInstance, int cmdShow)
{
    WNDCLASS wc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hInstance = hInstance;
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = L"stencil";
    wc.lpszMenuName = NULL;
    wc.style = CS_VREDRAW | CS_HREDRAW;
    RegisterClass(&wc);
    HWND hWnd = CreateWindow(L"stencil", L"stencil", 0, 500, 200, 800, 600, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, cmdShow);
    UpdateWindow(hWnd);
    pd3d = Direct3DCreate9(D3D_SDK_VERSION);
    pd3d->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&caps);
    if (caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT)
        iUseProcess = D3DCREATE_HARDWARE_VERTEXPROCESSING;
    else
        iUseProcess = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    D3DPRESENT_PARAMETERS d3dpp;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
    d3dpp.BackBufferHeight = 600;
    d3dpp.BackBufferWidth = 800;
    d3dpp.EnableAutoDepthStencil = true;
    d3dpp.Flags = 0;
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.MultiSampleQuality = 0;
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.Windowed = true;
    pd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, iUseProcess, &d3dpp, &pd3dDevice);
    return true;
}
void Setup(float width,float height)
{
    D3DXCreateTeapot(pd3dDevice, &teapot, 0);
    teapotMtrl = InitMtrl(YELLOW, YELLOW*0.4f, YELLOW*0.6f, BLACK, 2.0f);
    wallMtrl = InitMtrl(WHITE, WHITE*0.4f, WHITE*0.6f, BLACK, 2.0f);
    floorMtrl = InitMtrl(WHITE, WHITE*0.4f, WHITE*0.6f, BLACK, 2.0f);
    mirrorMtrl = InitMtrl(WHITE, WHITE*0.4f, WHITE*0.6f, BLACK, 2.0f);
    D3DXCreateTextureFromFile(pd3dDevice, L"wall1.jpg", &wallTex);
    D3DXCreateTextureFromFile(pd3dDevice, L"floor1.jpg", &floorTex);
    D3DXCreateTextureFromFile(pd3dDevice, L"mirror1.bmp", &mirrorTex);
    pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    pd3dDevice->CreateVertexBuffer(sizeof(Vertex) * 24, 0, FVF, D3DPOOL_MANAGED, &vb, 0);
    Vertex *v;
    vb->Lock(0, 0, (void**)&v, 0);
    // floor-------------------------------------------------------
    v[0] = Vertex(-7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    v[1] = Vertex(-7.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
    v[2] = Vertex(7.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
    v[3] = Vertex(-7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
    v[4] = Vertex(7.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
    v[5] = Vertex(7.5f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
    // wall--------------------------------------------------------
    v[6] = Vertex(-7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[7] = Vertex(-7.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
    v[8] = Vertex(-2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[9] = Vertex(-7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[10] = Vertex(-2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[11] = Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
    v[12] = Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[13] = Vertex(2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
    v[14] = Vertex(7.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[15] = Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[16] = Vertex(7.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[17] = Vertex(7.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
    // mirror-------------------------------------------------------
    v[18] = Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[19] = Vertex(-2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
    v[20] = Vertex(2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[21] = Vertex(-2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
    v[22] = Vertex(2.5f, 5.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
    v[23] = Vertex(2.5f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
    vb->Unlock();
    D3DLIGHT9 dir = InitDirLight(WHITE, WHITE, WHITE, D3DXVECTOR3(0.707f, -0.707f, 0.707f));
    pd3dDevice->SetLight(0, &dir);
    pd3dDevice->LightEnable(0, true);
    pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
    pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4.0f, width / height, 1.0f, 1000.f);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj);
}
void Display(float timeDelta)
{
    if (pd3dDevice)
    {
        if (::GetAsyncKeyState(VK_LEFT) & 0x8000f)
            teapotPosition.x -= 3.f*0.0001f;
        if (::GetAsyncKeyState(VK_RIGHT) & 0x8000f)
            teapotPosition.x += 3.f*0.0001f;
        if (::GetAsyncKeyState(VK_UP) & 0x8000f)
            teapotPosition.y += 3.f*0.0001f;
        if (::GetAsyncKeyState(VK_DOWN) & 0x8000f)
            teapotPosition.y -= 3.f*0.0001f;
        static float angle = (3.0f * D3DX_PI) / 2.0f;
        static float radius = 20.f;
        if (::GetAsyncKeyState('A') & 0x8000f)
            angle -= 0.5f*0.0001f;
        if (::GetAsyncKeyState('D') & 0x8000f)
            angle += 0.5f*0.0001f;
        if (::GetAsyncKeyState('W') & 0x8000f)
            radius -= 2.0f * 0.0001f;
        if (::GetAsyncKeyState('S') & 0x8000f)
            radius += 2.0f * 0.0001f;
        D3DXMATRIX cam;
        D3DXVECTOR3 at(0.f, 0.f, 0.f);
        D3DXVECTOR3 up(0.f, 1.f, 0.f);
        D3DXVECTOR3 eye(cosf(angle)*radius, 3.f, sinf(angle)*radius);
        D3DXMatrixLookAtLH(&cam, &eye, &at, &up);
        pd3dDevice->SetTransform(D3DTS_VIEW, &cam);
        pd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER| D3DCLEAR_STENCIL, 0xff000000, 1.f, 0);
        pd3dDevice->BeginScene();
        RenderScene();
        RenderMirror();
        pd3dDevice->EndScene();
        pd3dDevice->Present(0, 0, 0, 0);
    }
}
void Rel()
{
    pd3d->Release();
    pd3dDevice->Release();
    vb->Release();
    mirrorTex->Release();
    wallTex->Release();
    floorTex->Release();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE)
            DestroyWindow(hWnd);
        break;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}
D3DLIGHT9 InitDirLight(D3DXCOLOR ambient, D3DXCOLOR specular,D3DXCOLOR diffuse,D3DXVECTOR3 dir)
{
    D3DLIGHT9 tem;
    ::ZeroMemory(&tem, sizeof(tem));
    tem.Type = D3DLIGHT_DIRECTIONAL;
    tem.Ambient = ambient;
    tem.Specular = specular;
    tem.Diffuse = diffuse;
    tem.Direction = dir;
    return tem;
}
D3DMATERIAL9 InitMtrl(D3DXCOLOR ambient, D3DXCOLOR specular, D3DXCOLOR diffuse, D3DXCOLOR emissive, float power)
{
    D3DMATERIAL9 tem;
    tem.Ambient = ambient;
    tem.Specular = specular;
    tem.Diffuse = diffuse;
    tem.Emissive = emissive;
    tem.Power = power;
    return tem;
}
void RenderScene()
{
    pd3dDevice->SetTexture(0, 0);
    pd3dDevice->SetMaterial(&teapotMtrl);
    D3DXMATRIX w;
    D3DXMatrixTranslation(&w, teapotPosition.x, teapotPosition.y, teapotPosition.z);
    pd3dDevice->SetTransform(D3DTS_WORLD, &w);
    teapot->DrawSubset(0);
    D3DXMATRIX i;
    D3DXMatrixIdentity(&i);
    pd3dDevice->SetTransform(D3DTS_WORLD, &i);
    pd3dDevice->SetStreamSource(0, vb, 0, sizeof(Vertex));
    pd3dDevice->SetFVF(FVF);
    pd3dDevice->SetTexture(0, floorTex);
    pd3dDevice->SetMaterial(&floorMtrl);
    pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
    pd3dDevice->SetTexture(0, wallTex);
    pd3dDevice->SetMaterial(&wallMtrl);
    pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 6, 4);
    pd3dDevice->SetTexture(0, mirrorTex);
    pd3dDevice->SetMaterial(&mirrorMtrl);
    pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 18, 2);
}
void RenderMirror()
{
    pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, true);//开启模版缓存
    pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);//设置模版的比较运算
    pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0x1);//对REF值的设置
    pd3dDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff);//设置模版掩码
    pd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);//模版写缓存掩码设置
    pd3dDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);//如果测试中的像素被遮挡,则保留当前值,即不更新
    pd3dDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
    pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);//如果测试成功,则更新模版缓存中的像素内容
    //设置绘制状态,取消对深度缓存和后台缓存的写入
    pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
    pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
    pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
    //绘制镜面内容到模版缓存中
    pd3dDevice->SetStreamSource(0, vb, 0, sizeof(Vertex));
    pd3dDevice->SetFVF(FVF);
    pd3dDevice->SetMaterial(&mirrorMtrl);
    pd3dDevice->SetTexture(0, mirrorTex);
    D3DXMATRIX i;
    D3DXMatrixIdentity(&i);
    pd3dDevice->SetTransform(D3DTS_WORLD, &i);
    pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 18, 2);
    //启用对深度缓存的写入
    pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
    //准备绘制茶壶的映像
    //对状态进行设置
    pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
    pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
    //计算确定映像的位置
    D3DXMATRIX W, T, R;
    D3DXPLANE plane(0.f, 0.f, 1.f, 0.f);//xy面
    D3DXMatrixReflect(&R, &plane);
    D3DXMatrixTranslation(&T, teapotPosition.x, teapotPosition.y, teapotPosition.z);
    W = T * R;
    //开始绘制茶壶的映像
    //首先清空深度缓存
    pd3dDevice->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, 1.f, 0);
    //将茶壶映像与镜面融合
    pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
    pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
    //绘制茶壶
    pd3dDevice->SetTransform(D3DTS_WORLD, &W);
    pd3dDevice->SetMaterial(&teapotMtrl);
    pd3dDevice->SetTexture(0, 0);
    pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
    teapot->DrawSubset(0);
    //禁用融合操作和模版操作,恢复先前的消隐模式
    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
    pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, false);
    pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}

纹理素材

http://www.yuihouse.moe:8080/wp-content/uploads/2018/04/wall.jpg

wall1.jpg

http://www.yuihouse.moe:8080/wp-content/uploads/2018/04/mirror.bmp

mirror1.bmp

http://www.yuihouse.moe:8080/wp-content/uploads/2018/04/floor.jpg

floor1.jpg

没有标签
首页      读书笔记      directx龙书的学习笔记      directx9使用模版实现镜面效果
https://secure.gravatar.com/avatar/d0fe7f1b17d5e9122db921e3a8cc327f?s=256&d=mm&r=g

Suzumiya, Yui

文章作者

发表评论

textsms
account_circle
email

Yui的狗窝

directx9使用模版实现镜面效果
对于一面镜子,物体在其中所成的像,不能够在非镜面区域被看到。模版缓存可以控制像素写入后台缓存,这可以帮助我们实现相当于镜面的效果。 1.为了使用模版缓存的功能,需要在代码中显示…
扫描二维码继续阅读
2018-04-26


没有激活的小工具