예제 #1
0
파일: Shadow.cpp 프로젝트: YunHsiao/RTR
void CShadow::onTick(float fElapsedTime) {
	for (unsigned int i(0); i < m_vMesh.size(); i++) {
		D3DXVECTOR3 vSun(*m_pSun); D3DXMATRIX mInv;
		D3DXMatrixInverse(&mInv, NULL, m_vMat[i]);
		D3DXVec3TransformCoord(&vSun, &vSun, &mInv);

		ID3DXMesh* pMesh;
		m_vMesh[i]->CloneMeshFVF(m_vMesh[i]->GetOptions(), D3DFVF_XYZ, 
			CDirect3D::getInstance()->GetD3D9Device(), &pMesh);

		D3DXVECTOR3 *pVertices, *pVolume;
		WORD* pIndices;
		pMesh->LockVertexBuffer(NULL, (void**) &pVertices);
		pMesh->LockIndexBuffer(NULL, (void**) &pIndices);
		DWORD dwFaces(pMesh->GetNumFaces());

		WORD* pEdges = new WORD[dwFaces*3*2];
		DWORD dwEdges(0);
		for (DWORD j(0); j < dwFaces; j++) {
			WORD wFace0 = pIndices[j*3];
			WORD wFace1 = pIndices[j*3+1];
			WORD wFace2 = pIndices[j*3+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, m_pSun) > 0.f) {
				AddEdge(pEdges, dwEdges, wFace0, wFace1);
				AddEdge(pEdges, dwEdges, wFace1, wFace2);
				AddEdge(pEdges, dwEdges, wFace2, wFace0);
			}
		}
		m_dwTriangles[i] = dwEdges*2;
		m_vVB[i]->Lock(0, sizeof(D3DXVECTOR3)*m_dwTriangles[i]*3, (void**) &pVolume, NULL);
		// some (solvable, but expensive) issues here: 
		// (view port related) direction undetermined for segment v1 - v2,
		// so CULL_CW doesn't necessarily mean 'back side'.
		for (DWORD j(0); j < dwEdges; j++) {
			D3DXVECTOR3 v1 = pVertices[pEdges[2*j+0]];	
			D3DXVECTOR3 v2 = pVertices[pEdges[2*j+1]];  
			D3DXVECTOR3 v3 = (v1 - vSun);				
			D3DXVECTOR3 v4 = (v2 - vSun);
			pVolume[j*6] = v3;		
			pVolume[j*6+1] = v1;	
			pVolume[j*6+2] = v4;	// 1 2
			pVolume[j*6+3] = v4;	// |\|
			pVolume[j*6+4] = v1;	// 3 4
			pVolume[j*6+5] = v2;
		}
		m_vVB[i]->Unlock();
		pMesh->UnlockVertexBuffer();
		pMesh->UnlockIndexBuffer();
		Safe_Release(pMesh);
		Safe_Delete_Array(pEdges);
	}
}
//-----------------------------------------------------------------------------
// Name: buildShadowVolume()
// Desc: Takes a mesh as input, and uses it to build a shadow volume. The
//       technique used considers each triangle of the mesh, and adds it's
//       edges to a temporary list. The edge list is maintained, such that
//       only silohuette edges are kept. Finally, the silohuette edges are
//       extruded to make the shadow volume vertex list.
//-----------------------------------------------------------------------------
HRESULT CShadowVolume::BuildShadowVolume(LPD3DXMESH pMesh, D3DXVECTOR3 vLight)
{
    // pMesh的顶点结构
    struct MeshVertex {
        D3DXVECTOR3 p;
        D3DXVECTOR3 n;
        float u, v;
    };

    MeshVertex *pVertices;
    WORD       *pIndices;

    // 锁缓存
    pMesh->LockVertexBuffer(0L, (LPVOID*)&pVertices);
    pMesh->LockIndexBuffer(0L, (LPVOID*)&pIndices);
    DWORD dwNumFaces = pMesh->GetNumFaces();

    // 分配一个临时的索引数组
    WORD *pEdges = new WORD[dwNumFaces * 6];

    if (pEdges == NULL)
    {
        pMesh->UnlockVertexBuffer();
        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].p;
        D3DXVECTOR3 v1 = pVertices[wFace1].p;
        D3DXVECTOR3 v2 = pVertices[wFace2].p;

        // 计算法线是否向光
        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);
        }
    }

    // pEdges中仅剩pMesh的边缘顶点,对每条边的两个顶点按光照的方向进行延伸
    // 最终构建一个完整的阴影体
    for (DWORD i = 0; i < dwNumEdges; ++i)
    {
        D3DXVECTOR3 v1 = pVertices[pEdges[2 * i + 0]].p;
        D3DXVECTOR3 v2 = pVertices[pEdges[2 * i + 1]].p;
        D3DXVECTOR3 v3 = v1 + vLight * 200;
        D3DXVECTOR3 v4 = v2 + vLight * 200;

        // 封边操作
        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 the temporary edge list
    delete[] pEdges;

    // Unlock the geometry buffers
    pMesh->UnlockVertexBuffer();
    pMesh->UnlockIndexBuffer();

    return S_OK;
}
예제 #3
0
void Sombra::ConstruirSombra(LPD3DXMESH pMesh, D3DXVECTOR3 vLight)
{
    // Note: the MeshVertex format depends on the FVF of the mesh
	struct MeshVertex { D3DXVECTOR3 p, n;
                            DWORD diffuse;
                         float tu,tv;   };

    MeshVertex *pVertices;
    WORD       *pIndices;

    // Lock the geometry buffers
    pMesh->LockVertexBuffer( 0L, (LPVOID*)&pVertices );
    pMesh->LockIndexBuffer( 0L, (LPVOID*)&pIndices );
    DWORD dwNumFaces    = pMesh->GetNumFaces();

    // Allocate a temporary edge list
    WORD *pEdges = new WORD[dwNumFaces*6];

    if( pEdges == NULL )
    {
        pMesh->UnlockVertexBuffer();
        pMesh->UnlockIndexBuffer();
        return ;
    }
	
    DWORD dwNumEdges = 0;

    // For each face
    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].p;
        D3DXVECTOR3 v1 = pVertices[wFace1].p;
        D3DXVECTOR3 v2 = pVertices[wFace2].p;

        // Transform vertices or transform light?
        D3DXVECTOR3 vCross1(v2-v1);
        D3DXVECTOR3 vCross2(v1-v0);
        D3DXVECTOR3 vNormal;
        D3DXVec3Cross( &vNormal, &vCross1, &vCross2 );

        if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f )
        {
            InsertarSegmento( pEdges, dwNumEdges, wFace0, wFace1 );
            InsertarSegmento( pEdges, dwNumEdges, wFace1, wFace2 );
            InsertarSegmento( pEdges, dwNumEdges, wFace2, wFace0 );
        }
    }

    // Se construyen las caras de la sombra extrudando los segmentos en la dirección
    // de la luz y una longitud 10 veces la del vector luz.
    for( i = 0; i < dwNumEdges; ++i )
    {
        D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]].p;
        D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]].p;
        D3DXVECTOR3 v3 = v1 - vLight/10;
        D3DXVECTOR3 v4 = v2 - vLight/10;

        // Add a quad (two triangles) to the vertex list
        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 the temporary edge list
    delete[] pEdges;

    // Unlock the geometry buffers
    pMesh->UnlockVertexBuffer();
    pMesh->UnlockIndexBuffer();

   
    
}