当前位置:网站首页>QT and OpenGL: loading 3D models using the open asset import library (assimp) - Part 2
QT and OpenGL: loading 3D models using the open asset import library (assimp) - Part 2
2022-07-07 23:53:00 【Raring_ Ringtail】
Qt and OpenGL: Use Open Asset Import Library(ASSIMP) load 3D Model - The first 2 part
Translated from :https://www.ics.com/blog/qt-and-opengl-loading-3d-model-open-asset-import-library-assimp-part-2
By John Stone Wednesday, May 18, 2016
welcome back . This is based on Eric Stone The article “Qt and OpenGL: Use Open Asset Import Library(ASSIMP) load 3D Model ” Follow up article of . Last time we introduced how to use ASSIMP Load the model into our data structure , So that you can use OpenGL Rendering . This time, , We will show you how to write a program to actually render these models .
obviously , We will use Qt As a platform layer ( As the title of this blog says ), We will be in Kejiang OpenGL And Qt Choose from various methods of integration QOpenGLWindow. ( More about , See this webinar :http://www.ics.com/webinars/state-art-opengl-and-qt).
This is the list of our project skeleton :
#include <QtGui/QGuiApplication>
#include <QtGui/QKeyEvent>
#include <QtGui/QOpenGLWindow>
#include <QtGui/QOpenGLBuffer>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLVertexArrayObject>
#include "modelloader.h"
static QString vertexShader =
"#version 330 core\n"
"\n"
"layout(location = 0) in vec3 vertexPosition;\n"
"layout(location = 1) in vec3 vertexNormal;\n"
"\n"
"out vec3 normal;\n"
"out vec3 position;\n"
"\n"
"uniform mat4 MV;\n"
"uniform mat3 N;\n"
"uniform mat4 MVP;\n"
" \n"
"void main()\n"
"{\n"
" normal = normalize( N * vertexNormal );\n"
" position = vec3( MV * vec4( vertexPosition, 1.0 ) );\n"
" gl_Position = MVP * vec4( vertexPosition, 1.0 );\n"
"}\n"
;
static QString fragmentShader =
"#version 330 core\n"
"\n"
"in vec3 normal;\n"
"in vec3 position;\n"
"\n"
"layout (location = 0) out vec4 fragColor;\n"
"\n"
"struct Light\n"
"{\n"
" vec4 position;\n"
" vec3 intensity;\n"
"};\n"
"uniform Light light;\n"
"\n"
"struct Material {\n"
" vec3 Ka;\n"
" vec3 Kd;\n"
" vec3 Ks;\n"
" float shininess;\n"
"};\n"
"uniform Material material;\n"
"\n"
"void main()\n"
"{\n"
" vec3 n = normalize( normal);\n"
" vec3 s = normalize( light.position.xyz - position);\n"
" vec3 v = normalize( -position.xyz);\n"
" vec3 h = normalize( v + s);\n"
" float sdn = dot( s, n);\n"
" vec3 ambient = material.Ka;\n"
" vec3 diffuse = material.Kd * max( sdn, 0.0);\n"
" vec3 specular = material.Ks * mix( 0.0, pow( dot(h, n), material.shininess), step( 0.0, sdn));\n"
" fragColor = vec4(light.intensity * (ambient + diffuse + specular), 1);\n"
"}\n"
;
struct Window : QOpenGLWindow, QOpenGLFunctions
{
Window() :
m_vbo(QOpenGLBuffer::VertexBuffer),
m_nbo(QOpenGLBuffer::VertexBuffer),
m_ibo(QOpenGLBuffer::IndexBuffer)
{
}
void createShaderProgram()
{
if ( !m_pgm.addShaderFromSourceCode( QOpenGLShader::Vertex, vertexShader)) {
qDebug() << "Error in vertex shader:" << m_pgm.log();
exit(1);
}
if ( !m_pgm.addShaderFromSourceCode( QOpenGLShader::Fragment, fragmentShader)) {
qDebug() << "Error in fragment shader:" << m_pgm.log();
exit(1);
}
if ( !m_pgm.link() ) {
qDebug() << "Error linking shader program:" << m_pgm.log();
exit(1);
}
}
void createGeometry()
{
}
void initializeGL()
{
QOpenGLFunctions::initializeOpenGLFunctions();
createShaderProgram(); m_pgm.bind();
m_pgm.setUniformValue("light.position", QVector4D( -1.0f, 1.0f, 1.0f, 1.0f ));
m_pgm.setUniformValue("light.intensity", QVector3D( 1.0f, 1.0f, 1.0f ));
createGeometry();
m_view.setToIdentity();
m_view.lookAt(QVector3D(0.0f, 0.0f, 1.2f), // Camera Position
QVector3D(0.0f, 0.0f, 0.0f), // Point camera looks towards
QVector3D(0.0f, 1.0f, 0.0f)); // Up vector
glEnable(GL_DEPTH_TEST);
glClearColor(.9f, .9f, .93f ,1.0f);
}
void resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
m_projection.setToIdentity();
m_projection.perspective(60.0f, (float)w/h, .3f, 1000);
update();
}
void draw()
{
}
void paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_pgm.bind();
m_vao.bind();
draw();
m_vao.release();
update();
}
void keyPressEvent(QKeyEvent * ev)
{
if (ev->key() == Qt::Key_Escape) exit(0);
}
ModelLoader m_loader;
QMatrix4x4 m_projection, m_view;
QOpenGLShaderProgram m_pgm;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo, m_nbo;
QOpenGLBuffer m_ibo;
GLsizei m_cnt;
};
int main(int argc, char *argv[])
{
QGuiApplication a(argc,argv);
QSurfaceFormat f;
f.setMajorVersion( 3 );
f.setMinorVersion( 3 );
f.setProfile( QSurfaceFormat::CoreProfile );
Window w;
w.setFormat(f);
w.setWidth(800); w.setHeight(600);
w.show();
return a.exec();
}
Use this code , We can draw almost any geometry you can give us , So our task will become how to fill the empty createGeometry() Methods and empty draw() Method . Let's first solve the problem of creating geometry . If you remember, we ended our first blog post with the following code :
ModelLoader model;
if (!model.Load("head.3ds"))
{
m_error = true;
return;
}
QVector<float> *vertices;
QVector<float> *normals;
QVector<unsigned int=""> *indices;
model.getBufferData(&vertices, &normals, &indices);
m_rootNode = model.getNodeData();
We said :“ Here we are , You have used OpenGL Display all the data required by the model .” Let's see how to turn it into code .
void createGeometry()
{
if(!m_loader.Load("velociraptor_mesh_materials.dae", ModelLoader::RelativePath)) {
qDebug() << "ModelLoader failed to load model" << m_pgm.log();
exit(1);
}
// Get the loaded model data from the model-loader: (v)ertices, (n)ormals, and (i)ndices
QVector<glfloat> *v, *n; QVector<gluint> *i; m_loader.getBufferData(&v, &n, &i);
// Initialize and bind the VAO that's going to capture all this vertex state
m_vao.create();
m_vao.bind();
// Put all the vertex data in a FBO
m_vbo.create();
m_vbo.setUsagePattern( QOpenGLBuffer::StaticDraw );
m_vbo.bind();
m_vbo.allocate(&(*v)[0], v->size() * sizeof((*v)[0]));
// Configure the attribute stream
m_pgm.enableAttributeArray(0);
m_pgm.setAttributeBuffer(0, GL_FLOAT, 0, 3);
// Put all the normal data in a FBO
m_nbo.create();
m_nbo.setUsagePattern( QOpenGLBuffer::StaticDraw );
m_nbo.bind();
m_nbo.allocate(&(*n)[0], n->size() * sizeof((*n)[0]));
// Configure the attribute stream
m_pgm.enableAttributeArray(1);
m_pgm.setAttributeBuffer(1, GL_FLOAT, 0, 3);
// Put all the index data in a IBO
m_ibo.create();
m_ibo.setUsagePattern( QOpenGLBuffer::StaticDraw );
m_ibo.bind();
m_ibo.allocate(&(*i)[0], i->size() * sizeof((*i)[0]));
// Okay, we've finished setting up the vao
m_vao.release();
}
What we are doing is to use the ModelLoader object , Ask it to load a “ velociraptor” Model , Then the model is in QVector Object to provide us with model data . then , We get the model data , And create a separate Vertex-Buffer and Index-Buffer object , Then upload the model data to the graphics card . There? , We configure the attribute flow for vertex shader input , Because they point to these buffer objects , Then we are ready to render .
Now? , Let's do the actual rendering . Review the first article ,ModelLoader Object returns a grid data tree , Each mesh object contains a bunch of metadata about how to render it ( Including material color data ). What we need to do is create an algorithm , Traverse this “ Grid tree ”, Render the mesh in turn . Let's see how we do this in our code .
void drawNode(const QMatrix4x4& model, const Node *node, QMatrix4x4 parent)
{
// Prepare matrices
QMatrix4x4 local = parent * node->transformation;
QMatrix4x4 mv = m_view * model * local;
m_pgm.setUniformValue("MV", mv);
m_pgm.setUniformValue("N", mv.normalMatrix());
m_pgm.setUniformValue("MVP", m_projection * mv);
// Draw each mesh in this node
for(int i = 0; i<node->meshes.size(); ++i)
{
const Mesh& m = *node->meshes[i];
if (m.material->Name == QString("DefaultMaterial")) {
m_pgm.setUniformValue("material.Ka", QVector3D( 0.05f, 0.2f, 0.05f ));
m_pgm.setUniformValue("material.Kd", QVector3D( 0.3f, 0.5f, 0.3f ));
m_pgm.setUniformValue("material.Ks", QVector3D( 0.6f, 0.6f, 0.6f ));
m_pgm.setUniformValue("material.shininess", 50.f);
} else {
m_pgm.setUniformValue("material.Ka", m.material->Ambient);
m_pgm.setUniformValue("material.Kd", m.material->Diffuse);
m_pgm.setUniformValue("material.Ks", m.material->Specular);
m_pgm.setUniformValue("material.shininess", m.material->Shininess);
}
glDrawElements(GL_TRIANGLES, m.indexCount, GL_UNSIGNED_INT, (const GLvoid*)(m.indexOffset * sizeof(GLuint)));
}
// Recursively draw this nodes children nodes
for(int i = 0; i < node->nodes.size(); ++i)
drawNode(model, &node->nodes[i], local);
}
void draw()
{
QMatrix4x4 model;
model.translate(-0.2f, 0.0f, .5f);
model.rotate(55.0f, 0.0f, 1.0f, 0.0f);
drawNode(model, m_loader.getNodeData().data(), QMatrix4x4());
}
As you can see , We have built an elegant recursive algorithm to traverse the grid tree . Please note that , In each recursive step , How does the current local transformation matrix become the parent transformation matrix of the next level . in addition , Notice how we update the lighting parameters with the lighting metadata of each mesh object , In order to render the mesh object correctly .
this is it , We are using Qt,OpenGL and ASSIMP Render Raptor !
Thanks to the contributing author :Eric Stone,ICS Software Engineer of .

