DirectX基础学习系列8 渐进网格以及外接体

1 IUnknown--> ID3DXBUFFER D3D泛型接口:

GetBufferPointer

Retrieves a pointer to the data in the buffer.

GetBufferSize

Retrieves the total size of the data in the buffer.

使用完之后需要进行释放:Release()

2XFILE

//从文件中加载xfile文件

 HRESULT  D3DXLoadMeshFromX(
  __in   LPCTSTR pFilename,    //xfile文件名
  __in   DWORD Options,        //加载可选项
  __in   LPDIRECT3DDEVICE9 pD3DDevice, //设备
  __out  LPD3DXBUFFER *ppAdjacency,  //临街信息,DWORD数组
  __out  LPD3DXBUFFER *ppMaterials,  //材质信息
  __out  LPD3DXBUFFER *ppEffectInstances, //
  __out  DWORD *pNumMaterials,   //材质数目
  __out  LPD3DXMESH *ppMesh
);
//材质结构:ppMaterials结构中第I项 对应第I个子集
typedef struct D3DXMATERIAL {
  D3DMATERIAL9 MatD3D;
  LPSTR        pTextureFilename;
} D3DXMATERIAL, *LPD3DXMATERIAL;
加载时,首先加载XFILE文件,然后遍历纹理数据,将纹理数据加载,在渲染的时候,先设置纹理和纹理
3生成顶点法线
方便使用光照,网格的法向量计算方法
 HRESULT  D3DXComputeNormals(
  __inout  LPD3DXBASEMESH pMesh,     //输出的网格数据
  __in     const DWORD *pAdjacency   //临街数据
);
pMesh参数中顶点格式必须包含D3DFVF_NORMAL,所以需要从原先的mesh数据copy一份过来
4.渐进网格
类似于渐进纹理数据,通过边折叠技术对网格进行简化,并且这种操作时可逆转的
渐进网格从已有的网格数据中产生:
    D3DXGeneratePMesh(
        LPD3DXMESH pMesh, 
        CONST DWORD* pAdjacency, //邻接信息dword数组
        CONST D3DXATTRIBUTEWEIGHTS *pVertexAttributeWeights, //指定相应顶点属性权值 涉及被移除的概率
        CONST FLOAT *pVertexWeights,  //指定顶点权值,涉及被移除的概率
        DWORD MinValue,        //面片简化的最少值,如果设置为1 表示尽可能的少
        DWORD Options,         //决定上面的参数为定点数或者面片数
        LPD3DXPMESH* ppPMesh); 
D3DXATTRIBUTEWEIGHTS 顶点属相权值结构,暂且使用默认值
D3DXPMesh提供的操作接口:
GetMaxFaces() //最多的面片数目上限
GetMinFaces() //最少的面片数目下限
GetMaxVertexs() //最多的顶点数目上限
GetMinVertexs() //最少的顶点数目下限
SetNumFaces() // 设置面片数目,
SetNumVertexs() //设置顶点数目
trimByFaces(newfacemin , newfacemax, --- ., --)  // 重新设置顶点的最大,最小限制
trimByVetex(newfacemin , newfacemax, --- ., --)  // 重新设置顶点的最大,最小限制
5外接体:可以用于检测碰撞以及可见性
//外接球
    D3DXComputeBoundingSphere(
        CONST D3DXVECTOR3 *pFirstPosition,  // pointer to first position  指向顶点的第一个位置
DWORD NumVertices, 数组中顶点数目 DWORD dwStride, // count in bytes to subsequent position vectors 每个顶点字节数 D3DXVECTOR3 *pCenter, 外界球中心 FLOAT *pRadius); 外接球半径
// 外界体
    D3DXComputeBoundingBox(
        CONST D3DXVECTOR3 *pFirstPosition,  // pointer to first position,指向顶点的第一个位置
        DWORD NumVertices,                      //顶点数组中的顶点数目
        DWORD dwStride,                     // count in bytes to subsequent position vectors 每个顶点的字节数
        D3DXVECTOR3 *pMin,     //返回的
        D3DXVECTOR3 *pMax);
//////////////////////////////////////////////////////////////////////////////////////////////////
// 
// File: boundingvolumes.cpp
// 
// Author: Frank Luna (C) All Rights Reserved
//
// System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 
//
// Desc: Demonstrates how to use D3DXComputeBoundingSphere and D3DXComputeBoundingBox.
//
//      -The spacebar key switches between rendering the mesh's bounding sphere and box.
//          
//////////////////////////////////////////////////////////////////////////////////////////////////

#include "d3dUtility.h"
#include <vector>

//
// Globals
//

IDirect3DDevice9* Device = 0; 

const int Width  = 640;
const int Height = 480;

ID3DXMesh*                      Mesh = 0;
ID3DXPMesh*                     pMesh = 0;
std::vector<D3DMATERIAL9>       Mtrls(0);
std::vector<IDirect3DTexture9*> Textures(0);

ID3DXMesh* SphereMesh = 0;
ID3DXMesh* BoxMesh    = 0;

bool RenderBoundingSphere = true;

//
// Prototypes
//

bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere);
bool    ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox*    box);

