⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 game_shadow.cpp

📁 我做的毕业设计
💻 CPP
字号:
//=============================================================================
// Desc: ShadowVolume.cpp
//=============================================================================

#include "Game_User.h"


//-----------------------------------------------------------------------------
// Desc: 创建阴影体
//-----------------------------------------------------------------------------
HRESULT CShadowVolume::Create(LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXMESH pMesh)
{
	//克隆与阴影体关联的网格模型
	pMesh->CloneMeshFVF(pMesh->GetOptions(), D3DFVF_XYZ, pd3dDevice, &m_pMesh);

	//为阴影体顶点分配存储空间
	DWORD dwNumFaces    = m_pMesh->GetNumFaces();
	m_pVertices = new D3DXVECTOR3[dwNumFaces*3*6];

	return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 根据网格模型和光源位置构造阴影体
//       首先检查网格模型的每个三角形, 将网格模型的轮廓边保存到一个临时列表中.
//       然后根据轮廓边和光源位置构造阴影体
//-----------------------------------------------------------------------------
HRESULT CShadowVolume::UpdateShadowVolume( D3DXVECTOR3 vLight )
{
    D3DXVECTOR3* pVertices;
    WORD*       pIndices;

    //锁定网格模型顶点缓冲区和索引缓冲区
    m_pMesh->LockVertexBuffer( 0L, (LPVOID*)&pVertices );
    m_pMesh->LockIndexBuffer( 0L, (LPVOID*)&pIndices );

	//获取网格模型面的数量
    DWORD dwNumFaces    = m_pMesh->GetNumFaces();

	//为临时边列表分配内存空间
    WORD* pEdges = new WORD[dwNumFaces*6];
    if( pEdges == NULL )
    {
        m_pMesh->UnlockVertexBuffer();
        m_pMesh->UnlockIndexBuffer();
        return E_OUTOFMEMORY;
    }
    DWORD dwNumEdges = 0;

    //遍历网格模型的每个面(三角形), 将网格模型的轮廓边添加到临时边列表中
    for( DWORD i=0; i<dwNumFaces; i++ )
    {
		//当前面三个顶点的索引
        WORD wFace0 = pIndices[3*i+0];
        WORD wFace1 = pIndices[3*i+1];
        WORD wFace2 = pIndices[3*i+2];

		//根据顶点索引获取当前面三个顶点的坐标
        D3DXVECTOR3 v0 = pVertices[wFace0];
        D3DXVECTOR3 v1 = pVertices[wFace1];
        D3DXVECTOR3 v2 = pVertices[wFace2];

        //计算当前面的法线
        D3DXVECTOR3 vCross1(v2-v1);
        D3DXVECTOR3 vCross2(v1-v0);
        D3DXVECTOR3 vNormal;
        D3DXVec3Cross( &vNormal, &vCross1, &vCross2 );

		//如果当前面是背光面, 则将当前面的三条边"添加"到边列表
        if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f )
        {
            AddEdge( pEdges, dwNumEdges, wFace0, wFace1 );
            AddEdge( pEdges, dwNumEdges, wFace1, wFace2 );
            AddEdge( pEdges, dwNumEdges, wFace2, wFace0 );
        }
    }

	//针对保存的每条轮廓边, 添加一个矩形, 所有的矩形构成阴影体
	m_dwNumVertices = 0;
    for(int i=0; i<dwNumEdges; i++ )
    {
		//计算矩形的四个的顶点
        D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]];
        D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]];
        D3DXVECTOR3 v3 = v1 - vLight*100;
        D3DXVECTOR3 v4 = v2 - vLight*100;

		//添加矩形
        m_pVertices[m_dwNumVertices++] = v1;
        m_pVertices[m_dwNumVertices++] = v2;
        m_pVertices[m_dwNumVertices++] = v3;

        m_pVertices[m_dwNumVertices++] = v2;
        m_pVertices[m_dwNumVertices++] = v4;
        m_pVertices[m_dwNumVertices++] = v3;
    }
   
	//删除临时的边列表
    delete[] pEdges;

    //解锁网格模型顶点缓冲区和索引缓冲区
    m_pMesh->UnlockVertexBuffer();
    m_pMesh->UnlockIndexBuffer();

    return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 将边添加到列表中
//-----------------------------------------------------------------------------
VOID CShadowVolume::AddEdge( WORD* pEdges, DWORD& dwNumEdges, WORD v0, WORD v1 )
{
	//首先删除内部的边(在边列表中出现两次的边)
    for( DWORD i=0; i < dwNumEdges; i++ )
    {
        if( ( pEdges[2*i+0] == v0 && pEdges[2*i+1] == v1 ) ||
            ( pEdges[2*i+0] == v1 && pEdges[2*i+1] == v0 ) )
        {
            if( dwNumEdges > 1 )
            {
                pEdges[2*i+0] = pEdges[2*(dwNumEdges-1)+0];
                pEdges[2*i+1] = pEdges[2*(dwNumEdges-1)+1];
            }
            dwNumEdges--;
            return;
        }
    }

	//在边列表中添加一条新边
    pEdges[2*dwNumEdges+0] = v0;
    pEdges[2*dwNumEdges+1] = v1;
    dwNumEdges++;
}

//-----------------------------------------------------------------------------
// Desc: 渲染阴影体, 只更新模板缓冲区, 不更新颜色缓冲区
//-----------------------------------------------------------------------------
HRESULT CShadowVolume::Render( LPDIRECT3DDEVICE9 pd3dDevice, 
							  D3DXMATRIX* pmatWorld, bool bRenderVolume)
{
	//禁用z缓冲区写操作, 并启用模板缓冲区
    pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE );
    pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );

	//使用平面着色模式(不进行插值)
    pd3dDevice->SetRenderState( D3DRS_SHADEMODE,    D3DSHADE_FLAT );

	//如果渲染阴影体到颜色缓冲区
	if(bRenderVolume)
	{
		pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
		pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
		pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

		//为阴影体设置材质
		D3DMATERIAL9 mtrl;
		ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
		mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
		mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
		mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
		mtrl.Diffuse.a = mtrl.Ambient.a = 0.5f;
		pd3dDevice->SetMaterial( &mtrl );
	}
	else  //只更新深度模板缓冲区
	{
		pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
		pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ZERO );
		pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
	}

	//渲染阴影体前面
	pd3dDevice->SetRenderState( D3DRS_STENCILFUNC,  D3DCMP_ALWAYS );
    pd3dDevice->SetRenderState( D3DRS_STENCILPASS,  D3DSTENCILOP_INCR );
	pd3dDevice->SetTransform( D3DTS_WORLD, pmatWorld );
	pd3dDevice->SetFVF( D3DFVF_XYZ );
    pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, m_dwNumVertices/3, 
		                         m_pVertices, sizeof(D3DXVECTOR3) );

	//渲染阴影体背面
	pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CW );
	pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );
	pd3dDevice->SetTransform( D3DTS_WORLD, pmatWorld );
	pd3dDevice->SetFVF( D3DFVF_XYZ );
    pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, m_dwNumVertices/3, 
		                         m_pVertices, sizeof(D3DXVECTOR3) );

	//恢复渲染状态
	pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
    pd3dDevice->SetRenderState( D3DRS_CULLMODE,  D3DCULL_CCW );
    pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,     TRUE );
    pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
    pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

    return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 销毁阴影体
//-----------------------------------------------------------------------------
HRESULT CShadowVolume::Destroy( )
{
	if(m_pMesh != NULL)
	{
		m_pMesh->Release();
		m_pMesh = NULL;
	}

	delete[] m_pVertices;
	return S_OK;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -