驾校回来几天了,继续干openGL,之前有一个帖子是立方体六个面不同纹理的。
这次使用vs+Qt一块写的,Qt里直接配置opencv打不开视频文件,被逼无奈,只能vs里用qt tools,然后在我们设计ui时候,如果vs里直接打开会卡死,直接在文件夹里打开ui,至于qrc源文件,这就多点耐心,卡死了慢慢来就行。
这次播放是播放个立方体视频,每个面不同视频。其实核心就是opencv+openGL,调用一个时间槽函数,每隔一段时间比如20ms去调用on_timeout()函数,然后函数里用openCV获取视频每一帧,然后转化成Qimage,再调用update()函数,openGL去渲染成为纹理。有个很要命的问题,就是当时显示了d->textureId报错,然后想了挺多方法,最后是把获取的帧的总数减掉一个值(到现在也没太懂,可能是有些帧没办法变成图片,还是帧转化为Qiamge中间有些问题?望懂得小伙伴给我讲讲)。
opencv配置啥的,b站搜一下,很详细,不多说了,画立方体播放不同视频,其实是画立方体每个面不同纹理的进阶版,不懂得可以看我之前写的帖子。
超详细讲解。QT+OpenGL画出不同纹理面立方体(部分面可反色)_硏的博客-CSDN博客
这是axbopenglwidget.cpp
#include "axbopenglwidget.h"
#include
#include
#include
#include "opencv2/imgproc/types_c.h"
#include "mainwindow.h"
#include
using namespace cv;
int count = 0;
unsigned int VBO, VAO, EBO;
unsigned int VBO1, VAO1, EBO1;
//VideoCapture capture;
int flag = 0;
int countt = 0;
int count1 = 0;
VideoCapture capture[6];
Mat frame[6], dst, Myvideo;
GLuint myTex;
int totalnumber[6];
float vertices[] = {
-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, 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, 1.0f, 0.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, 1.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, 0.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, 1.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, 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,
};
QVector cubePositions = {
QVector3D(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)*/
};
float vertices1[] = {
-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
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
float ratio = 0.5;
AXBOpenGLWidget::AXBOpenGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
//初始化中将totalnumber,currentnumber,flag都设置为0
//当currentnumber==totalnumber-15,15是自己试验的一个数,直接写两者等于会报错,flag[i]设置为1,这时候这个视频所有画面播放结束
for (int i = 0; i < 6; i++)
{
totalnumber[i] = 0;
currentnumber[i] = 0;
flag[i] = 0;
}
// 调用时间槽函数,on_timeout()中调用opencv获取帧
setFocusPolicy(Qt::StrongFocus);
connect(&timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
timer.start(10);
}
//析构函数,删除VAO VBO
AXBOpenGLWidget::~AXBOpenGLWidget()
{
makeCurrent();
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO);
doneCurrent();
}
//帧转化为Qimage,网上找到的,也不知道对不对(opencv还没开始学)
QImage Mat2QImage(cv::Mat& image)
{
QImage img;
if (image.channels() == 3) {
cvtColor(image, image, CV_BGR2RGB);
img = QImage((const unsigned char*)(image.data), image.cols, image.rows,
image.cols * image.channels(), QImage::Format_RGB888);
}
else if (image.channels() == 1) {
img = QImage((const unsigned char*)(image.data), image.cols, image.rows,
image.cols * image.channels(), QImage::Format_ARGB32);
}
else {
img = QImage((const unsigned char*)(image.data), image.cols, image.rows,
image.cols * image.channels(), QImage::Format_RGB888);
}
return img;
}
void AXBOpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
bool success;
for (int i = 0; i < 6; i++)
{
shaderProgram[i].addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes_1.vert");
shaderProgram[i].addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes_1.frag");
success = shaderProgram[i].link();
if (!success)
qDebug() << "ERR:" << shaderProgram[i].log();
}
for (int i = 0; i < 6; i++)
{
textureSmall[i]= new QOpenGLTexture(QImage(":/images/wall.jpg").mirrored());
shaderProgram[i].bind();
shaderProgram[i].setUniformValue("textureSmall", 0);
}
//初始化流程,VAO,VBO的创建以及绑定,还有指针告诉其怎么运作
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
QMatrix4x4 projection;
projection.perspective(45, (float)width() / height(), 0.1, 100);
//给定projection。这一部分直接参考立方体画六个面的纹理,上个帖子就是
for (int i = 0; i < 6; i++) {
shaderProgram[i].bind();
shaderProgram[i].setUniformValue("textureSmall", 0);
shaderProgram[i].setUniformValue("projection", projection);
}
glBindVertexArray(0);
}
void AXBOpenGLWidget::resizeGL(int w, int h)
{
Q_UNUSED(w);Q_UNUSED(h);
//glViewport(0, 0, w, h);
}
void AXBOpenGLWidget::paintGL()
{
//interval就是每次绘画时候的范围
int interval = 0;
QMatrix4x4 model;
QMatrix4x4 view;
unsigned int time = QTime::currentTime().msec();
view.translate(0.0, 0.0, -3);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//给定view和model。这一部分直接参考立方体画六个面的纹理,上个帖子就是
model.setToIdentity();
model.translate(cubePositions[0]);
model.rotate(45, 1.0f, 1.0f, 1.0f);
for (int i = 0; i < 6; i++) {
shaderProgram[i].bind();
shaderProgram[i].setUniformValue("ratio", ratio);
shaderProgram[i].setUniformValue("view", view);
shaderProgram[i].setUniformValue("model", model);
}
glBindVertexArray(VAO);
//每次绑定shaderprogram,然后画图,这样子就一次性把六个面渲染完了,然后下次调用paintGL,interval重新回到0,再次画新的帧。缺点是单线程真的很慢
for (int i = 0; i < 6; i++) {
shaderProgram[i].bind();
textureSmall[i]->bind(0);
glDrawArrays(GL_TRIANGLES, interval,interval+6);
interval = interval + 6;
}
}
void AXBOpenGLWidget::on_timeout() {
//六个面,每个面都是获取帧,然后一帧一帧播放
for (int i = 0; i < 6; i++)
{
if (flag[i] == 0)
{
capture[i] >> frame[i];
if (currentnumber[i] % 1 == 0)
{
//这里减去15可以保证视频播放结束不崩
if (currentnumber[i] == totalnumber[i] - 15)
{
flag[i] = 1;
}
else
{
//frame转化为Qimage,然后分别绑定shaderprogram和着色器程序里的值
QImage img = Mat2QImage(frame[i]);
shaderProgram[i].bind();
shaderProgram[i].setUniformValue("textureSmall", 0);
//opengl纹理是倒过来的,所以用个mirrored,让其方向正过来
textureSmall[i] = new QOpenGLTexture(img.mirrored());
}
//每次渲染完一幅图片,就++
currentnumber[i]++;
}
//转到paintGL函数喽
update();
}
}
}
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
MainWindow w;
//读取六个视频,分别放到立方体六个面
capture[0].open("a.avi");
capture[1].open("b.avi");
capture[2].open("c.avi");
capture[3].open("d.avi");
capture[4].open("e.avi");
capture[5].open("yi.avi");
for (int i = 0; i < 6; i++)
{
//打开视频并且获得每个视频总帧数
if (!capture[i].isOpened())
std::cout << "could not load video data" << endl;
//新版本中是CAP_PROP_FRAME_COUNT
totalnumber[i] = capture[i].get(CAP_PROP_FRAME_COUNT);
}
//显示窗口,这时候就到了构造函数中调用时间槽函数
w.show();
return a.exec();
}
然后这是对应的头文件
#ifndef AXBOPENGLWIDGET_H
#define AXBOPENGLWIDGET_H
#include
#include
#include
#include
#include
#include
#include
#include "opencv2/imgproc/types_c.h"
class AXBOpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
enum Shape { None, Rect, Circle, Triangle };
explicit AXBOpenGLWidget(QWidget* parent = nullptr);
~AXBOpenGLWidget();
void drawShape(Shape shape);
void setWirefame(bool wireframe);
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
signals:
public slots:
void on_timeout();
private:
Shape m_shape;
QWidget* w1;
QOpenGLShaderProgram shaderProgram[6];
QOpenGLTexture* textureSmall[6];
int currentnumber[6];
int flag[6];
QTimer timer;
};
#endif // AXBOPENGLWIDGET_H
#version 330 core
out vec4 FragColor;
out vec4 Color;
in vec2 TexCord;
uniform sampler2D textureSmall;
void main(){
Color=texture(textureSmall,TexCord);
}
shapes_1.frag
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCord;
out vec2 TexCord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(){
gl_Position = projection*view*model*vec4(aPos.x, aPos.y, aPos.z, 1.0f);
TexCord=aTexCord;
}
shapes_1.vert
其他mainwindow什么的按原来的就OK,不需要多改