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.pswp.cn/news/899101.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899101.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899101.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

0326-Java 字符串方法

package com.qc.字符串;import java.util.Arrays;public class Test {public static void main(String[] args) { // String x"hello";//字符串 char[] // x x"demo";//字符串拼接 // xx2450; // xxtrue; // System.out.println(x);//hellodemo2450t…

<command-line>:0:1: error: macro names must be identifiers m

報錯&#xff1a;:0:1: error: macro names must be identifiers 排查類很久 原來是&#xff1a; add_compile_definitions(_GLIBCXX_USE_CXX11_ABI$ABI_VERSION)寫成了 add_compile_definitions(-D_GLIBCXX_USE_CXX11_ABI$ABI_VERSION)多了個 -D。

風光互補智慧路燈的燈桿設計有哪些要求?

嘿&#xff0c;朋友們&#xff01;叁仟風光互補智慧路燈的燈桿設計那可是超級重要的事兒&#xff0c;得全方位綜合考量各種因素&#xff0c;就是為了確保咱們的路燈能兼具超棒的功能性、絕對的安全性、無敵的美觀性以及超厲害的耐用性&#xff01;下面就來看看這些超贊的常見要…

06、RAG

LLM的知識僅限于它所接受到的訓練數據。如果我們希望讓它了解特定領域的專有知識&#xff0c;則可以使用下面的方式操作&#xff1a; 使用RAG使用專有數據對LLM進行微調RAG與數據微調方式結合使用 什么是RAG 簡單地說&#xff0c;RAG就是把數據發送給LLM之前從數據中查找相關…

自然語言處理:第一百零二章 如何去掉DeepSeek R1思考過程

本人項目地址大全&#xff1a;Victor94-king/NLP__ManVictor: CSDN of ManVictor 寫在前面: 筆者更新不易&#xff0c;希望走過路過點個關注和贊&#xff0c;筆芯!!! 寫在前面: 筆者更新不易&#xff0c;希望走過路過點個關注和贊&#xff0c;筆芯!!! 寫在前面: 筆者更新不易…

flink 安裝與訪問 ui

官方文檔&#xff1a;First steps | Apache Flink 版本&#xff1a;v2.0.0 下載Flink Flink運行在所有類UNIX環境中&#xff0c;即Linux&#xff0c;Mac OS X和Cygwin&#xff08;適用于Windows&#xff09;。您需要安裝Java 11。要檢查安裝的Java版本&#xff0c;請在終端中…

WPF TextBox實現鍵盤enter后實時讀取TextBox中的值

代碼 <TextBox Grid.Column"0" x:Name"textBox" Margin"10,5,0,5" TextWrapping"Wrap" Text"{Binding SendMessage,UpdateSourceTriggerPropertyChanged}" VerticalContentAlignment"Center" CaretBrush&qu…

PyTorch實現Transformer模型

首先&#xff0c;我得回顧一下Transformer的基本結構&#xff0c;確保自己沒有記錯。Transformer由編碼器和解碼器組成&#xff0c;每個編碼器層包含多頭自注意力機制和前饋網絡&#xff0c;解碼器層則還有編碼器-解碼器注意力。 接下來&#xff0c;用戶需要的是手把手的代碼解…

詳細介紹sentinel的使用,并列舉經常出的面試題以及答案

Sentinel 是一款由阿里巴巴開源的分布式系統的流量防衛系統&#xff0c;能夠實時響應并滿足高并發的流量控制需求。它提供了流量監控、流量控制、熔斷降級、系統保護等核心功能&#xff0c;可幫助開發人員實時發現系統的流量異常并快速做出相應的限流策略。 Sentinel 的使用步…

mysql-connector-java-5.1.37.jarJava連接器

mysql-connector-java-5.1.37.jar是MySQL官方提供的Java連接器&#xff0c;用于在Java應用程序中與MySQL數據庫進行通信。具體來說&#xff0c;這個JAR文件是MySQLJDBC驅動程序的一個版本&#xff0c;允許Java程序通過JDBC&#xff08;JavaDatabaseConnectivity&#xff09;接口…

Python基于Django的智能旅游推薦系統(附源碼,文檔說明)

博主介紹&#xff1a;?IT徐師兄、7年大廠程序員經歷。全網粉絲15W、csdn博客專家、掘金/華為云//InfoQ等平臺優質作者、專注于Java技術領域和畢業項目實戰? &#x1f345;文末獲取源碼聯系&#x1f345; &#x1f447;&#x1f3fb; 精彩專欄推薦訂閱&#x1f447;&#x1f3…

【博客節選】再談Unity 的 root motion

節選自 【Unity實戰筆記】第二十三 root motion變更方向攻擊 &#xff08;OnStateMove rootmotion rigidbody 使用的一些問題&#xff09; 小伙伴們應該對root motion非常困惑&#xff0c;包括那個bake into pose。 當xz bake into pose后&#xff0c;角色攻擊動畫與父節點產…

網站服務器常見的CC攻擊防御秘籍!

CC攻擊對網站的運營是非常不利的&#xff0c;因此我們必須積極防范這種攻擊&#xff0c;但有些站長在防范這種攻擊時可能會陷入誤區。讓我們先了解下CC攻擊&#xff01; CC攻擊是什么 CC是DDoS攻擊的一種&#xff0c;CC攻擊是借助代理服務器生成指向受害主機的合法請求&#x…

JAVA:Spring Boot @Conditional 注解詳解及實踐

1、簡述 在 Spring Boot 中&#xff0c;Conditional 注解用于實現 條件化 Bean 裝配&#xff0c;即根據特定的條件來決定是否加載某個 Bean。它是 Spring 框架中的一個擴展機制&#xff0c;常用于實現模塊化、可配置的組件加載。 本文將詳細介紹 Conditional 相關的注解&…

使用python爬取網絡資源

整體思路 網絡資源爬取通常分為以下幾個步驟&#xff1a; 發送 HTTP 請求&#xff1a;使用requests庫向目標網站發送請求&#xff0c;獲取網頁的 HTML 內容。解析 HTML 內容&#xff1a;使用BeautifulSoup庫解析 HTML 內容&#xff0c;從中提取所需的數據。處理數據&#xff…

PostgreSQL 數據庫源碼編譯安裝全流程詳解 Linux 8

PostgreSQL 數據庫源碼編譯安裝全流程詳解 Linux 8 1. 基礎環境配置1.1 修改主機名1.2 配置操作系統yum源1.3 安裝操作系統依賴包1.4 禁用SELINUX配置1.5 關閉操作系統防火墻1.6 創建用戶和組1.7 建立安裝目錄1.8 編輯環境變量 2. 源碼方式安裝&#xff08;PG 16&#xff09;2.…

(基本常識)C++中const與引用——面試常問

作者&#xff1a;求一個demo 版權聲明&#xff1a;著作權歸作者所有&#xff0c;商業轉載請聯系作者獲得授權&#xff0c;非商業轉載請注明出處 內容通俗易懂&#xff0c;沒有廢話&#xff0c;文章最后是面試常問內容&#xff08;建議通過標題目錄學習&#xff09; 廢話不多…

Java并發編程 什么是分布式鎖 跟其他的鎖有什么區別 底層原理 實戰講解

目錄 一、分布式鎖的定義與核心作用 二、分布式鎖與普通鎖的核心區別 三、分布式鎖的底層原理與實現方式 1. 核心實現原理 2. 主流實現方案對比 3. 關鍵技術細節 四、典型問題與解決方案 五、總結 六、具體代碼實現 一、分布式鎖的定義與核心作用 分布式鎖是一種在分布…

案例:使用網絡命名空間模擬多主機并通過網橋訪問外部網絡

案例目標 隔離性&#xff1a;在同一臺物理機上創建兩個獨立的網絡命名空間&#xff08;模擬兩臺主機&#xff09;&#xff0c;確保其網絡配置完全隔離。內部通信&#xff1a;允許兩個命名空間通過虛擬設備直接通信。外部訪問&#xff1a;通過宿主機的網橋和 NAT 規則&#xff…

AF3 Rotation 類解讀

Rotation 類(rigid_utils 模塊)是 AlphaFold3 中用于 3D旋轉 的核心組件,支持兩種旋轉表示: 1?? 旋轉矩陣 (3x3) 2?? 四元數 (quaternion, 4元向量) ?? 設計目標: 允許靈活選擇 旋轉矩陣 或 四元數 封裝了常用的 旋轉操作(組合、逆旋轉、應用到點上等) 像 torch.…