About author

John Stone
John Stone Is an experienced software developer , With a wide range of computer science education and entrepreneurial background , And in graphic visualization and virtual reality (VR) Have rich practical experience in . As the University of Texas at Austin VR Former technical director and researcher of the Laboratory , He spent many years honing his skills , use OpenGL Develop for scientific experiments and other projects based on VR Data acquisition system .
original text :https://www.ics.com/blog/qt-and-opengl-loading-3d-model-open-asset-import-library-assimp-part-2
Welcome to my official account. Notes on Jiangda
边栏推荐
- Wechat applet development beginner 1
- C language greedy snake
- P1067 [noip2009 popularity group] polynomial output (difficult, pit)
- 第四期SFO销毁,Starfish OS如何对SFO价值赋能?
- HDU - 1260 Tickets(线性DP)
- postgis学习
- One click installation with fishros in blue bridge ROS
- 平衡二叉树【AVL树】——插入、删除
- FFA and ICGA angiography
- Ping error: unknown name or service
猜你喜欢

Learn about scratch

Data Lake (XV): spark and iceberg integrate write operations
![Arbre binaire équilibré [Arbre AVL] - Insérer et supprimer](/img/1f/cd38b7c6f00f2b3e85d4560181a9d2.png)
Arbre binaire équilibré [Arbre AVL] - Insérer et supprimer
postgis学习

