当前位置:网站首页>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
边栏推荐
- 解析token的网址
- Take you hand in hand to build Eureka client with idea
- Chisel tutorial - 03 Combinatorial logic in chisel (chisel3 cheat sheet is attached at the end)
- [summary] some panels and videos seen
- BSS 7230 航空内饰材料阻燃性能测试
- AITM3.0005 烟雾毒性测试
- Access database query all tables SQL
- HB 5469民用飞机机舱内部非金属材料燃烧试验方法
- One click free translation of more than 300 pages of PDF documents
- UIC564-2 附录4 –阻燃防火测试:火焰的扩散
猜你喜欢
随机推荐
HB 5469 combustion test method for non-metallic materials in civil aircraft cabin
Where are you going
Rectification characteristics of fast recovery diode
Redis caching tool class, worth owning~
At the age of 35, I made a decision to face unemployment
10 schemes to ensure interface data security
一个测试工程师的7年感悟 ---- 致在一路独行的你(别放弃)
DataGuard active / standby cleanup archive settings
Oracle statistics by time
codeforces每日5题(均1500)-第八天
Codeworks 5 questions per day (average 1500) - day 8
Dependency injection 2 advantage lifecycle
P2141 [noip2014 popularization group] abacus mental arithmetic test
Rock-paper-scissors
MySQL Architecture
Display the server hard disk image to the browser through Servlet
Wechat applet development beginner 1
C - linear table
2022.7.7-----leetcode. six hundred and forty-eight
Flash download setup