当前位置: 首页 > article >正文

qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体,并且我们实现了立方体的旋转,光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件(head.obj)。资源在本页下载

2 在obj文件里面,我们关注下 v 字段和f字段

 v 字段就是顶点  f字段代表了面,意思是每个面的顶点编号。 结构如下

v -0.99179999 -2.98999995 4.05410025  表示顶点值

f 12791 127 126   表示这个面的三个点在 v 里面的index值是12791 也是就是v[12791]的值的顶点是这个面的顶点值。

3 下面我们来解析obj文件

bool load(QString fileName, QVector<float>& vPoints)
{
    if (fileName.mid(fileName.lastIndexOf('.')) != ".obj" && fileName.mid(fileName.lastIndexOf('.')) != ".OBJ")
    {
        qDebug() << "file is not a obj file.";
        return false;
    }
    QFile objFile(fileName);
    if (!objFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "open" << fileName << "failed";
        return false;
    }
    else
    {
        qDebug() << "open" << fileName << "success!";
    }

    QVector<float> vertextPoints, texturePoints, normalPoints;
    QVector<Face> facesIndexs;
    while (!objFile.atEnd())
    {
        QByteArray lineData = objFile.readLine();

        QList<QByteArray> strValues = lineData.trimmed().split(' ');
        QString dataType = strValues.takeFirst();
        for(int i=0;i<strValues.size();i++)
        {
            double nData = strValues.at(i).toDouble();
            QString strTemp = QString::number(nData,'f',4);
            if (dataType == "v")
            {
                vertextPoints.append(strTemp.toFloat());
            }
            else if (dataType == "vt")
            {
               texturePoints.append(strValues.at(i).toFloat());
            }
            else if (dataType == "vn")
            {
                normalPoints.append(strValues.at(i).toFloat());
            }
            else if (dataType == "f")
            {
                Face ondInfo;
                if(strValues.at(i).contains("/"))
                {
                    QList<QByteArray> strTemp = strValues.at(i).split('/');
                    if(strTemp.size()==2)
                    {
                      ondInfo.vertices  =  strTemp.at(0).toInt();
                      ondInfo.texCoords =  strTemp.at(1).toInt();
                    }
                    else if(strTemp.size()==3)
                    {
                        ondInfo.vertices  =  strTemp.at(0).toInt();
                        ondInfo.texCoords =  strTemp.at(1).toInt();
                        ondInfo.normals   =  strTemp.at(2).toInt();
                    }
                }
                else
                {
                    ondInfo.vertices = strValues.at(i).toInt();
                    //qDebug()<<"Face ondInfo"<<ondInfo.vertices;
                }
                facesIndexs.append(ondInfo);
            }
        }
    }
    objFile.close();
    int count =0;
    for (int i=0;i<facesIndexs.size();i++)
    {
        int vIndex = facesIndexs[i].vertices - 1;
        if(vIndex * 3 <=vertextPoints.size() ||vIndex * 3 + 1 <=vertextPoints.size()||vIndex * 3 + 2<=vertextPoints.size() )
        {
            vPoints << vertextPoints.at(vIndex * 3);
            vPoints << vertextPoints.at(vIndex * 3 + 1);
            vPoints << vertextPoints.at(vIndex * 3 + 2);
           // qDebug()<<"vIndex"<<i<<vertextPoints.size()<<vIndex * 3;
        }
        else
        {
         //  qDebug()<<"vIndex error"<<i<<vertextPoints.size()<<vIndex * 3;
        }
    }
    vertextPoints.clear();
    texturePoints.clear();
    normalPoints.clear();
    facesIndexs.clear();

    return true;
}

 接着我们来写加载代码

和以前的一样,就是写glsl语句,

#ifndef TESTOBJOPENGL_H
#define TESTOBJOPENGL_H

#include <QObject>
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QOpenGLTexture>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QMouseEvent>

QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram);
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)
class testobjOpengl : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    testobjOpengl( QWidget *parent=nullptr);
    ~testobjOpengl();
protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int width, int height) override;
    void rotateBy(int xAngle, int yAngle, int zAngle);
    bool load(QString fileName, QVector<float>& vPoints);
    struct Face{
       int vertices;
       int texCoords;
       int normals;
       Face()
       {
           vertices = -1;
           texCoords = -1;
           normals = -1;
       }
    };
private:
    QVector<float> m_vPoints;
    int m_xRot;
    int m_yRot;
    int m_zRot;
    QOpenGLShaderProgram *m_program= nullptr;
    QOpenGLVertexArrayObject vao;
    QOpenGLBuffer vbo;
    QVector3D cameraPos;
    QVector3D cameraTarget;
    QVector3D cameraDirection;
    QOpenGLTexture *texture;

    int m_projMatrixLoc;
    int m_mvMatrixLoc;
    int m_normalMatrixLoc;
    int m_lightPosLoc;
    QMatrix4x4 m_proj;

    QMatrix4x4 m_camera;
    QMatrix4x4 m_world;
    QVector3D m_camera_pos;
    QTimer* timer;

    int  m_yPos=0;
    int  m_zPos=0;

};