激光slam学习(2D/3D、偏实践)

UIC564-2 附录4 –阻燃防火测试:火焰的扩散

MP4文件格式解析之结合实例分析

Chisel tutorial - 05 Sequential logic in chisel (including explicit multi clock, explicit synchronous reset and explicit asynchronous reset)

Take you hand in hand to build Eureka server with idea

Take you hand in hand to build Eureka client with idea
随机推荐
Go time package common functions
webflux - webclient Connect reset by peer Error
HB 5469 combustion test method for non-metallic materials in civil aircraft cabin
archery安装测试
Dependency injection
Idea automatically generates serialVersionUID
P5594 [xr-4] simulation match
正畸注意事项(持续更新中)
【leetcode】day1
【汇总】看过的一些Panel与视频
Chisel tutorial - 01 Introduction to Scala
【路径规划】使用垂距限值法与贝塞尔优化A星路径
Introduction to programming hardware
受限线性表
数据湖(十五):Spark与Iceberg整合写操作
一鍵免費翻譯300多頁的pdf文檔
Svn relocation
Chisel tutorial - 05 Sequential logic in chisel (including explicit multi clock, explicit synchronous reset and explicit asynchronous reset)
数据分析系列 之3σ规则/依据拉依达准则来剔除异常值
[path planning] use the vertical distance limit method and Bessel to optimize the path of a star