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) 显示模型文件的更多相关文章
- Directx11教程(44) alpha blend(1)
原文:Directx11教程(44) alpha blend(1) 我们知道,D3D11中按Frame来渲染物体,每个Frame中又可能包含若干个primitive,如下面的示意图所示: ...
- DirectX11 With Windows SDK--19 模型加载:obj格式的读取及使用二进制文件提升读取效率
前言 一个模型通常是由三个部分组成:网格.纹理.材质.在一开始的时候,我们是通过Geometry类来生成简单几何体的网格.但现在我们需要寻找合适的方式去表述一个复杂的网格,而且包含网格的文件类型多种多 ...
- 织梦中在线显示pdf文件的方法
如何在织梦中添加pdf文件并显示呢?下面这个教程将带领大家来操作.(注:手机版无法查看) 第一步:在系统-系统基本参数-附件设置中添加pdf格式 并且将大小调大 第二步:在核心-内容模型-普通文章中添 ...
- Cesium官方教程7--三维模型
原文地址:https://cesiumjs.org/tutorials/3D-Models-Tutorial/ 三维模型 (3D Models) 这篇教程给大家介绍,如何在Cesium中通过Primi ...
- Directx11教程(66) D3D11屏幕文本输出(1)
原文:Directx11教程(66) D3D11屏幕文本输出(1) 在D3D10中,通过ID3DX10Font接口对象,我们可以方便的在屏幕上输出文字信息,一个DrawText函数就能解决所 ...
- Directx11教程(65) 渲染到纹理
原文:Directx11教程(65) 渲染到纹理 通常情况下,我们的render target都是后缓冲,但也可以把render target设置为一个2d 纹理,然后再通过贴图的方式,把这个 ...
- Directx11教程(56) 建立一个skydome
原文:Directx11教程(56) 建立一个skydome 本章建立一个skydome(天空穹),主要学习如何使用cube mapping. cube map就是把六张纹理当作 ...
- Directx11教程(51) 简单的billboard
原文:Directx11教程(51) 简单的billboard billboard称作公告板,通常用一个quad(四边形)表示[有的billboard用两个正交的quad表示],它的特点 ...
- Directx11教程(42) 纹理映射(12)-简单的bump mapping
原文:Directx11教程(42) 纹理映射(12)-简单的bump mapping 有时候,我们只有一个粗糙的模型,但是我们想渲染纹理细节,比如一个砖墙,我们如何在只有一个平面的时候 ...
随机推荐
- R语言建立回归分析,并利用VIF查看共线性问题的例子
R语言建立回归分析,并利用VIF查看共线性问题的例子 使用R对内置longley数据集进行回归分析,如果以GNP.deflator作为因变量y,问这个数据集是否存在多重共线性问题?应该选择哪些变量参与 ...
- PAT甲级——A1014 Waiting in Line
Suppose a bank has N windows open for service. There is a yellow line in front of the windows which ...
- [Day2] Nginx静态文件
上一节我们介绍了nginx的三个使用场景和一些配置语法参数,今天我们就用一章的内容来介绍一下Nginx作为静态资源服务器的配置和常见问题. 一. 简单的静态服务器 话不多说,直接上配置代码. se ...
- Elasticsearch快速开始
Elasticsearch是一个分布式RESTful风格的搜索和数据分析引擎 查询:Elasticsearch允许执行和合并多种类型的搜索——结构化.非结构化.地理位置.度量指标.搜索方式随心而变 分 ...
- Jmeter环境搭建及目录介绍
Jmeter环境搭建及目录介绍 运行环境:jmeter是基于java语言的,所有需要准备Java的JDK环境,并添加到环境变量中. 一.环境搭建及配置 1.JMeter的下载: 官网:http://j ...
- Luogu P1462 通往奥格瑞玛的道路(最短路+二分)
P1462 通往奥格瑞玛的道路 题面 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己 ...
- 洛谷P4022 熟悉的文章
题意:给定一个串集合s,每次给定一个串t,询问一个最大的L,使得存在一种划分能把t划分成若干个子串, 其中好的子串总长不小于0.9|t|.好的子串定义为长度不小于L且是s中某一个串的子串. 解:发现这 ...
- linux和window双系统下修改系统启动项
参考:http://jingyan.baidu.com/article/63acb44ae4062c61fcc17e27.html: 我们在安装双系统之后经常会遇到想打开windows但默认启动项是u ...
- UVA10905 Children's Game
题意:给定n个正整数,把它们连接成一个最大的整数.比如,123,124,556,90有24种连接方法,最大的结果为9 056 124 123. 贪心.一开始就想用string水过.注意不能直接用str ...
- git(转)
转载:http://www.cnblogs.com/my-freedom/p/5701427.html 一.如何安装git 下载地址: https://git-scm.com/download/win ...