#endif // TESTOBJOPENGL_H
#include "testobjopengl.h"

static const char *vertexShaderSourceCore =
        "#version 330\n"
        "layout (location = 0) in vec4 vertex;\n"
        "layout (location = 1) in vec3 normal;\n"
        "out vec3 vert;\n"
        "out vec3 vertNormal;\n"
        "uniform  mat4 matrix;\n"
        "uniform  mat4 view;\n"
        "uniform  mat4 projection;\n"
        "uniform  mat3 normalMatrix;\n"
        "void main() {\n"
        "   vert = vertex.xyz;\n"
        "   vertNormal = normalMatrix * normal;\n"
        "   gl_Position = projection*view* matrix * vertex;\n"
        "}\n";
static const char *fragmentShaderSourceCore =
        "#version 150\n"
        "in highp vec3 vert;\n"
        "in highp vec3 vertNormal;\n"
        "out highp vec4 fragColor;\n"
        "uniform highp vec3 lightPos;\n"
        "void main() {\n"
        "   highp vec3 L = normalize(lightPos - vert);\n"
        "   highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n"
        "   highp vec3 color = vec3(1.0, 1.0, 0.0);\n"
        "   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n"
        "   fragColor = vec4(col, 1.0);\n"
        "}\n";

testobjOpengl::testobjOpengl(QWidget *parent)
    : QOpenGLWidget(parent),
      m_xRot(0),
      m_yRot(0),
      m_zRot(0)
{
    m_vPoints.clear();
    cameraPos = QVector3D(0, 0, 3);
    QString strTemp = "F:/Tree2/head.obj";
    bool ret = load(strTemp,m_vPoints);
    if(ret)
    {
        timer = new QTimer;
        timer->setInterval(100);
        connect(timer,&QTimer::timeout,this,[=]{
            qDebug()<<"timeout";
            rotateBy(10 * 16, +10 * 16, -1 * 16);
        });
        timer->start();
    }
    else
    {
       qDebug()<<"1111111111111111";
    }

}
void testobjOpengl::rotateBy(int xAngle, int yAngle, int zAngle)
{
    float cameraSpeed = 0.2;
    m_camera_pos -= cameraSpeed * QVector3D(0, 0, -1);//由远到近
    if(m_yPos>=100)
    {
       m_yPos = 0;
    }
    m_yPos+=10;
    if(m_zPos>=100)
    {
       m_zPos = 0;
    }
    m_zPos+=10;
   // m_camera_pos = QVector3D(0, m_yPos, m_zPos);//由远到近
   // m_camera_pos.setY(m_yPos);
    m_xRot += xAngle;
    m_yRot += yAngle;
    m_zRot += zAngle;
    update();
    //timer->stop();
}
testobjOpengl::~testobjOpengl()
{

}

void testobjOpengl::initializeGL()
{
    initializeOpenGLFunctions();
    m_program = new QOpenGLShaderProgram;
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSourceCore);
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSourceCore);
    if (m_program->link())
    {
        qDebug() << "link success!";
    }
    else
    {
        qDebug() << "link failed";
    }
    m_program->bindAttributeLocation("vertex", 0);
    m_program->bindAttributeLocation("normal", 1);
    m_program->link();
    m_program->bind();

//    m_projMatrixLoc = m_program->uniformLocation("projection");
//    m_mvMatrixLoc = m_program->uniformLocation("matrix");
//    m_normalMatrixLoc = m_program->uniformLocation("normalMatrix");
//    m_lightPosLoc = m_program->uniformLocation("lightPos");

    vbo.create();
    vbo.bind();
    vbo.allocate(m_vPoints.data(), m_vPoints.size() * sizeof(float));

    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
    f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
    vbo.release();
    m_program->setUniformValue(m_lightPosLoc, QVector3D(10, 10, 10)); 
}


void testobjOpengl::paintGL()
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);


    QMatrix4x4 m;
    //m.ortho(-0.5f, +0.5f, +0.5f, -0.5f, 4.0f, 15.0f);
    m.setToIdentity();
    m.translate(0.0f, 0.0f, 0.0f);
    m.rotate(m_xRot / 16.0f, 1.0f, 0.0f, 0.0f);
    m.rotate(90, 0.0f, 1.0f, 0.0f);
    m.rotate(0, 0.0f, 0.0f, 1.0f);
    m.scale(0.5);

    QMatrix4x4 view;
    view.setToIdentity();
    view.lookAt(QVector3D(0, 20, 20), QVector3D(0,0,0), QVector3D(1,0,0));



    m_program->bind();
    m_program->setUniformValue("projection", m_proj);
    m_program->setUniformValue("matrix", m);
    m_program->setUniformValue("view", view);
    m_program->setUniformValue("lightPos", QVector3D(10, 10, 0));
    QMatrix3x3 normalMatrix = m.normalMatrix();
    m_program->setUniformValue("normalMatrix", normalMatrix);

    glDrawArrays(GL_TRIANGLES, 0, m_vPoints.size()/3);

    m_program->release();
}