//
// Framework functions
//
bool Setup()
{
    HRESULT hr = 0;

    //
    // Load the XFile data.
    //
    ID3DXBuffer* adjBuffer  = 0;
    ID3DXBuffer* mtrlBuffer = 0;
    DWORD        numMtrls   = 0;

    hr = D3DXLoadMeshFromX(  
        "bigship1.x",
        D3DXMESH_MANAGED,
        Device,
        &adjBuffer,
        &mtrlBuffer,
        0,
        &numMtrls,
        &Mesh);

    if(FAILED(hr))
    {
        ::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);
        return false;
    }

    //
    // Extract the materials, load textures.
    //

    if( mtrlBuffer != 0 && numMtrls != 0 )
    {
        D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();

        for(int i = 0; i < numMtrls; i++)
        {
            // the MatD3D property doesn't have an ambient value set
            // when its loaded, so set it now:
            mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;

            // save the ith material
            Mtrls.push_back( mtrls[i].MatD3D );

            // check if the ith material has an associative texture
            if( mtrls[i].pTextureFilename != 0 )
            {
                // yes, load the texture for the ith subset
                IDirect3DTexture9* tex = 0;
                D3DXCreateTextureFromFile(
                    Device,
                    mtrls[i].pTextureFilename,
                    &tex);

                // save the loaded texture
                Textures.push_back( tex );
            }
            else
            {
                // no texture for the ith subset
                Textures.push_back( 0 );
            }
        }
    }
    d3d::Release<ID3DXBuffer*>(mtrlBuffer); // done w/ buffer

    //
    // Optimize the mesh.
    //

    hr = Mesh->OptimizeInplace(        
        D3DXMESHOPT_ATTRSORT |
        D3DXMESHOPT_COMPACT  |
        D3DXMESHOPT_VERTEXCACHE,
        (DWORD*)adjBuffer->GetBufferPointer(),
        0, 0, 0);

    d3d::Release<ID3DXBuffer*>(adjBuffer); // done w/ buffer

    if(FAILED(hr))
    {
        ::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);
        return false;
    }

    //
    // Compute Bounding Sphere and Bounding Box.
    //
    
    d3d::BoundingSphere boundingSphere;
    d3d::BoundingBox    boundingBox;

    ComputeBoundingSphere(Mesh, &boundingSphere);
    ComputeBoundingBox(Mesh, &boundingBox);

    D3DXCreateSphere(
        Device,
        boundingSphere._radius,
        20,
        20,
        &SphereMesh,
        0);

    D3DXCreateBox(
        Device,
        boundingBox._max.x - boundingBox._min.x,
        boundingBox._max.y - boundingBox._min.y,
        boundingBox._max.z - boundingBox._min.z,
        &BoxMesh,
        0);

    //
    // Set texture filters.
    //

    Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

    // 
    // Set Lights.
    //

    D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);
    D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);
    D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);

    Device->SetLight(0, &light);
    Device->LightEnable(0, true);
    Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
    Device->SetRenderState(D3DRS_SPECULARENABLE, true);

    //
    // Set camera.
    //

    D3DXVECTOR3 pos(4.0f, 12.0f, -20.0f);
    D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

    D3DXMATRIX V;
    D3DXMatrixLookAtLH(
        &V,
        &pos,
        &target,
        &up);

    Device->SetTransform(D3DTS_VIEW, &V);

    //
    // Set projection matrix.
    //

    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
            &proj,
            D3DX_PI * 0.5f, // 90 - degree
            (float)Width / (float)Height,
            1.0f,
            1000.0f);
    Device->SetTransform(D3DTS_PROJECTION, &proj);

    return true;
}

