assimp批量转模型,[OpenGL] 使用Assimp导入模型(Qt)
最近终于决定要在本身的demo中加入模型了!本次选择的是开源库Assimp,以前一直嫌麻烦没有去落实这件事,但实际上,assimp的配置意外的没有我想象中的那么麻烦。html
下载源码后,须要使用cmake进行编译,在上方选择源码位置,和build工程的位置,若是没有什么特殊的配置需求的话,直接按顺序依次点1,2,3的按钮便可。Configure的时候,可能会遇到一个dx的error,按照引用文章的提示,直接在http://www.microsoft.com/en-us/download/details.aspx?id=6812下载相关组件,安装中还可能遇到s1023的错误代码,此处可在命令行输入(卸载vs的一些组件):post
MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}
MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}
这里特别须要注意的是,cmake的generator选择,须要和最终调用assimp的编译器匹配。好比,个人Qt版本为:5.11.2 MSVC2017 64bit。ui
也就是我使用了vs的msvc做为c++的编译器,而且是2017版本,64位的。那么相应的,如cmake界面右下角红色框所标出的,generator选择Visual Studio 15 2017 Win64。spa
编译完成以后,打开对应工程,切到release模式,而后点编译。以后,能够在code/Release获得咱们所需的lib和dll(用不一样的编译器获得的名称会不太同样):.net
以后,咱们在Qt的pro文件处,新建include文件夹,把源码中的include内容复制过去;新建lib文件夹,把assimpxxx.lib放到该文件夹下。最后,把assimpxxx.dll放到生成的exe所在的文件夹下。(若是设定了shadow build和构建目录,那么就在这一目录下)。命令行
最后,在.pro按以下写好lib和include的链接:code
INCLUDEPATH += include
LIBS += -L$$PWD/lib/ \
-lassimp-vc140-mt
配置完成后,能够开始导入代码的编写。Assimp仅仅是实现了导入相关的功能,这些导入的数据实际上要如何使用,是须要额外实现的。orm
因为个人材质是动态加载和替换的,因此此处只导入了顶点、法线和纹理坐标:
(5.15更新,以前的代码只能加载一个mesh,改进了一下,不过每一个mesh只支持一个贴图)
#ifndef GEOMETRYENGINE_H
#define GEOMETRYENGINE_H
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct VertexData
{
QVector3D position;
QVector3D tangent;
QVector3D normal;
QVector2D texcoord;
};
struct MeshBuffer
{
QOpenGLBuffer arrayBuf;
QOpenGLBuffer indexBuf;
int vertexNum;
int indiceNum;
MeshBuffer() : indexBuf(QOpenGLBuffer::IndexBuffer)
{
arrayBuf.create();
indexBuf.create();
}
~MeshBuffer()
{
arrayBuf.destroy();
indexBuf.destroy();
}
void Init(VertexData* vertex, int num)
{
vertexNum = num;
arrayBuf.bind();
arrayBuf.allocate(vertex, vertexNum * static_cast(sizeof(VertexData)));
}
void Init(GLushort* indice, int num)
{
indiceNum = num;
indexBuf.bind();
indexBuf.allocate(indice, indiceNum * static_cast(sizeof(GLushort)));
}
void bind()
{
arrayBuf.bind();
indexBuf.bind();
}
};
struct Mesh
{
string name;
MeshBuffer* buffer = nullptr;
QOpenGLTexture* albedo;
};
class Model
{
private:
vector vecMesh;
public:
void Push(Mesh* mesh)
{
vecMesh.emplace_back(mesh);
}
MeshBuffer* GetMeshBuffer(size_t idx) { return vecMesh[idx]->buffer;}
Mesh* GetMesh(size_t idx) { return vecMesh[idx];}
size_t Count() { return vecMesh.size();}
};
class GeometryEngine
{
public:
GeometryEngine();
virtual ~GeometryEngine();
bool loadObj(string path, Model*& pModel);
void drawObj(string path,QOpenGLShaderProgram* program,bool bTess = false);
void drawObj(MeshBuffer* meshBuffer, QOpenGLShaderProgram* program,bool bTess = false);
void CalTangent(VertexData& vertex0, VertexData& vertex1, VertexData& vertex2);
private:
void processNode(const string& path, aiNode *node, const aiScene *scene);
void processMesh(vector& vertices, vector& indices, QOpenGLTexture*& albedo, aiMesh *mesh, const aiScene *scen);
map mapModel;
};
#endif // GEOMETRYENGINE_H
#include "geometryengine.h"
#include "resourceinfo.h"
#include
#include
#include
GeometryEngine::GeometryEngine()
{
}
GeometryEngine::~GeometryEngine()
{
}
bool GeometryEngine::loadObj(string path, Model*& pModel)
{
if(mapModel.find(path) != mapModel.end())
{
return true;
}
Assimp::Importer import;
const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
qDebug() << "ERROR::ASSIMP::" << import.GetErrorString() ;
return false;
}
string directory = path.substr(0, path.find_last_of('/'));
processNode(path, scene->mRootNode, scene);
pModel = &mapModel[path];
return true;
}
void GeometryEngine::drawObj(MeshBuffer* meshBuffer, QOpenGLShaderProgram* program,bool bTess)
{
meshBuffer->bind();
auto gl = QOpenGLContext::currentContext()->extraFunctions();
int offset = 0;
int vertexLocation = program->attributeLocation("a_position");
program->enableAttributeArray(vertexLocation);
program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
offset += sizeof(QVector3D);
int tangentLocation = program->attributeLocation("a_tangent");
program->enableAttributeArray(tangentLocation);
program->setAttributeBuffer(tangentLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
offset += sizeof(QVector3D);
int normalLocation = program->attributeLocation("a_normal");
program->enableAttributeArray(normalLocation);
program->setAttributeBuffer(normalLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
offset += sizeof(QVector3D);
int texcoordLocation = program->attributeLocation("a_texcoord");
program->enableAttributeArray(texcoordLocation);
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
if(bTess)
{
gl->glPatchParameteri(GL_PATCH_VERTICES, 3);
gl->glDrawElements(GL_PATCHES, meshBuffer->indiceNum, GL_UNSIGNED_SHORT, nullptr);
}
else
{
gl->glDrawElements(GL_TRIANGLES, meshBuffer->indiceNum, GL_UNSIGNED_SHORT, nullptr);
}
}
void GeometryEngine::drawObj(string path,QOpenGLShaderProgram* program,bool bTess)
{
Model* pModel;
if(mapModel.find(path) == mapModel.end())
{
if(!loadObj(path, pModel))
{
return;
}
}
auto vecMesh = mapModel[path];
for(size_t i = 0;i < vecMesh.Count();i++)
{
auto meshBuffer = vecMesh.GetMeshBuffer(i);
drawObj(meshBuffer,program, bTess);
}
}
void GeometryEngine::processMesh(vector& vertices, vector& indices, QOpenGLTexture*& albedo, aiMesh *mesh, const aiScene *scene)
{
for(unsigned int i = 0; i < mesh->mNumVertices; i++)
{
VertexData vertex;
if(mesh->mVertices)
{
vertex.position = QVector3D(mesh->mVertices[i].x,mesh->mVertices[i].y,mesh->mVertices[i].z);
}
if(mesh->mTextureCoords[0])
{
vertex.texcoord = QVector2D(mesh->mTextureCoords[0][i].x,mesh->mTextureCoords[0][i].y);
}
if(mesh->mNormals)
{
vertex.normal = QVector3D(mesh->mNormals[i].x,mesh->mNormals[i].y,mesh->mNormals[i].z);
vertex.normal.normalized();
}
if(mesh->mTangents)
{
vertex.tangent = QVector3D(mesh->mTangents[i].x,mesh->mTangents[i].y,mesh->mTangents[i].z);
}
vertices.push_back(vertex);
}
for(unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for(unsigned int j = 0; j < face.mNumIndices; j++)
{
indices.push_back(static_cast(face.mIndices[j]));
}
}
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
for(unsigned int i = 0; i < material->GetTextureCount(aiTextureType_DIFFUSE); i++)
{
aiString str;
material->GetTexture(aiTextureType_DIFFUSE, i, &str);
albedo = CResourceInfo::Inst()->CreateTexture(str.C_Str());
}
}
void GeometryEngine::processNode(const string& path, aiNode *node, const aiScene *scene)
{
// process all the node's meshes (if any)
for(unsigned int i = 0; i < node->mNumMeshes; i++)
{
vector vertices;
vector indices;
QOpenGLTexture* albedo = nullptr;
aiMesh *aimesh = scene->mMeshes[node->mMeshes[i]];
processMesh(vertices, indices, albedo, aimesh, scene);
MeshBuffer* meshBuffer = new MeshBuffer();
for(size_t i = 0;i < indices.size() / 3; i++)
{
CalTangent(vertices[indices[3 * i]],vertices[indices[3 * i + 1]],vertices[indices[3 * i + 2]]);
}
meshBuffer->Init(vertices.data(),static_cast(vertices.size()));
meshBuffer->Init(indices.data(),static_cast(indices.size()));
Mesh* mesh = new Mesh();
mesh->name = node->mName.C_Str();
mesh->buffer = meshBuffer;
mesh->albedo = albedo;
mapModel[path].Push(mesh);
}
// then do the same for each of its children
for(unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(path, node->mChildren[i], scene);
}
}
void GeometryEngine::CalTangent(VertexData& vertex0, VertexData& vertex1, VertexData& vertex2)
{
float u0 = vertex0.texcoord.x();
float v0 = vertex0.texcoord.y();
float u1 = vertex1.texcoord.x();
float v1 = vertex1.texcoord.y();
float u2 = vertex2.texcoord.x();
float v2 = vertex2.texcoord.y();
float t1 = u1 - u0;
float b1 = v1 - v0;
float t2 = u2 - u0;
float b2 = v2 - v0;
QVector3D e0 = vertex1.position - vertex0.position;
QVector3D e1 = vertex2.position - vertex0.position;
float k = t1 * b2 - b1 * t2;
QVector3D tangent;
tangent = k * QVector3D(b2 * e0.x() - b1 * e1.x(),b2 * e0.y() - b1 * e1.y(),b2 * e0.z() - b1 * e1.z());
QVector vertexArr = { &vertex0, &vertex1, &vertex2};
QVector adjoinPlane;
adjoinPlane.resize(vertexArr.size());
for(int i = 0;i < vertexArr.size();i++)
{
adjoinPlane[i]++;
float ratio = 1.0f / adjoinPlane[i];
vertexArr[i]->tangent = vertexArr[i]->tangent * (1 - ratio) + tangent * ratio;
vertexArr[i]->tangent.normalize();
}
}
接下来,咱们能够试着导入一个简单的模型。
在建模软件maya中,拖出一个简单的甜甜圈,并勾选使用三角面显示:
给这个甜甜圈绑定一个uv,此处uv用了一个圆柱形投影,将其水平扫描设为360度,高度稍微调高一些。这里只是大体获得一个还算过得去的uv纹理。
选中当前对象,而后在文件菜单选择导出当前选择,而后根据本身的需求导出:
而后就能够把这个"甜甜圈”导入本身的项目中了:
试着加一下材质,除了有一块由于瞎搞的uv致使不太对的地方,其它看起来都没什么问题了。
assimp批量转模型,[OpenGL] 使用Assimp导入模型(Qt)相关推荐
- OpenGL通过Assimp加载模型
OpenGL通过Assimp加载模型 OpenGL通过Assimp加载模型简介 源代码剖析 主要源代码 OpenGL通过Assimp加载模型简介 到目前为止,我们已经使用了手动创建的模型.如您所见,为 ...
- DAZ3D导入模型设置材质
Substance里导出模型及贴图 导入模型到DAZ 选中模型,进入表面选项卡设置材质贴图 透明度默认是0就TM离谱 DAZ里
- python 导入模型_scikit-learn系列之如何存储和导入机器学习模型
scikit-learn系列之如何存储和导入机器学习模型 如何存储和导入机器学习模型 找到一个准确的机器学习模型,你的项目并没有完成.本文中你将学习如何使用scikit-learn来存储和导入机器学习 ...
- SKIL/工作流程/导入模型
导入模型 TensorFlow, Caffe, Keras, 与 Deeplearning4j 都可以导入到SKIL SKIL模型导入允许数据科学家将他们在其他地方创建的深度学习模型部署到SKIL模型 ...
- QT+OpenGL模型加载 - Assimp
QT+OpenGL模型加载 - Assimp 本篇完整工程见gitee:OpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主 模型加载 先来张图: 我们不大可能手 ...
- 3Ds max批量导入模型
3Ds max批量导入模型 3Ds max 批量导入脚本,复制到maxscript界面,运行即可弹出插件. rollout mytools "批量导入" ( button bt1 ...
- “winform+opengl+freeglut“实现导入两关节机械臂的obj模型,并进行旋转、平移等操作
开发环境:vs2019 开发工具:C++.OpenGL 工具库:freeglut 窗口:winform 主要实现:将OpenGL绘图窗口嵌入Winform窗口,在OpenGL窗口中导入事先准备好的ob ...
- unity 批量导入模型工具_零基础的Unity图形学笔记3:使用多模型UV与优化模型导出...
前文所说,贴图多UV,直接命名对应贴图就可以. 模型的多套UV,则需要在3DMAX里编辑. 这篇文章主要解决两个问题: 如何正确使用多模型UV? 从3DMAX导出,到shader使用 如何优化模型导出 ...
- 南邮|计算机图形学——导入模型、添加天空盒
导入模型 1.网格 #include <string> #include <fstream> #include <sstream> #include <ios ...
- matlab 三维模型怎么导入ansys,Ansys怎么导入模型?Ansys导入模型的方法
Ansys是一款非常好用的CAE工具之一,它提供了一个完整的实体建模及网格划分工具,那你知道Ansys怎么导入模型的吗?接下来我们一起往下看看Ansys导入模型的方法吧. 方法步骤 1.这里小编以常用 ...
最新文章
- 【Linux 内核】CFS 调度器 ① ( CFS 完全公平调度器概念 | CFS 调度器虚拟时钟 Virtual Runtime 概念 | 四种进程优先级 | 五种调度类 )
- 登录页面test记录
- WordPress的RSS订阅优化
- 动态传参, 名称空间, 嵌套, gloabal, nonlocal
- linux git clone 401,Git Eclipse:401未经授权的错误
- SENT (Single Edge Nibble Transmission) 协议 接口
- 红包封面发货平台卡密系统 全新红包封面平台可搭建分站独立后台的源码
- 干掉Dubbo,换下Spring Cloud,这个架构有点厉害!
- postman 接口测试用例设计
- eax, ebx, ecx, edx, esi, edi, ebp, esp
- SKYLAKE平台安装win7步骤(U盘)
- 刘强东的“毛乌素”之斗
- [答疑]类图:支付手段和优惠券、金额、积分有关
- 微型计算机最大的电路板是,微型计算机系统中最大的一块电路板被称作 。
- EXCEL难题一网打尽 无意间看到的 转过来 自己看看
- iOS底层系统:虚拟内存
- 【Java接口】限制App登录次数
- GlassFish4安装部署
- Android实战(二)—— 房贷计算器
- python中pack什么意思_Python struct.pack如何理解其原理
热门文章
- 阿里巴巴实习 面试题
- DiffuseBumpCutout‘: invalid subscript ‘boxMax‘ at line 151
- PS中如何简单、快速更换照片的背景色
- 自动控制原理分析工作原理以及方框图做题过程
- (XWZ)的Python学习笔记Ⅱ------面向对象编程
- (XWZ)的python学习笔记——pandas
- 精品微信小程序ssm培训机构管理系统+后台管理系统|前后分离VUE
- 程序员眼中的中国传统文化-王阳明《传习录》21
- webservice 教程学习系列(八)——wsdl文档深入分析
- 西电计算机软件考研,西安电子科技大学软件工程硕士考研