void testobjOpengl::resizeGL(int width, int height)
{
    m_proj.setToIdentity();
    m_proj.perspective(45.0f, GLfloat(width) / height, 0.01f, 100.0f);
}
bool testobjOpengl::load(QString fileName, QVector<float>& vPoints)
{
    if (fileName.mid(fileName.lastIndexOf('.')) != ".obj" && fileName.mid(fileName.lastIndexOf('.')) != ".OBJ")
    {
        qDebug() << "file is not a obj file.";
        return false;
    }
    QFile objFile(fileName);
    if (!objFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "open" << fileName << "failed";
        return false;
    }
    else
    {
        qDebug() << "open" << fileName << "success!";
    }

    QVector<float> vertextPoints, texturePoints, normalPoints;
    QVector<Face> facesIndexs;
    while (!objFile.atEnd())
    {
        QByteArray lineData = objFile.readLine();

        QList<QByteArray> strValues = lineData.trimmed().split(' ');
        QString dataType = strValues.takeFirst();
        for(int i=0;i<strValues.size();i++)
        {
            double nData = strValues.at(i).toDouble();
            QString strTemp = QString::number(nData,'f',4);
            if (dataType == "v")
            {
                vertextPoints.append(strTemp.toFloat());
            }
            else if (dataType == "vt")
            {
               texturePoints.append(strValues.at(i).toFloat());
            }
            else if (dataType == "vn")
            {
                normalPoints.append(strValues.at(i).toFloat());
            }
            else if (dataType == "f")
            {
                Face ondInfo;
                if(strValues.at(i).contains("/"))
                {
                    QList<QByteArray> strTemp = strValues.at(i).split('/');
                    if(strTemp.size()==2)
                    {
                      ondInfo.vertices  =  strTemp.at(0).toInt();
                      ondInfo.texCoords =  strTemp.at(1).toInt();
                    }
                    else if(strTemp.size()==3)
                    {
                        ondInfo.vertices  =  strTemp.at(0).toInt();
                        ondInfo.texCoords =  strTemp.at(1).toInt();
                        ondInfo.normals   =  strTemp.at(2).toInt();
                    }
                }
                else
                {
                    ondInfo.vertices = strValues.at(i).toInt();
                    //qDebug()<<"Face ondInfo"<<ondInfo.vertices;
                }
                facesIndexs.append(ondInfo);
            }
        }
    }
    objFile.close();
    int count =0;
    for (int i=0;i<facesIndexs.size();i++)
    {
        int vIndex = facesIndexs[i].vertices - 1;
        if(vIndex * 3 <=vertextPoints.size() ||vIndex * 3 + 1 <=vertextPoints.size()||vIndex * 3 + 2<=vertextPoints.size() )
        {
            vPoints << vertextPoints.at(vIndex * 3);
            vPoints << vertextPoints.at(vIndex * 3 + 1);
            vPoints << vertextPoints.at(vIndex * 3 + 2);
           // qDebug()<<"vIndex"<<i<<vertextPoints.size()<<vIndex * 3;
        }
        else
        {
         //  qDebug()<<"vIndex error"<<i<<vertextPoints.size()<<vIndex * 3;
        }
    }
    vertextPoints.clear();
    texturePoints.clear();
    normalPoints.clear();
    facesIndexs.clear();

    return true;
}

 我们开始调用

testobjOpengl w;

w.show();

运行结果:


http://www.kler.cn/a/611672.html

相关文章:

  • 跨网段投屏(by quqi99)
  • STM32编写触摸按键
  • 安全工具膨胀的隐性成本及其解决方法
  • 使用string和string_view(二)——数值转换、std::string_view和非标准字符串
  • Flutter常用功能教程:新手入门指南
  • 【读论文】——基于高光谱的玉米籽粒黄曲霉侵染方法研究
  • 性能测试理论基础-性能指标及jmeter中的指标
  • 车载充气泵pcba设计方案研发
  • 学习Vue-router的使用
  • 【Python实用技巧】OS模块详解:文件与目录操作的瑞士军刀
  • ENSP学习day11
  • 探索 Vue 中的多语言切换:<lang-radio /> 组件详解!!!
  • c++面经
  • 2025年渗透测试面试题总结-某快手-安全工程师(题目+回答)
  • Spring Cloud Config 快速介绍与实例
  • 企业级风控系统设计:速卖通API数据+区块链存证防篡改方案
  • 索引定义、作用和分类
  • C++:异常的深度解析
  • 新能源动力电池测试设备深度解析:充放电设备与电池模拟器的差异及技术趋势
  • 如何快速解决django报错:cx_Oracle.DatabaseError: ORA-00942: table or view does not exist