QT中的OpenGL学习-----3D图形

embedded/2024/9/22 15:20:35/

一、3D坐标系

记住V_clip = M_projection * M_view * M_model * V_local就行,可以在顶点着色器里面添加位置信息:

#version 330 core
layout (location = 2) in vec3 aPos;//location属性位置有16个
layout (location = 3) in vec3 aColor;
layout (location = 1) in vec2 aTextureCoordinates;
out vec3 ourColor;
out vec2 TextureCoordinates;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);ourColor = aColor;TextureCoordinates = aTextureCoordinates;
}

片段着色器不用改变:

#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TextureCoordinates;
uniform sampler2D textureWall;
uniform sampler2D textureLe;
uniform sampler2D textureSmall;
uniform sampler2D texturePJ;
uniform float ratio;
void main()
{FragColor = mix(texture(textureWall, TextureCoordinates), texture(textureLe, TextureCoordinates), ratio);
}

二、透视投影

这方面可以恶补下线性代数知识。

三、代码实现

3.1 构建一个正方体的点

        在OpenGL里面,三角形是基础图形,正方体6个面,每一个面都是两个三角形拼接而成,所以点需要2×3×6=36个顶点坐标,在坐标的数组里面可以放入颜色、纹理等信息,后面调用解析的时候注意步长和位置即可。

        在编写顶点的时候,只要能连起来是个正方体即可,不同的点做原点都可以,但是一定要连起来,纹理是2个数来表示X和Y,和顶点坐标没有关系。下面是构建的一个例子:

float vertices[] =
{//positions //texture coordinates//正面-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,//背面-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,//左面-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,//右面0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f,//上面-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,//下面-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f
};

3.2 画出正方体

注意要给M_projection * M_view * M_model这三个矩阵,写在外面也可以,但是多个3D图形的话model需要初始化,不然除了第一次的图形是单位矩阵,for循环后面的都不是。

void OpenGLWidget::paintGL()
{QMatrix4x4 model;QMatrix4x4 view;QMatrix4x4 projection;unsigned int time = QTime::currentTime().msec();//先旋转再位移,图片在固定位置旋转//先位移再旋转,图片围着一个地方转//具体参考线性代数矩阵知识
//    model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转view.translate(0.0, 0.0, -3);projection.perspective(45, (float)width()/height(), 0.1, 100);m_shaderProgram.setUniformValue("projection", projection);//red:0.0f无色,1.0f全红glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glEnable(GL_DEPTH_TEST);//加了立方体可以封面glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);m_shaderProgram.bind();//绑定可以理解为使用它m_shaderProgram.setUniformValue("ratio", ratio);glBindVertexArray(VAO);switch (m_shape){case Rect://纹理绑定textureLe->bind(1);textureWall->bind(0);//图形绘画//画之前设置3D图形//V_clip = M_projection * M_view * M_model * V_localm_shaderProgram.setUniformValue("view", view);foreach(auto item, cubePositions){model.setToIdentity();//初始化model.translate(item);//位移model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转m_shaderProgram.setUniformValue("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);}break;default:break;}
}

3.3 完整代码