void Cleanup()
{
    d3d::Release<ID3DXMesh*>(Mesh);

    for(int i = 0; i < Textures.size(); i++)
        d3d::Release<IDirect3DTexture9*>( Textures[i] );

    d3d::Release<ID3DXMesh*>(SphereMesh);
    d3d::Release<ID3DXMesh*>(BoxMesh);
}

bool Display(float timeDelta)
{
    if( Device )
    {
        //
        // Update: Rotate the mesh.
        //

        static float y = 0.0f;
        D3DXMATRIX yRot;
        D3DXMatrixRotationY(&yRot, y);
        y += timeDelta;

        if( y >= 6.28f )
            y = 0.0f;

        D3DXMATRIX World = yRot;

        Device->SetTransform(D3DTS_WORLD, &World);

        //
        // Render
        //

        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        Device->BeginScene();

        // draw the mesh
        for(int i = 0; i < Mtrls.size(); i++)
        {
            Device->SetMaterial( &Mtrls[i] );
            Device->SetTexture(0, Textures[i]);
            Mesh->DrawSubset(i);
        }    

        //
        // Draw bounding volume in blue and at 10% opacity
        D3DMATERIAL9 blue = d3d::BLUE_MTRL;
        blue.Diffuse.a = 0.10f; // 10% opacity

        Device->SetMaterial(&blue);
        Device->SetTexture(0, 0); // disable texture

        Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
        Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
        Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

        if( RenderBoundingSphere )
            SphereMesh->DrawSubset(0);
        else
            BoxMesh->DrawSubset(0);

        Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);

        Device->EndScene();
        Device->Present(0, 0, 0, 0);
    }
    return true;
}

//
// WndProc
//
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch( msg )
    {
    case WM_DESTROY:
        ::PostQuitMessage(0);
        break;
        
    case WM_KEYDOWN:
        if( wParam == VK_ESCAPE )
            ::DestroyWindow(hwnd);

        if( wParam == VK_SPACE )
            RenderBoundingSphere = !RenderBoundingSphere;

        break;
    }
    return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
                   HINSTANCE prevInstance, 
                   PSTR cmdLine,
                   int showCmd)
{
    if(!d3d::InitD3D(hinstance,
        Width, Height, true, D3DDEVTYPE_HAL, &Device))
    {
        ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
        return 0;
    }
        
    if(!Setup())
    {
        ::MessageBox(0, "Setup() - FAILED", 0, 0);
        return 0;
    }

    d3d::EnterMsgLoop( Display );

    Cleanup();

    Device->Release();

    return 0;
}

bool ComputeBoundingSphere(ID3DXMesh* mesh, d3d::BoundingSphere* sphere)
{
    HRESULT hr = 0;

    BYTE* v = 0;
    mesh->LockVertexBuffer(0, (void**)&v);

    hr = D3DXComputeBoundingSphere(
            (D3DXVECTOR3*)v,
            mesh->GetNumVertices(),
            D3DXGetFVFVertexSize(mesh->GetFVF()),
            &sphere->_center,
            &sphere->_radius);

    mesh->UnlockVertexBuffer();

    if( FAILED(hr) )
        return false;

    return true;
}

bool ComputeBoundingBox(ID3DXMesh* mesh, d3d::BoundingBox* box)
{
    HRESULT hr = 0;

    BYTE* v = 0;
    mesh->LockVertexBuffer(0, (void**)&v);

    hr = D3DXComputeBoundingBox(
            (D3DXVECTOR3*)v,
            mesh->GetNumVertices(),
            D3DXGetFVFVertexSize(mesh->GetFVF()),
            &box->_min,
            &box->_max);

    mesh->UnlockVertexBuffer();

    if( FAILED(hr) )
        return false;

    return true;
}
View Code

 

posted @ 2013-10-29 12:19  RubbyZhang  阅读(529)  评论(0编辑  收藏  举报