Qt+OpenGL进阶教学之三维模型读取

Qt+OpenGL进阶教学之三维模型读取

基于Qt+OpenGL的UR3机械臂仿真与控制系统(三)

综述:本文介绍了如何读取一个.obj文件并将其用OpenGL绘制出来

机械臂模型转.OBJ

用到的模型文件可以在UR3机器人的官方网站上下载,一般下载的模型文件是.STEP文件或者是.SLDSAM格式,使用SOLIDWORKS打开下载的模型文件,同时需要安装SW的插件,插件安装参考。环境配置好后还是用SW打开模型文件,按照建立的DH参数模型在模型中建立参考坐标系、基准轴。建好后如下图所示

Qt+OpenGL进阶教学之三维模型读取_第1张图片

点击工具–>Tools–>“Export as URDF”,按照机器人的构型选定每一个link包含的模型部分、参考坐标系和参考基准轴如下图。

Qt+OpenGL进阶教学之三维模型读取_第2张图片

最重要的设置是参考坐标系与基准轴,这将直接决定导出的模型的参考坐标系

设置完后点击Preview and Export导出模型,直接点next然后Export如下图,此时已经将机械臂模型按照每一个link导出为多个stl文件

Qt+OpenGL进阶教学之三维模型读取_第3张图片

在输出的文件夹中meshs文件夹中即为stl文件

使用Blender软件导入STL进行细微调整(可能需要调整坐标轴朝向)并导出OBJ文件即可

.OBJ文件格式

Qt+OpenGL进阶教学之三维模型读取_第4张图片

上述模型的描述文件如下

# Blender 3.3.1
# www.blender.org
mtllib link2.mtl
o link2
v 0.051850 -0.000000 0.082150
v 0.061750 -0.000000 0.082150
v 0.061750 -0.007838 0.082974
......
vn -0.0000 -0.1046 -0.9945
vn -0.0000 -0.3089 -0.9511
vn -0.0000 -0.5000 -0.8660
......
s 0
f 1//1 2//1 3//1
f 1//1 3//1 4//1
f 4//2 3//2 5//2
......

v 就是点的位置信息(3f x,y,z)

vn 就是点的法线信息(3f x,y,z)

vt 是点的纹理坐标(3f u,v,w),一般只用uv坐标即可

f 即面的信息

下面给出C++读取.OBJ文件的代码

readmodel.h

#ifndef READMODEL_H
#define READMODEL_H
#include 
#include 
#include 
#include
//#include 

#include "./robot_simulation.h"

class readObj{
  public:
    struct Face
    {
        int v[3];
        int t[3];
        int n[3];
    };
    std::vector<std::vector<QVector3D>> vertexs;  //保存点坐标
    std::vector<std::vector<QVector3D>> normals;  //保存法向量
    QVector<QVector3D> m_texcoords;//保存纹理坐标
    readObj(QString filename);
    void draw();
};

#endif // READMODEL_H

readmodel.cpp

#include "./readmodel.h"
#include 

readObj::readObj(QString filename)
{
    QFile file(filename);
    if(!file.open(QIODevice::ReadOnly))
    {
        qDebug()<<"[Error] fail to open file :"<<filename;
        return;
    }
    QTextStream ts(&file);
    // Temp arrays;
    QVector<QVector3D> v;
    QVector<QVector3D> vn;
    QVector<QVector3D> vt;
    QVector<QStringList> str_faces;
    QVector<Face> faces;
    while(!ts.atEnd())
    {
        QStringList list = ts.readLine().split(QRegExp("(\\s+)"));
        list.removeAll(" ");
        if(list.size() == 0 )
            break;
        if(list[0] == "v")
            v.push_back(QVector3D(list[1].toFloat(),list[2].toFloat(),list[3].toFloat()));
        if(list[0] == "vn")
            vn.push_back(QVector3D(list[1].toFloat(),list[2].toFloat(),list[3].toFloat()));
        if(list[0] == "vt")
            vt.push_back(QVector3D(list[1].toFloat(),list[2].toFloat(),0));
        if(list[0] == "f")
            str_faces.push_back(list);
    }
    for( int i =0; i< str_faces.size(); i++)
    {
        Face face;
        for( int j = 1; j<=3; j++)  //这种解析方式仅针对每个面都是三角形的渲染场景
        {
            QStringList list = str_faces[i][j].split("/");
            face.v[j-1] = list[0].toInt() -1;
            face.t[j-1] = list[1].toInt() -1;
            face.n[j-1] = list[2].toInt() -1;
        }
        faces.push_back(face);
    }

    for( int i = 0; i<faces.size();i++)
    {
        std::vector<QVector3D> vertex,normal;
        QVector3D a,b,c,na,nb,nc;
        a = v[faces[i].v[0]];
        b = v[faces[i].v[1]];
        c = v[faces[i].v[2]];
        na = vn[faces[i].n[0]];
        nb = vn[faces[i].n[1]];
        nc = vn[faces[i].n[2]];
        vertex.push_back(a);
        vertex.push_back(b);
        vertex.push_back(c);
        normal.push_back(na);
        normal.push_back(nb);
        normal.push_back(nc);
        vertexs.push_back(vertex);
        normals.push_back(normal);
    }
    file.close();
    std::cout<<"model_size:"<<vertexs.size()<<std::endl;
}

void readObj::draw()  //渲染模型
{
    glBegin(GL_TRIANGLES);
    glColor3f(0.1f,0.0f,0.0f);
    for (int i=0;i<vertexs.size();i++){
        glVertex3f(vertexs[i][0].x(),vertexs[i][0].y(),vertexs[i][0].z());
        glVertex3f(vertexs[i][1].x(),vertexs[i][1].y(),vertexs[i][1].z());
        glVertex3f(vertexs[i][2].x(),vertexs[i][2].y(),vertexs[i][2].z());
        glNormal3f(normals[i][0].x(),normals[i][0].y(),normals[i][0].z());
        glNormal3f(normals[i][1].x(),normals[i][1].y(),normals[i][1].z());
        glNormal3f(normals[i][2].x(),normals[i][2].y(),normals[i][2].z());
    }
    glEnd();
}

分析:构造函数中读取.OBJ文件将点和面的信息存入类成员变量中,要绘制三维模型的时候调用类的draw()函数

void ROBOT_SIMULATION::initializeGL()
{
    initializeOpenGLFunctions();
    base_link  = new readObj("./new_ur3_model/base_link.obj");
    link1  = new readObj("./new_ur3_model/link1.obj");
    link2  = new readObj("./new_ur3_model/link2.obj");
    link3  = new readObj("./new_ur3_model/link3.obj");
    link4  = new readObj("./new_ur3_model/link4.obj");
    link5  = new readObj("./new_ur3_model/link5.obj");
    link6  = new readObj("./new_ur3_model/link6.obj");
    ......
}
base_link->draw();

整体效果

Qt+OpenGL进阶教学之三维模型读取_第5张图片

你可能感兴趣的:(qt,开发语言)