#include "openglwidget.h"unsigned int VBO, VAO, EBO;
float ratio = 0.5;
float vertices[] =
{//positions //texture coordinates//正面-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,//背面-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,//左面-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,//右面0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, 0.5f, -0.5f, 0.0f, 1.0f,//上面-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,//下面-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f
};unsigned int indices[] = //note that we start from 0!
{0, 1, 3,//第一个三角形1, 2, 3 // 第二个三角形
};//多个3D图形,建立位移数组
QVector<QVector3D> cubePositions =
{//X,Y,ZQVector3D(0.0f, 0.0f, 0.0f),QVector3D(2.0f, 5.0f, -15.0f),QVector3D(-1.5f, -2.2f, -2.5f),QVector3D(-3.8f, -2.0f, -12.3f),QVector3D(2.4f, -0.4f, -3.5f),QVector3D(-1.7f, 3.0f, -7.5f),QVector3D(1.3f, -2.0f, -2.5f),QVector3D(1.5f, 2.0f, -2.5f),QVector3D(1.5f, 0.2f, -1.5f),QVector3D(-1.3f, 1.0f, -1.5f)
};OpenGLWidget::OpenGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{setFocusPolicy(Qt::StrongFocus);m_timer = new QTimer;m_timer->start(100);connect(m_timer, &QTimer::timeout, this, [=](){update();});
}OpenGLWidget::~OpenGLWidget()
{makeCurrent();glDeleteBuffers(1,&VBO);glDeleteBuffers(1, &EBO);glDeleteVertexArrays(1,&VAO);doneCurrent();
}void OpenGLWidget::drawShape(Shape shape)
{m_shape = shape;update();
}void OpenGLWidget::setWireframe(bool wireframe)
{makeCurrent();if (wireframe){glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);}else{glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);}update();doneCurrent();
}void OpenGLWidget::initializeGL()
{initializeOpenGLFunctions();//使用QT封装的着色器bool success;m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes.vert");//顶点着色器m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes.frag");//片段着色器success = m_shaderProgram.link();//连接到着色器if(!success)qDebug() << "ERR:" << m_shaderProgram.log();//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//访问着色器里面属性的位置m_shaderProgram.bind();GLint posLocation = m_shaderProgram.attributeLocation("aPos");//询问着色器里面变量aPos顶点信息的属性位置GLint textureLocation = m_shaderProgram.attributeLocation("aTextureCoordinates");//告知显卡如何解析缓冲里的顶点属性值glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);//告知显卡如何解析缓冲里的纹理属性值glVertexAttribPointer(textureLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));//开启VAO管理的顶点属性值glEnableVertexAttribArray(posLocation);//开启VAO管理的纹理属性值glEnableVertexAttribArray(textureLocation);//EBO创建与绑定glGenBuffers(1, &EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//纹理textureWall = new QOpenGLTexture(QImage(":/imags/imag/1.jpg").mirrored());textureLe = new QOpenGLTexture(QImage(":/imags/imag/2.jpg").mirrored());textureSmall = new QOpenGLTexture(QImage(":/imags/imag/3.jpg").mirrored());texturePJ = new QOpenGLTexture(QImage(":/imags/imag/4.jpg").mirrored());//设置纹理单元,纹理单元有16个m_shaderProgram.bind();m_shaderProgram.setUniformValue("textureWall", 0);m_shaderProgram.setUniformValue("textureLe", 1);m_shaderProgram.setUniformValue("textureSmall", 2);m_shaderProgram.setUniformValue("texturePJ", 3);//设置渐远纹理texturePJ->generateMipMaps();//纹理绑定textureLe->bind(1);textureWall->bind(0);//VAO和VBO绑定为0,相当于释放休息glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);QMatrix4x4 projection;projection.perspective(45, (float)width()/height(), 0.1, 100);m_shaderProgram.setUniformValue("projection", projection);
}void OpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(h)Q_UNUSED(w)
}void OpenGLWidget::paintGL()
{QMatrix4x4 model;QMatrix4x4 view;unsigned int time = QTime::currentTime().msec();//先旋转再位移,图片在固定位置旋转//先位移再旋转,图片围着一个地方转//具体参考线性代数矩阵知识
//    model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转view.translate(0.0, 0.0, -3);//red:0.0f无色,1.0f全红glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glEnable(GL_DEPTH_TEST);//加了立方体可以封面glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);m_shaderProgram.bind();//绑定可以理解为使用它m_shaderProgram.setUniformValue("ratio", ratio);glBindVertexArray(VAO);switch (m_shape){case Rect://纹理绑定textureLe->bind(1);textureWall->bind(0);//图形绘画//画之前设置3D图形//V_clip = M_projection * M_view * M_model * V_localm_shaderProgram.setUniformValue("view", view);foreach(auto item, cubePositions){model.setToIdentity();//初始化model.translate(item);//位移model.rotate(time, 1.0f, 5.0f, 0.5f);//旋转m_shaderProgram.setUniformValue("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);}break;default:break;}
}void OpenGLWidget::keyPressEvent(QKeyEvent *event)
{switch (event->key()){case Qt::Key_Up:ratio += 0.1;break;case Qt::Key_Down:ratio -= 0.1;break;default:break;}if(ratio>1) ratio = 1;if(ratio<0) ratio = 0;m_shaderProgram.bind();m_shaderProgram.setUniformValue("ratio", ratio);update();
}

详细代码看压缩文件。

3.4 学习地址

5-3代码实现3D效果_哔哩哔哩_bilibili

四、效果展示

3D旋转跳跃画圈圈


http://www.ppmy.cn/embedded/13208.html

相关文章

Python 异常处理与日志记录

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 异常处理是任何编程语言中的重要组成部分&#xff0c;Python 也不例外。Python 提供了丰富的…

详解数据结构:栈

一、顺序栈 顺序栈的存储方式如下&#xff1a; 从图中可以看出&#xff0c;顺序栈需要两个指针&#xff0c;base指向栈底&#xff0c;top指向栈顶。 typedef struct SqStack {ElemType *base; //栈底指针ElemType *top; //栈顶指针}SqStack; 说明&#xff1a; ElemType是元…

数仓建模—物理数据模型

数仓建模—物理数据模型 前面我们讲了数据模型和逻辑数据模型,你可以参考前面的文章,这一节我们介绍一下物理数据模型 数仓建模—数据模型 数仓建模—逻辑数据模型 什么是物理数据模型 物理数据模型指定如何在数据库中构建数据模型。它概述了所有表结构,包括列名、数据类…

Qt 运行 Android 程序时找不到 Toou2D 库闪退

问题描述 程序闪退&#xff0c;错误信息如下&#xff0c;找不到库。 W libAndroid10_armeabi-v7a.so: QQmlApplicationEngine failed to load component W libAndroid10_armeabi-v7a.so: qrc:/main.qml:3:1: plugin cannot be loaded for module "Toou2D": Cannot …

【一些神金】怎么缓解工作压力?使用VS-code彩虹屁插件

怎么缓解工作压力&#xff1f; 其实吃点好的&#xff0c;多睡一会儿&#xff0c;再锻炼锻炼身体就好。 但我只是想炫耀一下这个彩虹屁插件。 原版插件&#xff1a;VS-code-Rainbowfart 我的版本&#xff1a;RainbowFart-Oberon 基于 MIT 开源&#xff0c;包括所有设计资源及音…

Day10 React———— 第十天

useReducer useReducer 是 React Hooks 中的一个函数&#xff0c;用于管理组件的状态。它类似于 useState&#xff0c;但提供了更复杂的状态逻辑处理能力。 接受一个 reducer 函数和初始状态作为参数&#xff0c;并返回当前状态和 dispatch 函数。 使用 useReducer 的基本流程…

【AI写作】未来科技趋势:揭秘DreamFusion的革新力量

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

Redis 数据类型

文章目录 Reidis 命名规范String类型Hash 类型List 类型Set 类型Zset 类型补充 概览&#xff1a; 数据结构 &#xff1a; key value 中value的类型 内部编码&#xff1a; 实际在底层用来存储value的结构 设计优点&#xff1a; ① 解耦&#xff0c;用户可根据需求再开发内部编…