Directx11教程(67) 顯示模型文件


      在前面的教程中,我們都是通過在ModelClass中直接產生頂點和索引數據,簡單的三角形,立方體等等還好說,畢竟比較簡單,如何顯示復雜的三維物體呢?特別是利用已有的3D文件,比如obj, 3ds, md2, x等格式的文件,這時,就要利用這些3D格式的解析器,本教程中,我們利用Open Asset Import Library庫,來顯示各種格式的3D文件(動畫文件,暫時不考慮,只考慮靜態的3D文件)。

      Open Asset Import Library是一個開源的模型導入庫,支持很多格式,它的下載和安裝就不介紹了,下面我再myTutorialD3D11_35的基礎上,加入使用Assimp庫導入3D文件的代碼。

     主要就是增加了一個AssimpModelClass類,該類中頂點格式為:

{
D3DXVECTOR3 position;
D3DXVECTOR3 normal; //法向
D3DXVECTOR2 texture; //紋理坐標
D3DXVECTOR4 Kd;  //材質漫反射系數
D3DXVECTOR4 Ks;  //材質的高光系數
};

 

產生頂點和索引緩沖的函數為AssimpModelClass,我們通過該函數產生頂點緩沖和索引緩沖。

bool  AssimpModelClass::LoadModel(ID3D11Device* device, std::string filename)
{
    HRESULT result;

注意:首先我們會定義一個assimp導入器類,用該類讀入模型文件,我們會做2趟循環,第一趟循環得到頂點和索引的數量,然后創建頂點和索引臨時緩沖,用來保存頂點和索引數據,第二趟循環從模型文件中讀取頂點和索引的數據,最后創建頂點和索引緩沖。
    Assimp::Importer importer;
    VertexType* vertices;
    unsigned long* indices;
    D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
    D3D11_SUBRESOURCE_DATA vertexData, indexData;


    const aiScene* scene = importer.ReadFile(filename,aiProcessPreset_TargetRealtime_Quality);
   
    if(!scene)
    {
        MessageBoxA(NULL, importer.GetErrorString(), "Error", MB_OK);
        return false;
    }

    int m =0;
    //第一趟掃描,得到頂點和索引計數
    for(m=0; m<scene->mNumMeshes; ++m )
    {
        //第m個mesh
        aiMesh* aiMesh = scene->mMeshes[m];

        m_vertexCount += aiMesh->mNumVertices;
        m_indexCount  += aiMesh->mNumFaces*3;
    }

    // 創建頂點臨時緩沖.
    vertices = new VertexType[m_vertexCount];
    if(!vertices)
    {
        return false;
    }

    // 創建索引臨時緩沖.
    indices = new unsigned long[m_indexCount];
    if(!indices)
    {
        return false;
    }

    //臨時的頂點和索引指針
    int index1 = 0;
    int index2 = 0;
    int i = 0;

    //第二趟循環,得到每個頂點和索引的值
    for(m=0; m<scene->mNumMeshes; ++m )
    {
        //第m個mesh
        aiMesh* aiMesh = scene->mMeshes[m];

        if(!aiMesh->HasNormals() || !aiMesh->HasTextureCoords(0))
        {
            MessageBox(NULL, L"模型文件中沒有紋理坐標或者法向信息", L"Error", MB_OK);
            return false;
        }

        int vertexCount = aiMesh->mNumVertices;
        for(i = 0;i < vertexCount;++i)
        {
            vertices[index1].position = D3DXVECTOR3(aiMesh->mVertices[i].x, aiMesh->mVertices[i].y, aiMesh->mVertices[i].z);
            vertices[index1].normal = D3DXVECTOR3(aiMesh->mNormals[i].x, aiMesh->mNormals[i].y, aiMesh->mNormals[i].z);
            vertices[index1].texture = D3DXVECTOR2(aiMesh->mTextureCoords[0][i].x, aiMesh->mTextureCoords[0][i].y);
            vertices[index1].Kd = D3DXVECTOR4(1.0, 1.0, 1.0,1.0);
            vertices[index1].Ks = D3DXVECTOR4(0.2, 0.2, 0.2,1.0);
            index1++;
        }

        for (i = 0; i < aiMesh->mNumFaces;++i)
        {
            const aiFace& Face = aiMesh->mFaces[i];
            //assert(Face.mNumIndices == 3);
            indices[index2] = Face.mIndices[0];
            index2++;
            indices[index2] = Face.mIndices[1];
            index2++;
            indices[index2] = Face.mIndices[2];
            index2++;

        }
    }
    // 設置頂點緩沖描述
    vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = 0;
    vertexBufferDesc.MiscFlags = 0;
    vertexBufferDesc.StructureByteStride = 0;

    // 指向保存頂點數據的臨時緩沖.
    vertexData.pSysMem = vertices;
    vertexData.SysMemPitch = 0;
    vertexData.SysMemSlicePitch = 0;

    // 創建頂點緩沖.
    result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer);
    if(FAILED(result))
    {
        HR(result);
        return false;
    }

    // 設置索引緩沖描述.
    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount;
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;
    indexBufferDesc.StructureByteStride = 0;

    // 指向存臨時索引緩沖.
    indexData.pSysMem = indices;
    indexData.SysMemPitch = 0;
    indexData.SysMemSlicePitch = 0;

    // 創建索引緩沖.
    result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);
    if(FAILED(result))
    {
        HR(result);
        return false;
    }

    // 釋放臨時緩沖.
    delete [] vertices;
    vertices = 0;

    delete [] indices;
    indices = 0;

    return true;

}

     隨后在GraphicsClass中,我們會增加AssimpModelClass變量,並用LightTexShader來渲染該類裝入的模型,主要的代碼如下:

1、初始化的代碼

// 創建assimp模型對象
m_AssimpModel = new AssimpModelClass;
if(!m_AssimpModel)
    {
    return false;
    }
// 初始化坐標assimp模型對象.faerie.md2,tiny.x
result = m_AssimpModel->Initialize(m_D3D->GetDevice(), "tiny.x");
if(!result)
    {
    MessageBox(hwnd, L"Could not initialize the axis model object.", L"Error", MB_OK);
    return false;
    }

2、渲染的代碼:

D3DXMatrixScaling(&worldMatrix4, 0.02, 0.02,0.02);

m_AssimpModel->Render(m_D3D->GetDeviceContext());
//用light shader渲染,faerie2.bmp,Tiny_skin.dds
result = m_LightTexShader->Render(m_D3D->GetDeviceContext(), m_AssimpModel->GetIndexCount(), worldMatrix4, viewMatrix, projectionMatrix,
             light, material, camera,m_TexManager->createTex(m_D3D->GetDevice(),string("Tiny_skin.dds")));
if(!result)
    {
    return false;
    }

程序執行后的效果圖如下:

裝入x格式文件tiny.x

image

裝入md2格式文件faerie.md2

image

     

完整的代碼請參考:

工程文件myTutorialD3D11_64

代碼下載:

稍后提供

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM