14. QT_OPenGL中引入顶点着色器和片段着色器
创始人
2024-05-26 04:29:26
0

1. 说明:

着色器是OPenGL中非常重要的一部分,在有了模型后,如果未给模型添加着色器,那么渲染效果会折扣很多。着色器中使用到的语言是GLSL(OPenGL Shader Language),可以通过这篇文章GLSL基本语法进行了解。
效果展示:(绘制出一个橙色的矩形)

使用着色器绘制橙色矩形

2. 着色器引入

第一步:
需要用到Qt自带的Shader封装函数,在myopenglwidget.h添加对应头文件并创建一个私有变量 shaderProgram,代码如下:

#include 
private:QOpenGLShaderProgram shaderProgram;

第二步:
添加两个资源文件,顶点着色器文件shape.vert,片段着色器文件shape.frag,文件的后缀显示了是什么文件,里面的代码如下:
shape.vert:

#version 330 corelayout(location = 0) in vec3 aPos;	//in修饰,说明这个变量是需要外界代码传入进来的参数void main()
{gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0f);	//gl_Position 是内置变量
}

shape.frag:

#version 330 coreout vec4 FragColor;//out修饰,表名这个变量是需要传输出去的void main()
{FragColor = vec4(1.0f,0.5f,0.2f,1.0f);//这里使用内置变量 gl_FragColor 进行传输也是一样的
}

第三步:
在myopenglwidget.cpp文件的initializeGL()函数中对上述着色器文件进行使用:

//添加着色器
shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/Shaders/shape.vert");//注意:此处的路径最好用相对路径,绝对路径可能会打不开文件
shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/Shaders/shape.frag");
shaderProgram.link();	//将两个着色器文件连接到一起

然后在paintGL()函数中对着色器进行绑定即可:

shaderProgram.bind();	//渲染前绑定着色器

整体代码如下:
myopenglwidget.h:

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H#include 
#include #include 
#include 
#include class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{Q_OBJECT
public:enum Shape{None,Rect,Circle,Triangle};explicit MyOpenGLWidget(QWidget *parent = nullptr);void drawShape(Shape shape);void clearGraphic();void setWireFrame(bool wireFrame);protected:virtual void initializeGL() override;virtual void resizeGL(int w, int h) override;virtual void paintGL() override;signals:private:Shape m_shape;QOpenGLShaderProgram shaderProgram;
};#endif // MYOPENGLWIDGET_H

myopenglwidget.cpp:

#include "myopenglwidget.h"unsigned int VBO,VAO;//添加一个索引控制器
unsigned int EBO;//使用4个顶点数据绘制两个三角形
float vertices2[] = {0.5f,0.5f,0.0f,0.5f,-0.5f,0.0f,-0.5f,-0.5f,0.0f,-0.5f,0.5f,0.0f
};//添加索引数据
unsigned int indices[]={0,1,3,1,2,3
};MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) :  QOpenGLWidget(parent)
{}void MyOpenGLWidget::drawShape(MyOpenGLWidget::Shape shape)
{makeCurrent();m_shape = shape;update();doneCurrent();
}void MyOpenGLWidget::clearGraphic()
{makeCurrent();drawShape(MyOpenGLWidget::None);makeCurrent();glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);update();doneCurrent();
}void MyOpenGLWidget::setWireFrame(bool wireFrame)
{makeCurrent();if(wireFrame){glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);}else{glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);}update();doneCurrent();
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();//void glGenVertexArrays(GLsizei n, GLuint *arrays)生成顶点数组对象名称// n: 要产生的VAO对象的数量// arrays: 存放产生的VAO对象的名称glGenVertexArrays(1,&VAO);// void glGenBuffers(GLsizei n,GLuint *buffers)生成顶点缓冲对象// n: 要产生的VBO对象的数量// arrays: 存放产生的VBO对象的名称glGenBuffers(1,&VBO);//初始化索引器glGenBuffers(1,&EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof (indices),indices,GL_STATIC_DRAW);//绑定VAO和VBOglBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//在VBO中存入顶点数据glBufferData(GL_ARRAY_BUFFER,sizeof (vertices2),vertices2,GL_STATIC_DRAW);//告诉VAO怎么在VBO中拿数据glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof (float),(void*)0);//开启第一个VAOglEnableVertexAttribArray(0);//用完之后解除绑定(信息已经被记录下来了)glBindBuffer(GL_ARRAY_BUFFER,0);glBindVertexArray(0);//添加着色器shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/Shaders/shape.vert");shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/Shaders/shape.frag");shaderProgram.link();}void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);}void MyOpenGLWidget::paintGL()
{glClearColor(0.5f,0.9f,0.4f,1.0f);glClear(GL_COLOR_BUFFER_BIT);shaderProgram.bind();  //绑定着色器//在渲染前只需开启对应的VAO即可glBindVertexArray(VAO);switch (m_shape) {case Rect:glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,&indices);break;default:break;}}

持续更新中,请大家多多关注…

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...