创建立方环境地图图面 (Direct3D 9)

通过调用 CreateCubeTexture 方法创建立方环境贴图纹理。 立方体环境贴图纹理必须是正方形的,其维度的幂为 2。

下面的代码示例演示 C++ 应用程序如何创建简单的三次环境映射。

// Init m_d3dDevice to point to an IDirect3DDevice9 interface

LPDIRECT3DCUBETEXTURE9 m_pCubeMap;

m_d3dDevice->CreateCubeTexture(256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R8G8B8,
                                D3DPOOL_DEFAULT, &m_pCubeMap);

访问立方环境映射面

可以使用 GetCubeMapSurface 方法在立方体环境映射的面之间导航。

下面的代码示例使用 GetCubeMapSurface 检索用于正 y 面 (人脸 2) 的多维数据集映射图面。

// Init m_pCubeMap to point to an IDirect3DCubeTexture9 interface

LPDIRECT3DSURFACE9 pFace2;
m_pCubeMap->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_Y, 0, &pFace2);

GetCubeMapSurface 接受的第一个参数是一个D3DCUBEMAP_FACES枚举值,该值描述方法应检索的附加图面。 第二个参数告知 Direct3D 要检索的经过错误应用的多维数据集纹理的哪个级别。 接受的第三个参数是 IDirect3DSurface9 接口的地址,表示返回的多维数据集纹理图面。 由于未应用此多维数据集映射,因此此处使用 0。

注意

调用此方法后, IDirect3DSurface9 接口上的内部引用计数将增加。 使用此图面后,请务必在此 IDirect3DSurface9 接口上调用 IUnknown 方法,否则会出现内存泄漏。

 

呈现到立方环境映射

可以将图像复制到立方体贴图的各个面,就像对任何其他纹理或表面对象一样。 渲染到人脸之前,最重要的事情是设置转换矩阵,以便相机正确定位并指向该人脸的正确方向:向前 (+z) ,向后 (-z) ,左 (-x) ,右 (+x) ,向上 (+y) ,或向下 (-y) 。

以下 C++ 代码示例根据呈现的人脸准备和设置视图矩阵。

// Init pCubeMap to point to an IDirect3DCubeTexture9 interface
// Init d3dDevice to point to an IDirect3DDevice9 interface

void RenderFaces()
{
    // Save transformation matrices of the device
    D3DXMATRIX matProjSave, matViewSave;
    d3dDevice->GetTransform(D3DTS_VIEW,       &matViewSave ;
    d3dDevice->GetTransform(D3DTS_PROJECTION, &matProjSave);

    // Store the current back buffer and z-buffer
    LPDIRECT3DSURFACE9 pBackBuffer, pZBuffer;
    d3dDevice->GetRenderTarget(&pBackBuffer);
    d3dDevice->GetDepthStencilSurface(&pZBuffer);

请记住,立方体环境映射的每个面都表示 90 度的视野。 除非应用程序需要其他视场(例如,对于特殊效果),否则请注意相应地设置投影矩阵。

此代码示例为最常见的情况创建并设置投影矩阵。

    // Use 90-degree field of view in the projection
    D3DMATRIX matProj;
    D3DXMatrixPerspectiveFovLH(matProj, D3DX_PI/2, 1.0f, 0.5f, 1000.0f);
    d3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

    // Loop through the six faces of the cube map
    for(DWORD i=0; i<6; i++)
    {
        // Standard view that will be overridden below
        D3DVECTOR vEnvEyePt = D3DVECTOR(0.0f, 0.0f, 0.0f);
        D3DVECTOR vLookatPt, vUpVec;

        switch(i)
        {
            case D3DCUBEMAP_FACE_POSITIVE_X:
                vLookatPt = D3DVECTOR(1.0f, 0.0f, 0.0f);
                vUpVec    = D3DVECTOR(0.0f, 1.0f, 0.0f);
                break;
            case D3DCUBEMAP_FACE_NEGATIVE_X:
                vLookatPt = D3DVECTOR(-1.0f, 0.0f, 0.0f);
                vUpVec    = D3DVECTOR( 0.0f, 1.0f, 0.0f);
                break;
            case D3DCUBEMAP_FACE_POSITIVE_Y:
                vLookatPt = D3DVECTOR(0.0f, 1.0f, 0.0f);
                vUpVec    = D3DVECTOR(0.0f, 0.0f,-1.0f);
                break;
            case D3DCUBEMAP_FACE_NEGATIVE_Y:
                vLookatPt = D3DVECTOR(0.0f,-1.0f, 0.0f);
                vUpVec    = D3DVECTOR(0.0f, 0.0f, 1.0f);
                break;
            case D3DCUBEMAP_FACE_POSITIVE_Z:
                vLookatPt = D3DVECTOR( 0.0f, 0.0f, 1.0f);
                vUpVec    = D3DVECTOR( 0.0f, 1.0f, 0.0f);
                break;
            case D3DCUBEMAP_FACE_NEGATIVE_Z:
                vLookatPt = D3DVECTOR(0.0f, 0.0f,-1.0f);
                vUpVec    = D3DVECTOR(0.0f, 1.0f, 0.0f);
                break;
        }

         D3DMATRIX matView;
         D3DXMatrixLookAtLH(matView, vEnvEyePt, vLookatPt, vUpVec);
         d3dDevice->SetTransform(D3DTS_VIEW, &matView);

当相机就位且投影矩阵设置时,可以渲染场景。 场景中每个对象的位置应与平时的位置一样。 为完整性提供以下代码示例概述了此任务。

        // Get pointer to surface in order to render to it
        LPDIRECT3DSURFACE9 pFace;
        pCubeMap->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pFace);
        d3dDevice->SetRenderTarget (pFace , pZBuffer);
        SAFE_RELEASE(pFace);

        d3dDevice->BeginScene();
        // Render scene here
        ...
        d3dDevice->EndScene();
    }

    // Change the render target back to the main back buffer.
    d3dDevice->SetRenderTarget(pBackBuffer, pZBuffer);
    SAFE_RELEASE(pBackBuffer);
    SAFE_RELEASE(pZBuffer);

    // Restore the original transformation matrices
    d3dDevice->SetTransform(D3DTS_VIEW,       &matViewSave);
    d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjSave);
}

请注意对 SetRenderTarget 方法的调用。 呈现到多维数据集地图人脸时,必须将人脸指定为当前呈现目标图面。 使用深度缓冲区的应用程序可以为呈现目标显式创建深度缓冲区,或将现有的深度缓冲区重新分配给呈现目标图面。 上面的代码示例使用后一种方法。

立方环境映射