• 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

    代码下载:

    稍后提供

     

  • 相关阅读:
    setTimeout的时间设为0的问题
    nodejs的简单服务器程序
    使用Promise规定来处理ajax请求的结果
    使用myfocus制作焦点图
    给Array添加删除重复元素函数
    css派生选择器
    Javascript 参数传递
    Node.js 搞Javascript开发的无论如何要尝试一下
    CSS九宫格带边框的多种实现
    80%人会答错的JS基础面试题
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2831538.html
Copyright © 2020-2023  润新知