Nvidia SDK9.1 HardwareShadowMap 阴影程序注释

来源:互联网 发布:获取网站点击数据 编辑:程序博客网 时间:2024/06/04 18:13
 

//HardwareShadowMap.cpp,原程序见Nvidia SDK9.1

//该程序与Nvidia SDK中的SoftShadow程序一样,也是用ShadowMap产生阴影。 即//从灯光位置将场景渲染到Texture(ShadowMao)中产生深度图,再次渲染场景,各点与//ShadowMap中的深度比较,深度浅,即在阴影中。变黑即可。//ShadowMap方法优点是比ShadowMap简单,能处理一些ShadowVolume处理不料了的情况.//如处理静态阴影,可先渲染好ShadowMap,或将静态与动态分开渲染,绘制时,每帧只渲染动态的,//这样,速度可以达到比较理想//本程序比较简单,显示一个摇臂小机器在桌面上运动,产生动态阴影.//本例给出四种阴影效果,无柔化的,简单柔化的,高级柔化的,当然,越高级速度越慢//主程序为HardwareShadowMapApp.cpp,主要是D3D初始化,控制灯,关键的Render中,调用本程序渲染://  g_pHardwareShadowMap->Render(pd3dDevice, fTime, fElapsedTime, //   g_Camera.GetWorldMatrix(), //   g_Camera.GetViewMatrix(), //   g_Camera.GetProjMatrix());#include "HardwareShadowMap.h"#include #include #pragma warning(disable : 4786)#include #pragma warning(disable : 4786)#include static const int TEXDEPTH_HEIGHT = 512;  //ShadowMap 大小static const int TEXDEPTH_WIDTH = 512;HardwareShadowMap::HardwareShadowMap()  //初始化参数{    m_time = ::timeGetTime()*0.001f;    m_startTime = m_time;    m_frame = 0;    m_fps = 30;    m_main_menu = 0;    m_context_menu = 0;    m_pEffect = NULL;    m_pAttributes = NULL;    m_bWireframe = false;    m_fRadius = 0;    m_vecCenter = D3DXVECTOR3(0.f, 0.f, 0.f);    m_pBackBuffer = NULL;    m_pZBuffer = NULL;    m_pSMColorTexture = NULL;    m_pSMDecalTextureGround = NULL;    m_pSMDecalTextureBot = NULL;    m_pSMZTexture = NULL;    m_pSMColorSurface = NULL;    m_pSMZSurface = NULL;    m_lightDir = D3DXVECTOR4(0.f, 0.f, 0.f, 0.f);    m_bitDepth = 24;    m_Paused = false;    m_pDeclaration = NULL;    m_fDepthBias = 0.0002f;    m_fBiasSlope = 2.0f; m_pScene = NULL;    m_bLameTech = 0;    D3DXMatrixIdentity(&m_World);    D3DXMatrixIdentity(&m_View);    D3DXMatrixIdentity(&m_Projection);}//初始化HRESULT HardwareShadowMap::ResetDevice( IDirect3DDevice9* m_pd3dDevice, const D3DSURFACE_DESC* m_pBackBufferSurfaceDesc ){    HRESULT hr;    assert(m_pd3dDevice);    D3DFORMAT zFormat = D3DFMT_D24S8;    m_bitDepth = 24;    if(FAILED(CheckResourceFormatSupport(m_pd3dDevice, zFormat, D3DRTYPE_TEXTURE, D3DUSAGE_DEPTHSTENCIL)))    {        MessageBox(NULL, _T("Device/driver does not support hardware shadow maps!"), _T("ERROR"), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);        return E_FAIL;    }    //setup buffers    if(FAILED(m_pd3dDevice->GetRenderTarget(0, &m_pBackBuffer)))        return E_FAIL;    if(FAILED(m_pd3dDevice->GetDepthStencilSurface(&m_pZBuffer)))        return E_FAIL;    if(!m_pBackBuffer || !m_pZBuffer)        return E_FAIL; //载入灯光光罩图像:一个外边黑中间白圆的图,做光罩    if(FAILED(D3DXCreateTextureFromFileEx(m_pd3dDevice,                                           GetFilePath::GetFilePath(_T("spotlight.tga")).c_str(),                                          TEXDEPTH_WIDTH,                                          TEXDEPTH_HEIGHT,                                          1,                                          D3DUSAGE_RENDERTARGET,                                          D3DFMT_A8R8G8B8,                                          D3DPOOL_DEFAULT,                                          D3DX_DEFAULT,                                          D3DX_DEFAULT,                                          0,                                          NULL,                                          NULL,                                          &m_pSMDecalTextureGround)))        return E_FAIL; //载入阳光光罩图像:一个外边黑中间白圆的图,比灯光的亮 if(FAILED(D3DXCreateTextureFromFileEx(m_pd3dDevice,                                           GetFilePath::GetFilePath(_T("Sunlight.tga")).c_str(),                                          TEXDEPTH_WIDTH,                                          TEXDEPTH_HEIGHT,                                          1,                                          D3DUSAGE_RENDERTARGET,                                          D3DFMT_A8R8G8B8,                                          D3DPOOL_DEFAULT,                                          D3DX_DEFAULT,                                          D3DX_DEFAULT,                                          0,                                          NULL,                                          NULL,                                          &m_pSMDecalTextureBot)))        return E_FAIL;    D3DFORMAT colorFormat = D3DFMT_A8R8G8B8;    if( (zFormat == D3DFMT_D16) ||        (zFormat == D3DFMT_D15S1) )        colorFormat = D3DFMT_R5G6B5;  //根据Z-buffer格式,调整color格式 //建立ShadowMap图    if(FAILED(m_pd3dDevice->CreateTexture(TEXDEPTH_WIDTH, TEXDEPTH_HEIGHT, 1, D3DUSAGE_RENDERTARGET, colorFormat,        D3DPOOL_DEFAULT, &m_pSMColorTexture, NULL)))        return E_FAIL; //建立ShadowMap的Z-buffer图    if(FAILED(m_pd3dDevice->CreateTexture(TEXDEPTH_WIDTH, TEXDEPTH_HEIGHT, 1, D3DUSAGE_DEPTHSTENCIL, zFormat,        D3DPOOL_DEFAULT, &m_pSMZTexture, NULL)))        return E_FAIL;    if(!m_pSMColorTexture || !m_pSMZTexture || !m_pSMDecalTextureGround || !m_pSMDecalTextureBot)        return E_FAIL;    // Retrieve top-level surfaces of our shadow buffer (need these for use with SetRenderTarget)  //取得图的Surface,供渲染使用 if(FAILED(m_pSMColorTexture->GetSurfaceLevel(0, &m_pSMColorSurface)))        return E_FAIL;    if(FAILED(m_pSMZTexture->GetSurfaceLevel(0, &m_pSMZSurface)))        return E_FAIL;    if(!m_pSMColorSurface || !m_pSMZSurface)        return E_FAIL;    // Assign registers to the relevant vertex attributes    //定义顶点格式 D3DVERTEXELEMENT9 declaration[] =    {        { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },        { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },         D3DDECL_END()    };    m_pd3dDevice->CreateVertexDeclaration(declaration, &m_pDeclaration);    const char* profileOpts[] =     {        "-profileopts", "dcls", NULL,    };    DWORD tempFVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX0; //建立方桌    hr = CreateQuad(m_pd3dDevice,&m_smQuad);  //读取机器人Mesh,是Nvidia自己的nvb格式的 tstring fileName(_T("ClawBOT.nvb")); //    m_pScene = new NVBScene;    hr = m_pScene->Load(fileName, m_pd3dDevice, GetFilePath::GetFilePath);    if(FAILED(hr))        return hr;        if (!m_pScene->m_VertexHasNormal) {        MessageBox(NULL, _T("Model does not have normals"), _T("ERROR"), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);        return E_FAIL;    }    //bigship needs a bit of scale / trans    m_smBigship.scaleVec = D3DXVECTOR3(0.5f, 0.5f, 0.5f);    m_smBigship.transVec = D3DXVECTOR3(0.0f, -5.0f, 0.0f);    //载入效果fx文件    // Load our Effect file    // note: path is relative to MEDIA\ dir    hr = D3DXCreateEffectFromFile(m_pd3dDevice, GetFilePath::GetFilePath(_T("programs\\HLSL_HardwareShadowMap\\HardwareShadowMap.fx")).c_str(),        NULL, NULL, 0, NULL, &m_pEffect, NULL);    if (FAILED(hr))    {        MessageBox(NULL, _T("Failed to load effect file"), _T("ERROR"), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);        return hr;    } //定义灯光方向    m_lightDir.x = 0.8f;    m_lightDir.y = 1.0f;    m_lightDir.z = 0.0f;    m_lightDir.w = 0.0f;    D3DXVec4Normalize(&m_lightDir, &m_lightDir);     //将灯光向量传到效果中    m_pEffect->SetValue("LightVec", (float*)&m_lightDir, sizeof(float)*3);    m_lightPos.x = m_pScene->m_Center.x + m_pScene->m_Radius / 0.5f;     m_lightPos.y = m_pScene->m_Center.y + m_pScene->m_Radius / 0.5f;     m_lightPos.z = 0;    return S_OK;}//向效果传递矩阵的函数HRESULT HardwareShadowMap::SetVertexShaderMatrices(const D3DXMATRIX& worldMat, const D3DXMATRIX& viewMat, const D3DXMATRIX& projMat, const D3DXMATRIX& texMat){    D3DXMATRIX worldViewMat = worldMat * viewMat;    D3DXMATRIX worldViewProjMat = worldMat * viewMat * projMat;    D3DXMATRIX worldITMat;        D3DXMatrixInverse(&worldITMat, NULL, &worldMat);    D3DXMatrixTranspose(&worldITMat, &worldITMat);            m_pEffect->SetMatrix("WorldViewProj", &worldViewProjMat);    m_pEffect->SetMatrix("WorldView", &worldViewMat);    m_pEffect->SetMatrix("WorldIT", &worldITMat);    m_pEffect->SetMatrix("TexTransform", &texMat);        return S_OK;}//建立方桌HRESULT HardwareShadowMap::CreateQuad(IDirect3DDevice9* m_pd3dDevice, SMMeshInfo* mesh){        HRESULT hr = S_OK;    hr = m_pd3dDevice->CreateVertexBuffer(4 * sizeof(SMVertex), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &(mesh->pVB), NULL);    if(FAILED(hr))        return hr;    SMVertex* pVData;    hr = mesh->pVB->Lock(0, 0, (void**)&pVData, 0);    if(FAILED(hr))        return hr;    float value = 200.0f;    pVData[0].x  = -value; pVData[0].y  = -10.0f; pVData[0].z  = value;    pVData[0].nx = 0.0f;  pVData[0].ny = 1.0f; pVData[0].nz = 0.0f;    pVData[1].x  = value;  pVData[1].y  = -10.0f; pVData[1].z  = value;    pVData[1].nx = 0.0f;  pVData[1].ny = 1.0f; pVData[1].nz = 0.0f;    pVData[2].x  = -value; pVData[2].y  = -10.0f; pVData[2].z  = -value;    pVData[2].nx = 0.0f;  pVData[2].ny = 1.0f; pVData[2].nz = 0.0f;    pVData[3].x  = value;  pVData[3].y  = -10.0f; pVData[3].z  = -value;    pVData[3].nx = 0.0f;  pVData[3].ny = 1.0f; pVData[3].nz = 0.0f;    hr = mesh->pVB->Unlock();    if(FAILED(hr))        return hr;    hr = m_pd3dDevice->CreateIndexBuffer(4 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &(mesh->pIB), NULL);    if(FAILED(hr))        return hr;    WORD* pIData;    hr = mesh->pIB->Lock(0, 0, (void**)&pIData, 0);    if(FAILED(hr))        return hr;    //it's a strip    pIData[0] = 0;    pIData[1] = 2;    pIData[2] = 1;    pIData[3] = 3;    hr = mesh->pIB->Unlock();    mesh->dwNumFaces = 2;    mesh->dwNumVerts = 4;    mesh->primType = D3DPT_TRIANGLESTRIP;    //quad doesn't get scaled / translated    mesh->scaleVec = D3DXVECTOR3(1.0f, 1.0f, 1.0f);    mesh->transVec = D3DXVECTOR3(0.0f, 0.0f, 0.0f);    return S_OK;}//检查显卡能力HRESULT HardwareShadowMap::CheckResourceFormatSupport(IDirect3DDevice9* m_pd3dDevice, D3DFORMAT fmt, D3DRESOURCETYPE resType, DWORD dwUsage){    HRESULT hr = S_OK;    IDirect3D9* tempD3D = NULL;    m_pd3dDevice->GetDirect3D(&tempD3D);    D3DCAPS9 devCaps;    m_pd3dDevice->GetDeviceCaps(&devCaps); D3DDISPLAYMODE displayMode;    tempD3D->GetAdapterDisplayMode(devCaps.AdapterOrdinal, &displayMode);        hr = tempD3D->CheckDeviceFormat(devCaps.AdapterOrdinal, devCaps.DeviceType, displayMode.Format, dwUsage, resType, fmt);        tempD3D->Release(), tempD3D = NULL;        return hr;}//关键:渲染阴影图HRESULT HardwareShadowMap::RenderShadowMap(IDirect3DDevice9* m_pd3dDevice){    //setup matrices for shadowmap    D3DXVECTOR3 eye, lookAt, up;     //灯光位置为视点    lookAt.x = m_lightPos.x - (m_lightDir.x);     lookAt.y = m_lightPos.y - (m_lightDir.y);    lookAt.z = m_lightPos.z - (m_lightDir.z);        up.x     = 0.0f;          up.y     = 1.0f;          up.z     = 0.0f;        D3DXMATRIX lightView, lightProj;    D3DXMatrixLookAtLH(&lightView, &m_lightPos, &lookAt, &up); //灯光透视矩阵,60度,1:1,最近50,最远500,可根据自己的需要修改    D3DXMatrixPerspectiveFovLH(&lightProj, D3DXToRadian(60.0f), 1.0f, 50.0f, 500.0f);    m_LightViewProj = lightView * lightProj;  //设置ShadowMap图为渲染目标    //set render target to shadow map surfaces    if(FAILED(m_pd3dDevice->SetRenderTarget(0, m_pSMColorSurface)))        return E_FAIL; //深度图    //set depth stencil    if(FAILED(m_pd3dDevice->SetDepthStencilSurface(m_pSMZSurface)))        return E_FAIL;    //save old viewport //保存老的视口,设置新的    D3DVIEWPORT9 oldViewport;    m_pd3dDevice->GetViewport(&oldViewport);    //set new, funky viewport    D3DVIEWPORT9 newViewport;    newViewport.X = 0;    newViewport.Y = 0;    newViewport.Width  = TEXDEPTH_WIDTH;    newViewport.Height = TEXDEPTH_HEIGHT;    newViewport.MinZ = 0.0f;    newViewport.MaxZ = 1.0f;    m_pd3dDevice->SetViewport(&newViewport); //其实,使用Fx应该不需要再设视口了    //use technique that will draw plain black pixels //选择使用的Technique为发生阴影图    if (FAILED(m_pEffect->SetTechnique("GenHardwareShadowMap")))    {        MessageBox(NULL, _T("Failed to set 'GenHardwareShadowMap' technique in effect file"), _T("ERROR"), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);        return E_FAIL;    }    //depth bias //为什么用这两个渲染参数不太了解,按理说不需要对Z-Buffer偏移了.调节这两个参数也没发现场景有什么变化.估计是将深度上移动少量距离,避免比较时出错.    m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&m_fDepthBias);    m_pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&m_fBiasSlope); //先清除图象    m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00FFFFFF, 1.0f, 0L);    D3DXMATRIX tempIdentity;    D3DXMatrixIdentity(&tempIdentity); //绘制全部场景    for (unsigned int i = 0; i < m_pScene->m_NumMeshes; ++i)     {        const NVBScene::Mesh& mesh = m_pScene->m_Meshes[i];        D3DXMATRIX worldMat = mesh.m_Transform * m_World;        SetVertexShaderMatrices(worldMat, lightView, lightProj, tempIdentity);        m_pd3dDevice->SetVertexDeclaration(m_pDeclaration);        // render mesh using GenHardwareShadowMap technique        UINT uPasses;        if (D3D_OK == m_pEffect->Begin(&uPasses, 0)) {  // The 0 specifies that ID3DXEffect::Begin and ID3DXEffect::End will save and restore all state modified by the effect.            for (UINT uPass = 0; uPass < uPasses; uPass++) {                // Set the state for a particular pass in a technique.                m_pEffect->BeginPass(uPass);                // Draw it                 if (FAILED(mesh.Draw()))                    return E_FAIL;    m_pEffect->EndPass();            }            m_pEffect->End();        }    }    D3DXMATRIX tempScaleMat;    D3DXMatrixScaling(&tempScaleMat, m_smQuad.scaleVec.x, m_smQuad.scaleVec.y, m_smQuad.scaleVec.z);        SetVertexShaderMatrices(tempScaleMat, lightView, lightProj, tempIdentity);    //set vb    HRESULT hr = m_pd3dDevice->SetStreamSource(0, m_smQuad.pVB, 0, sizeof(SMVertex));    if (FAILED(hr))        return hr;        //set index buffer    hr = m_pd3dDevice->SetIndices(m_smQuad.pIB);    if(FAILED(hr))        return hr; //绘制桌面,其实如不需要桌子的影子,在此不必绘制桌面了    //render quad    UINT uPasses;    if (D3D_OK == m_pEffect->Begin(&uPasses, 0)) {  // The 0 specifies that ID3DXEffect::Begin and ID3DXEffect::End will save and restore all state modified by the effect.        for (UINT uPass = 0; uPass < uPasses; uPass++) {            m_pEffect->BeginPass(uPass);     // Set the state for a particular pass in a technique.            m_pd3dDevice->DrawIndexedPrimitive(m_smQuad.primType, 0, 0, m_smQuad.dwNumVerts, 0, m_smQuad.dwNumFaces);   m_pEffect->EndPass();        }        m_pEffect->End();    } //绘制完成,还原视口    m_pd3dDevice->SetViewport(&oldViewport);    //depth bias    float fTemp = 0.0f;    m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&fTemp);    m_pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&fTemp);    return S_OK;}//结束释放资源void HardwareShadowMap::LostDevice(){    SAFE_RELEASE(m_smBigship.pVB);    SAFE_RELEASE(m_smBigship.pIB);    SAFE_RELEASE(m_smQuad.pVB);    SAFE_RELEASE(m_smQuad.pIB);    SAFE_RELEASE(m_pSMColorTexture);    SAFE_RELEASE(m_pSMDecalTextureGround);    SAFE_RELEASE(m_pSMDecalTextureBot);    SAFE_RELEASE(m_pSMZTexture);    SAFE_RELEASE(m_pSMColorSurface);    SAFE_RELEASE(m_pSMZSurface);    SAFE_RELEASE(m_pBackBuffer);    SAFE_RELEASE(m_pZBuffer);    SAFE_RELEASE(m_pDeclaration);    SAFE_DELETE_ARRAY(m_pAttributes);    SAFE_DELETE(m_pScene);    SAFE_RELEASE(m_pEffect);}//渲染主过程HRESULT HardwareShadowMap::Render( IDirect3DDevice9* m_pd3dDevice, double fTime, float fElapsedTime,          const D3DXMATRIX* cworldMat, const D3DXMATRIX* cviewMat, const D3DXMATRIX* cprojMat){    HRESULT hr;    D3DXHANDLE hTechnique = NULL; //场景动画参数处理    // update time    m_time = ::timeGetTime()*0.001f;    if (m_frame == 0)        m_startTime = m_time;    else if (m_time > m_startTime)        m_fps = (float)m_frame / (m_time - m_startTime);    // Update view matrix    m_View = *cviewMat;//m_UICamera->GetRotationMatrix() * m_UICamera->GetTranslationMatrix();    //m_UIScene->SetControlOrientationMatrix(m_View);    // Update scene position    m_World = *cworldMat;//m_UIScene->GetRotationMatrix() * m_UIScene->GetTranslationMatrix();    static float time = 0.0f;    static bool forward = true;    if (!m_Paused)    {        if (forward)            time += 30 / m_fps;        else            time -= 30 / m_fps;    }    if (time > m_pScene->m_NumMeshKeys - 1)    {        forward = false;        time = (float)m_pScene->m_NumMeshKeys - 2.0f;    }    if (time < 1)        forward = true;    if (true)//m_pd3dDevice->BeginScene() == D3D_OK)    {        m_pScene->Update(time, &m_World); //动画场景        m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, (m_bWireframe ? D3DFILL_WIREFRAME : D3DFILL_SOLID));        //render into shadow map        if(FAILED(RenderShadowMap(m_pd3dDevice))) //调用上面的阴影图渲染过程,产生阴影图            return E_FAIL;  //根据菜单选择不同的阴影处理Technique过程        const D3DXHANDLE techs[4] = { "UseHardwareShadowMap", "UseHardwareShadowMapLame", "UseHardwareShadowMapGoodNoRot", "UseHardwareShadowMapGoodRot" };        if (FAILED(m_pEffect->SetTechnique(techs[m_bLameTech])))        {            MessageBox(NULL, _T("Failed to set 'UseHardwareShadowMap' technique in effect file"), _T("ERROR"), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);            return E_FAIL;        }  //设置渲染目标为背景图        //set render target back to normal back buffer / depth buffer        if(FAILED(m_pd3dDevice->SetRenderTarget(0, m_pBackBuffer)))            return E_FAIL;  //深度        if(FAILED(m_pd3dDevice->SetDepthStencilSurface(m_pZBuffer)))            return E_FAIL;  //清除缓存(看了一个ATI的Demo,把D3DCLEAR_TARGET去掉了,想想很对,一般情况,根本没必要每次清除TARGET)        m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 60, 60, 60), 1.0f, 0L);        //set depth map as texture  //将前面生成的阴影深度图传到效果中        if(FAILED(m_pEffect->SetTexture("ShadowMap", m_pSMZTexture)))            return E_FAIL;          //设置灯光光罩        //set spotlight texture for Bot        if(FAILED(m_pEffect->SetTexture("SpotLight", m_pSMDecalTextureBot)))            return E_FAIL;  //下面这一步Very重要,计算灯光的投影矩阵,这样,效果里直接使用texproj函数,一步就可找到对应的Shadow上的深度点        //set special texture matrix for shadow mapping        float fOffsetX = 0.5f + (0.5f / (float)TEXDEPTH_WIDTH);        float fOffsetY = 0.5f + (0.5f / (float)TEXDEPTH_HEIGHT);        unsigned int range = 1;            //note different scale in DX9!        //float fBias    = -0.001f * (float)range;        float fBias    = 0.0f;        D3DXMATRIX texScaleBiasMat( 0.5f,     0.0f,     0.0f,         0.0f,                                    0.0f,    -0.5f,     0.0f,         0.0f,                                    0.0f,     0.0f,     (float)range, 0.0f,                                    fOffsetX, fOffsetY, fBias,        1.0f );  //逐个渲染各物件        for (unsigned int i = 0; i < m_pScene->m_NumMeshes; ++i)         {            const NVBScene::Mesh& mesh = m_pScene->m_Meshes[i];   //投影矩阵为worldMat * m_LightViewProj * texScaleBiasMat            D3DXMATRIX worldMat = mesh.m_Transform * m_World;            SetVertexShaderMatrices(worldMat, m_View, m_Projection, worldMat * m_LightViewProj * texScaleBiasMat);            // render mesh using HardwareShadowMapTechnique            UINT uPasses;            if (D3D_OK == m_pEffect->Begin(&uPasses, 0)) {  // The 0 specifies that ID3DXEffect::Begin and ID3DXEffect::End will save and restore all state modified by the effect.                for (UINT uPass = 0; uPass < uPasses; uPass++) {                    // Set the state for a particular pass in a technique.                    m_pEffect->BeginPass(uPass);                    // Draw it                     if (FAILED(hr = mesh.Draw()))                        return hr;     m_pEffect->EndPass();                }                m_pEffect->End();            }        }  //渲染地面,使用光罩           //set spotlight texture for Ground        if(FAILED(m_pEffect->SetTexture("SpotLight", m_pSMDecalTextureGround)))            return E_FAIL;        D3DXMATRIX tempScaleMat;        D3DXMatrixScaling(&tempScaleMat, m_smQuad.scaleVec.x, m_smQuad.scaleVec.y, m_smQuad.scaleVec.z);        SetVertexShaderMatrices(tempScaleMat, m_View, m_Projection, tempScaleMat * m_LightViewProj * texScaleBiasMat);        //set vb        hr = m_pd3dDevice->SetStreamSource(0, m_smQuad.pVB, 0, sizeof(SMVertex));        if (FAILED(hr))            return hr;        //set index buffer        hr = m_pd3dDevice->SetIndices(m_smQuad.pIB);        if(FAILED(hr))            return hr;        //render quad using HardwareShadowMapTechnique        UINT uPasses;        if (D3D_OK == m_pEffect->Begin(&uPasses, 0)) {  // The 0 specifies that ID3DXEffect::Begin and ID3DXEffect::End will save and restore all state modified by the effect.            for (UINT uPass = 0; uPass < uPasses; uPass++) {                // Set the state for a particular pass in a technique.                m_pEffect->BeginPass(uPass);                // Draw it                 if(FAILED(m_pd3dDevice->DrawIndexedPrimitive(m_smQuad.primType, 0, 0, m_smQuad.dwNumVerts, 0, m_smQuad.dwNumFaces)))                    return E_FAIL;    m_pEffect->EndPass();            }            m_pEffect->End();        }//        m_pd3dDevice->EndScene();    }    m_frame++;    return S_OK;}


 

//HardwareShadowMap.fx 阴影效果实现//本效果没有考虑颜色及材料贴图,物体每点都是按法向量与灯光角度决定的颜色,即Phong着色.//如果考虑颜色及贴图的话,对多种物体多个材料都要加进来,可能就复杂无比了,估计这就是Shader难普及的原因吧//当然,对于简单的材料贴图,如果加入进来的话,修改起来也不是很难//本效果分为两部分//首先是发生ShadowMap,从灯光视点渲染场景,生成的Z-Buffer即为ShadowMap//第二部分是实际渲染,查找ShadowMap的对应点,渲染阴影场景 //包含几种选择:// UseHardwareShadowMapLame  模糊阴影// UseHardwareShadowMapGoodNoRot,没有前面CPP提到的UseHardwareShadowMapGoodRot// UseHardwareShadowMap//以及UseHardwareShadowMapLame4x4: 我加入的一个折衷的方案//-----------------------------------------------------------------------------texture ShadowMap;texture SpotLight;//-----------------------------------------------------------------------------float3 ObjectColor={1.0f,0.0f,0.0f};  //我加的场景色彩参数,可由主程序设置float4x4 WorldViewProj : WorldViewProj;float4x4 WorldIT : WorldIT;float4x4 WorldView : WorldView;float4x4 TexTransform;float3   LightVec;//-----------------------------------------------------------------------------struct VS_INPUT {    float4 Position : POSITION;    float3 Normal   : NORMAL;};struct VS_OUTPUT {    float4 Position  : POSITION;    float4 TexCoord0 : TEXCOORD0;    float4 TexCoord1 : TEXCOORD1;    float3 Color0 : COLOR0;};struct VS_OUTPUT_3 {    float2 Position  : VPOS;    float4 TexCoord0 : TEXCOORD0;    float4 TexCoord1 : TEXCOORD1;    float3 Color0 : COLOR0;};//-----------------------------------------------------------------------------sampler ShadowMapSampler = sampler_state{    Texture = ;    MinFilter = LINEAR;  //线性滤波    MagFilter = LINEAR;    MipFilter = None;    AddressU  = Clamp;    AddressV  = Clamp;};sampler ShadowMapSamplerPoint = sampler_state{    Texture = ;    MinFilter = POINT;  //不滤波    MagFilter = POINT;    MipFilter = None;    AddressU  = Clamp;    AddressV  = Clamp;};sampler SpotLightSampler = sampler_state{    Texture = ;    MinFilter = Linear;  //三线性滤波    MagFilter = Linear;    MipFilter = Linear;    AddressU  = Clamp;    AddressV  = Clamp;};//-----------------------------------------------------------------------------//生成ShadowMap//该VS不需要做什么事情,只要把顶点坐标转换到屏幕坐标就可以了,//如不使用效果直接使用固定管线渲染也可以,当然了,不必使用材料贴图等,以提高速度//本程序采取偷工减料的办法,直接使用了后面渲染的MainVS,利用里面的顶点转换,其他多余工作做了也没坏处(除了慢一点外)//-----------------------------------------------------------------------------//写ShadowMap,随便写一个黑点,写什么无所谓,反正需要Z-Buffer//未来显卡发展了,应该加个return NULL的功能,什么都不写,估计会更快.float4 BlackPS(void) : COLOR {    // just return opaque black (shadow)    return float4(0, 0, 0, 1);  }//简单阴影渲染,不加模糊处理//VS主要工作包括把顶点坐标转换到屏幕坐标//根据ShadowMap的矩阵,生成光罩图的查询坐标//以便PS把灯光光罩图象加到场景中VS_OUTPUT MainVS(VS_INPUT IN){    VS_OUTPUT OUT;    // transform normal into world space, then dot with world space light vector    // to determine how much light is falling on the surface:        float3 worldNormal = normalize(mul(IN.Normal, (float3x3)WorldIT));    float ldotn = max(dot(LightVec, worldNormal), 0.0);   //计算与顶点法线与光线的点积,Phong渲染    OUT.Color0 = ldotn;           //记录到顶点颜色    // transform model-space vertex position to light-space:        OUT.TexCoord0 = mul(IN.Position, TexTransform); //由输入的ShadowMap矩阵,生成ShadowMap的查询坐标//    OUT.TexCoord1 = mul(IN.Position, TexTransform); //生成光罩图查询坐标    OUT.TexCoord1 = OUT.TexCoord0;  //改写成这样的形式是否比上面一句快?        // transform model-space vertex position to screen space:        OUT.Position = mul(IN.Position, WorldViewProj);    return OUT;}//-----------------------------------------------------------------------------//PS查询光照图,确定输出点的颜色,阴影场景渲染完成,就是这么简单//不过,这个方法锯齿比较多float4 MainPS(VS_OUTPUT IN) : COLOR {    float3 shadow    = tex2D(ShadowMapSampler, IN.TexCoord0).rgb; //直接2D查询拿来做阴影?并不比较深度?  //非也,如果IN.TexCoord0为float2 格式,就取出该点位置的图像内容  //这里的IN.TexCoord0可不时U,V,而是float3   //如果为float3,该函数执行比较查询,即查询xy位置的内容,将内容与Z的深度比较,估计应该返回比较的结果0或1, //按结果判断,图像深度小于Z深度返回0,为阴影,反之为1 //这样,一个函数解决了一堆语句才能解决的问题 //该处为float4格式,手册上没有说明,是否自动当成float3了 //这样处理,关键就是前面的灯光投影矩阵了,一次乘法就将查询坐标转换为xyz格式        float3 spotlight = tex2D(SpotLightSampler, IN.TexCoord1).rgb;  //原并未使用光罩    float3 color = shadow * IN.Color0*spotlight;       //相乘叠加阴影    //  原来程序将光罩去掉了,这样做光罩似乎有点问题        return float4(color, 1.0);  }//下面是高模糊处理的渲染//-----------------------------------------------------------------------------VS_OUTPUT RenderSceneVS(VS_INPUT IN){    VS_OUTPUT OUT;    // transform normal into world space, then dot with world space light vector    // to determine how much light is falling on the surface:        float3 worldNormal = normalize(mul(IN.Normal, (float3x3)WorldIT));    float ldotn = max(dot(LightVec, worldNormal), 0.0); //计算点的法线与光线的夹角,这就是点的颜色    OUT.Color0 = ldotn;  //记录点的颜色    // transform model-space vertex position to light-space:        OUT.TexCoord0 = mul(IN.Position, TexTransform); //ShadowMap坐标    OUT.TexCoord1 = mul(IN.Position, WorldView); //这里是光罩图坐标,改为WorldView了,后面仍未用到        // transform model-space vertex position to screen space:        OUT.Position = mul(IN.Position, WorldViewProj);    return OUT;}//高模糊的PS,查询64个点的区域,进行模糊float4 FilterShadowLamePS(VS_OUTPUT IN) : COLOR{const float SHADOW_SIZE = 512.f;    float shadow = 0;    for (int y=-4; y<4; y++)        for (int x=-4; x<4; x++)  //查询8x8的64个点的ShadowMap区域,进行模糊处理        {            float4 coord = IN.TexCoord0;            coord.xy += (float2(x,y)/SHADOW_SIZE) * IN.TexCoord0.w;            shadow += tex2Dproj( ShadowMapSampler, coord );   //这里换成了tex2Dproj了        }            shadow= smoothstep(2, 58, shadow);    //这个函数是平滑要点,内容是判断shadow是否在指定的2,58间           //如果是,就返回一个2,58间的平稳变化的插值数据,          //具体是什么值,还真想不出来                float3 color = shadow * IN.Color0;  //叠加阴影    return float4(color,0);}//根据上面原理,我将区域改小,速度自然加快了,这样可以在质量与速度上折衷一下float4 FilterShadowLamePS4x4(VS_OUTPUT IN) : COLOR{const float SHADOW_SIZE = 512.f;    float shadow = 0;    for (int y=-2; y<2; y++)        for (int x=-2; x<2; x++)  //改为查询4x4的16个点的ShadowMap区域,进行模糊处理        {            float4 coord = IN.TexCoord0;            coord.xy += (float2(x,y)/SHADOW_SIZE) * IN.TexCoord0.w;            shadow += tex2Dproj( ShadowMapSampler, coord );   //这里换成了tex2Dproj了        }        //    shadow= smoothstep(2, 58, shadow);    shadow= smoothstep(2, 15, shadow);  float shadow_value=0.2f;  //我在这里加了个影子亮度参数,这样,影子就不再是死黑死黑的了  float3 color= ObjectColor*IN.Color0; //加上预定义的物体颜色     color = color*(1-shadow_value)+shadow * shadow_value;  //叠加阴影    return float4(color,0);}//高级的模糊阴影PS,查询20个点的区域,使用了log2等高级方法//速度与我修改的4x4相当,所以也不费心研究它的算法了float4 FilterShadowPS(VS_OUTPUT_3 IN) : COLOR {  const float SHADOW_SIZE = 512.f;        const float2 sample_array[20] = { //准备20查询位置区域坐标        //float2(  0.f,  0.f ) / SHADOW_SIZE,        float2(  1.f,  0.f ) / SHADOW_SIZE,        float2(  0.f,  1.f ) / SHADOW_SIZE,        float2(  0.f, -1.f ) / SHADOW_SIZE,        float2( -1.f,  0.f ) / SHADOW_SIZE,        float2( -1.f, -1.f ) / SHADOW_SIZE,        float2(  1.f, -1.f ) / SHADOW_SIZE,        float2( -1.f,  1.f ) / SHADOW_SIZE,        float2(  1.f,  1.f ) / SHADOW_SIZE,               float2(  0.f, -2.f ) / SHADOW_SIZE,        float2( -2.f,  0.f ) / SHADOW_SIZE,        float2(  0.f,  2.f ) / SHADOW_SIZE,        float2(  2.f,  0.f ) / SHADOW_SIZE,        float2( -1.f, -2.f ) / SHADOW_SIZE,        float2(  1.f, -2.f ) / SHADOW_SIZE,        float2( -2.f, -1.f ) / SHADOW_SIZE,        float2( -2.f,  1.f ) / SHADOW_SIZE,                float2( -1.f,  2.f ) / SHADOW_SIZE,        float2(  1.f,  2.f ) / SHADOW_SIZE,        float2(  2.f, -1.f ) / SHADOW_SIZE,        float2(  2.f,  1.f ) / SHADOW_SIZE,     };      float2 dSdX = SHADOW_SIZE * ddx( IN.TexCoord0.xy / IN.TexCoord0.w ); //ddx,ddy是计算屏幕坐标与x,y轴的偏导数    float2 dSdY = SHADOW_SIZE * ddy( IN.TexCoord0.xy / IN.TexCoord0.w ); //;(,我发晕了,简单推断它是做一种平滑吧        float approx_major_len = max( dot(dSdX, dSdX), dot(dSdY, dSdY) ); // :(    float rho = 0.5f*log2(approx_major_len);   // :(    float shadow = tex2Dproj(ShadowMapSampler, IN.TexCoord0);  //查询出ShadowMap的值    float4 offset = (float4) 0;           for ( int i=0; i<4; i++ )  //查询累加周围点的值,应该是1-4吧,上面已经将0值取出来了,    {        offset.x = dot(sample_array[i].xy, float2(0.793353,-0.608761));        offset.y = dot(sample_array[i].xy, float2(0.608761, 0.793353));        shadow += tex2Dproj(ShadowMapSampler, IN.TexCoord0 + offset*IN.TexCoord0.w);          }        float3 result;        if ( rho < 0.f )  //根据前面得到的rho,    {        float4 shadowCoord = (float4) 0;        shadowCoord.xyz = IN.TexCoord0.xyz / IN.TexCoord0.w;        float shadow2 = shadow;                for ( int i=4; i<20; i++ ) //查询更远距离的        {            offset.x = dot(sample_array[i].xy, float2(0.793353,-0.608761));            offset.y = dot(sample_array[i].xy, float2(0.608761, 0.793353));            shadow2 += tex2Dlod(ShadowMapSampler, shadowCoord + offset);        }        shadow2 = shadow + shadow2;        shadow2 = smoothstep(1.f, 19.f, shadow2);  //平滑        shadow = smoothstep(1,5,shadow);             float lerp_fac = saturate(-(rho));                             result = lerp(float3(0,1,0), float3(1,0,0), lerp_fac);        shadow = lerp(shadow, shadow2, lerp_fac);    }    else    {        shadow = smoothstep(1,5,shadow); //如rho不小于0,直接平滑5个点的        result = float3(0,1,0);    }      float3 color = result * (0.75*IN.Color0*shadow + 0.25);          return float4(color, 1.0);}//VSPS完,下面是定义technique,使用上面的VSPS//-----------------------------------------------------------------------------technique UseHardwareShadowMap{    pass P0    {        VertexShader = compile vs_1_1 MainVS();        PixelShader = compile ps_1_1 MainPS();                ZEnable          = True;        AlphaBlendEnable = False;        Lighting         = False;        CullMode         = CW;            TexCoordIndex[0] = 0;        TexCoordIndex[1] = 1;        TextureTransformFlags[0] = Projected;        TextureTransformFlags[1] = Projected;    }}technique UseHardwareShadowMapGoodNoRot{    pass P0    {        VertexShader = compile vs_3_0 RenderSceneVS();        PixelShader = compile ps_3_0 FilterShadowPS();                ZEnable          = True;        AlphaBlendEnable = False;        Lighting         = False;        CullMode         = CW;            TexCoordIndex[0] = 0;        TexCoordIndex[1] = 1;        //TextureTransformFlags[0] = Projected;        //TextureTransformFlags[1] = Projected;    }}technique UseHardwareShadowMapLame{    pass P0    {        VertexShader = compile vs_3_0 RenderSceneVS();        PixelShader = compile ps_3_0 FilterShadowLamePS4x4();                ZEnable          = True;        AlphaBlendEnable = False;        Lighting         = False;        CullMode         = CW;            TexCoordIndex[0] = 0;        TexCoordIndex[1] = 1;        //TextureTransformFlags[0] = Projected;        //TextureTransformFlags[1] = Projected;    }}technique GenHardwareShadowMap{    pass P0    {        VertexShader = compile vs_1_1 MainVS();        PixelShader = compile ps_1_1 BlackPS();        ZEnable          = True;        AlphaBlendEnable = False;        Lighting         = False;        CullMode         = CCW;  // note: not quite optimal                ColorWriteEnable = 0;     // no need to render to color, we only need z    }}//-----------------------------------------------------------------------------//阴影完了,看起来不复杂,但应用到整个场景中还比较麻烦:因为场景的内容可能很多很大,而ShadowMap拉伸太大精度很差.原先按投影锥检索可视物体的方法不能使用了,场景外的物体也会将阴影投到场景中.所以,实际如何做是个问题. 

原创粉丝点击