综述:本文介绍了如何读取一个.obj文件并将其用OpenGL绘制出来
用到的模型文件可以在UR3机器人的官方网站上下载,一般下载的模型文件是.STEP文件或者是.SLDSAM格式,使用SOLIDWORKS打开下载的模型文件,同时需要安装SW的插件,插件安装参考。环境配置好后还是用SW打开模型文件,按照建立的DH参数模型在模型中建立参考坐标系、基准轴。建好后如下图所示
点击工具–>Tools–>“Export as URDF”,按照机器人的构型选定每一个link包含的模型部分、参考坐标系和参考基准轴如下图。
最重要的设置是参考坐标系与基准轴,这将直接决定导出的模型的参考坐标系
设置完后点击Preview and Export导出模型,直接点next然后Export如下图,此时已经将机械臂模型按照每一个link导出为多个stl文件
在输出的文件夹中meshs文件夹中即为stl文件
使用Blender软件导入STL进行细微调整(可能需要调整坐标轴朝向)并导出OBJ文件即可
上述模型的描述文件如下
# 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();