原文: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

装入md2格式文件faerie.md2

     

完整的代码请参考:

工程文件myTutorialD3D11_64

代码下载:

稍后提供

 

 

Directx11教程(67) 显示模型文件的更多相关文章

  1. Directx11教程(44) alpha blend(1)

    原文:Directx11教程(44) alpha blend(1)    我们知道,D3D11中按Frame来渲染物体,每个Frame中又可能包含若干个primitive,如下面的示意图所示:     ...

  2. DirectX11 With Windows SDK--19 模型加载:obj格式的读取及使用二进制文件提升读取效率

    前言 一个模型通常是由三个部分组成:网格.纹理.材质.在一开始的时候,我们是通过Geometry类来生成简单几何体的网格.但现在我们需要寻找合适的方式去表述一个复杂的网格,而且包含网格的文件类型多种多 ...

  3. 织梦中在线显示pdf文件的方法

    如何在织梦中添加pdf文件并显示呢?下面这个教程将带领大家来操作.(注:手机版无法查看) 第一步:在系统-系统基本参数-附件设置中添加pdf格式 并且将大小调大 第二步:在核心-内容模型-普通文章中添 ...

  4. Cesium官方教程7--三维模型

    原文地址:https://cesiumjs.org/tutorials/3D-Models-Tutorial/ 三维模型 (3D Models) 这篇教程给大家介绍,如何在Cesium中通过Primi ...

  5. Directx11教程(66) D3D11屏幕文本输出(1)

    原文:Directx11教程(66) D3D11屏幕文本输出(1)      在D3D10中,通过ID3DX10Font接口对象,我们可以方便的在屏幕上输出文字信息,一个DrawText函数就能解决所 ...

  6. Directx11教程(65) 渲染到纹理

    原文:Directx11教程(65) 渲染到纹理     通常情况下,我们的render target都是后缓冲,但也可以把render target设置为一个2d 纹理,然后再通过贴图的方式,把这个 ...

  7. Directx11教程(56) 建立一个skydome

    原文:Directx11教程(56) 建立一个skydome       本章建立一个skydome(天空穹),主要学习如何使用cube mapping.      cube map就是把六张纹理当作 ...

  8. Directx11教程(51) 简单的billboard

    原文:Directx11教程(51) 简单的billboard        billboard称作公告板,通常用一个quad(四边形)表示[有的billboard用两个正交的quad表示],它的特点 ...

  9. Directx11教程(42) 纹理映射(12)-简单的bump mapping

    原文:Directx11教程(42) 纹理映射(12)-简单的bump mapping        有时候,我们只有一个粗糙的模型,但是我们想渲染纹理细节,比如一个砖墙,我们如何在只有一个平面的时候 ...

随机推荐

  1. HDU 6003 Problem Buyer

    贪心题(好久不做了) 题解 考虑最一般的,判断合法性? 经典贪心问题:左端点升序,左端点相同,右端点降序,c[i]升序 优先队列,每次选择覆盖x的右端点最小的区间. 称此方法为“区间匹配贪心” 最小的 ...

  2. centos7如何配置yum仓库

    centos7如何配置yum仓库 一.总结 一句话总结: 备份原仓库配置原件,接来下按需求 百度 是指定本地光盘作为yum仓库,还是使用网络源作为yum仓库 二.centos7如何配置yum仓库 1. ...

  3. 阅读jeecms源码总结

    转载:https://blog.csdn.net/a382064640?t=1   Jeecsm使用框架包括:springMVC,HIbernate(数据持久层框架),Quartz(作业调度框架),a ...

  4. python的collections应用为字典哈希

    import collections allNum=collections.defaultdict(int) allNum[1]+=1 allNum[5]+=1 print(allNum) 当然,de ...

  5. WCF简要介绍

    什么是WCF WCF的全称是:Windows Communication Foundation.从本质上来说,它是一套软件开发包,是微软公司推出的符合SOA思想的技术框架.WCF为程序员提供了丰富的功 ...

  6. Leetcode500.Keyboard Row键盘行

    给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词.键盘如下图所示. 示例: 输入: ["Hello", "Alaska", "Dad& ...

  7. Visual Studio 2019 正式发布

    原文链接: https://www.oschina.net/news/105629/vs2019-general-availability 如约而至,微软已于今天推出 Visual Studio 20 ...

  8. JS引擎查找属性的原理

    原型继承的原理 不断向上查找 funciton getProperty(obj,prop){ if(obj.hasOwnProperty(prop){ return obj[prop]; }else ...

  9. <br>和换行符/n

    我们知道<br>是html的标签,表示文本另起一行.经常在html的body标签里面看到br,起到另起一行的作用. 而换行符\n是javascript的转义字符,表示将输出一个换行符,用于 ...

  10. springmvc框架使用拦截器实现301永久重定向,其实用过滤器应该是更好

    做seo的朋友提出要求 所有不带www.的访问需要301到带www的域名,以集中权重 可以使用过滤器检查servername带不带www,也可以使用拦截器 不会配置过滤器,所以先用拦截器实现吧,不过我 ...