qt5_qml_Opengl_shader 第一弹----------------------openglunderqml的简化及介绍
最近得知opengl可以通过纹理贴图来渲染yuv的数据,这就免去了yuv-rgb,这个过程在arm上还是很耗时间的,于是就接触了opengl.
写这篇文章的目的是方便初学者使用qml来调用opengl显示,而qt自带的例程过于复杂,这里将之改成了一个简单的三角形的显示。(初学opengl,有错误请大家提出)
初学opengl,感觉不是很难,但是就是封装版本太多了,下边分三个来介绍:
Glut:
用的最多,大致步骤如下
1> 初始化:glutInit(),opengl的初始化很复杂的,但是经过glut的封装就变得很简单。
2> 显示模式:glutInitDisplayMode:以rgb显示或者其他,然后用双缓冲来显示,这是opengl很好的地方,加入有两帧数据,普通的显示:读第一张到内存里-显示-读第二张到内存-显示,opengl的双缓冲显示,在显示第一针的同时读入第二针,这样就不会造成卡顿,也增加了效率。
3> 创建窗口。
4> 加载显示函数:glutDisplayFunc(&myDisplay);这个是最重要的,关于显示的东西都在一个函数里,这样代码就变得很清晰了。
5> 主循环
- #include <GL/glut.h>
- void myDisplay(void)
- {
- glClear(GL_COLOR_BUFFER_BIT);
- glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
- glFlush();
- }
- int main(int argc, char *argv[])
- {
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
- glutInitWindowPosition(100, 100);
- glutInitWindowSize(400, 400);
- glutCreateWindow("第一个OpenGL程序");
- glutDisplayFunc(&myDisplay);
- glutMainLoop();
- return 0;
关于glut的描述,有兴趣的同学可以移步:
http://www.cnblogs.com/crazyxiaom/articles/2073586.html,讲的很详细。
另外在qt里边也可以调用glut。
Glwidget
Qt有自己对opengl的封装,在qt5之后叫QOpenGLFunctions,在qt中用opengl最多的是GLwidget,主要通过三个函数实现:
voidinitializeGL();--初始化
void paintGL(); --显示
void resizeGL(int width, int height );--自动缩放
详细介绍请参考nehe的opengl:http://www.yakergong.net/nehe/
结合网上的例子,我自己用最新的glwidget,实现了简单的三角形的绘制,会在最后附上代码,这里就不多讲了。
Scene Graph - OpenGL Under QML
因为本人酷爱qml,所以决定将现实的东西以qml插件的形式来显示。
有两个可以参考:分别是qt自带的例子:SceneGraph - OpenGL Under QML,还有彩阳大神的例子:http://blog.csdn.net/gamesdev/article/details/38024327
我主要参考了qt自带的例子,在其基础上结合qt帮助文档中的QOpenGLShaderProgram Class中的几段代码,略微懂了一些shader的知识,然后实现了用qml来显示简单的三角形。
首先需要定义两个类,一个供显示,另一个提供逻辑和线程的相应(个人认为是因为显示的类要调用gpu来处理),
classSquircleRenderer:publicQObject:供显示的类
classSquircle:publicQQuickItem:提供逻辑的类
然后主要的信号都是由qquickwindow.h等提供,
win,SIGNAL(beforeSynchronizing()———This signal is emittedbefore the scene graph is synchronized with the QML state.:
此信号与qml的状态同步,个人理解当qml中的参数改变或者窗口大小改变等状态改变都会触发这个信号。
win,SIGNAL(sceneGraphInvalidated()———This signal is emittedwhen the scene graph has been invalidated.
这个信号在scene grarh失效的时候触发
window(),SIGNAL(beforeRendering()———This signal is emittedbefore the scene starts rendering.
这个信号在scren graph渲染之前触发,在改变窗口大小的时候也会触发
然后我们来介绍几个槽函数:
- void Squircle::sync()
- {
- if (!m_renderer) {
- m_renderer = new SquircleRenderer();
- connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection);
- }
- m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
- }
比较多哈,其实前一部分只用了一次,如果没有实例化显示的类SquircleRenderer,则实例化一个,然后将paint()函数绑定信号:beforeRendering
后一部分很简单,调用显示类的setViewportSize函数:
voidsetViewportSize(constQSize&size)
{
m_viewportSize=size;
}
这个函数的作用就是将当前的窗口尺寸给m_viewportSize,而m_viewportSize就是opengl函数glViewport,所用到的长和宽,这个函数知道opengl的都明白的。
好,下一个槽函数:
- void Squircle::cleanup()
- {
- if (m_renderer) {
- delete m_renderer;
- m_renderer = 0;
- }
- }
这个函数,很简单,就是清除画面,什么时候执行呢:看这个:
connect(win,SIGNAL(sceneGraphInvalidated()),this,SLOT(cleanup()),Qt::DirectConnection);
sceneGraphInvalidated:这个信号在scene grarh失效的时候触发,意思就是你关闭了窗口了,scene grarh失效,然后画面清除。
下边是最重要的槽函数了:paint函数:(此函数连接了beforerendering信号,这个信号在改变窗口大小的时候触发,这样就可以保证在改变窗口是重新调用paint函数来重绘)
- void SquircleRenderer::paint()
- {
- if (!m_program) {
- m_program = new QOpenGLShaderProgram();
- m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
- "attribute highp vec4 vertices;"
- "varying highp vec2 coords;"
- "void main() {"
- " gl_Position = vertices;"
- " coords = vertices.xy;"
- "}");
- m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
- "uniform mediump vec4 color;\n"
- "void main(void)\n"
- "{\n"
- " gl_FragColor = color;\n"
- "}");
- m_program->bindAttributeLocation("vertices", 0);
- m_program->link();
- }
- m_program->bind();
- {
- m_program->enableAttributeArray(0);
- float values[] = {
- -1, -1,
- 1, -1,
- -1, 1,
- 1, 1
- };
- m_program->setAttributeArray(0, GL_FLOAT, values, 2);
- int colorLocation = m_program->uniformLocation("color");
- QColor color(255, 0, 0, 100);
- m_program->setUniformValue(colorLocation, color);
- glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
- glDisable(GL_DEPTH_TEST);
- glDrawArrays(GL_TRIANGLES, 0, 3);
- m_program->disableAttributeArray(0);
- }
- m_program->release();
- }
这些我也有很多不懂,先实例化一个QOpenGLShaderProgram:m_program,然后将shader的代码绑定,第一段Vertex与位置相关,第二段Fragment与颜色相关,由于我们要将显示做到qml插件上,所以,直接套用了qt例程中的代码,其中我搞懂的是
floatvalues[]={
-1,-1,
1,-1,
-1,1,
1,1
};
m_program->setAttributeArray(0,GL_FLOAT,values,2);
这个values[],表示渲染的对象在viewport的位置,如下图
按照这个设置,就是以viewport的大小和位置为渲染对象的大小和位置;
但是如果是
floatvalues[]={
1,0,
0,0,
0,1,
1,1
};
则表示,画在viewport的右上角,如图
而且点的顺序的不同,形状也不同,类似于纹理贴图,将对象的点与viewport的点进行映射。
然后是颜色:
intcolorLocation=m_program->uniformLocation("color");
QColorcolor(255,0,0,100);
m_program->setUniformValue(colorLocation,color);
这里将colorLocation指向shader着色器中的color变量,
uniformmediumpvec4color;
gl_FragColor=color;
然后定义一个qcolor,通过setUniformValue函数将定义的qcolor变量给colorLocation变量(这个变量传递真是恶心,但是必须这样)
然后glViewport(0,0,m_viewportSize.width(),m_viewportSize.height());
设置viewport。
最后glDisable(GL_DEPTH_TEST);这个很重要,不这个在改变窗口大小的时候三角形会闪烁消失。
主要的就介绍到这里了。下边通过qt消息相应将流程说明一下:
1> 初始化Squircle类:
SIGNAL(windowChanged(QQuickWindow*)àSLOT(handleWindowChanged(QQuickWindow*):
handleWindowChanged函数用于绑定信号:
connect(win,SIGNAL(beforeSynchronizing()),this,SLOT(sync()),Qt::DirectConnection);
connect(win,SIGNAL(sceneGraphInvalidated()),this,SLOT(cleanup()),Qt::DirectConnection);
2> qml状态改变-触发SIGNAL(beforeSynchronizing()-调用槽函数sync()绑定 connect(window(),SIGNAL(beforeRendering()),m_renderer,SLOT(paint()),Qt::DirectConnection);
3> 要渲染时候触发beforeRendering信号,调用paint函数来画
4> 在改变窗口大小时,qml状态改变,触发SIGNAL(beforeSynchronizing(),调用sync()函数,设置viewport的size,(我认为只要viewport的大小改变了,就会自动调用paint函数来重绘,这里确实没有update函数。)
代码地址:http://download.csdn.net/detail/u010423298/8699493
http://blog.csdn.net/u010423298/article/details/44889523
qt5_qml_Opengl_shader 第一弹----------------------openglunderqml的简化及介绍的更多相关文章
- Spring Boot 第一弹,问候一下世界!!!
持续原创输出,点击上方蓝字关注我吧 目录 前言 什么是Spring Boot? 如何搭建一个Spring Boot项目? 第一个程序 Hello World 依赖解读 什么是配置文件? 什么是启动类? ...
- typecho流程原理和插件机制浅析(第一弹)
typecho流程原理和插件机制浅析(第一弹) 兜兜 393 2014年03月28日 发布 推荐 5 推荐 收藏 24 收藏,3.5k 浏览 虽然新版本0.9在多次跳票后终于发布了,在漫长的等待里始终 ...
- 我的长大app开发教程第一弹:Fragment布局
在接下来的一段时间里我会发布一个相对连续的Android教程,这个教程会讲述我是如何从零开始开发“我的长大”这个Android应用. 在开始之前,我先来介绍一下“我的长大”:这是一个校园社交app,准 ...
- 关于『进击的Markdown』:第一弹
关于『进击的Markdown』:第一弹 建议缩放90%食用 比起隐蔽物下的狙击手,Markdown更像冲锋陷阵的阵头兵 简单.粗暴.直接.而且好上手 各位晚上好! 早饭吃了吗您 我 今 天 没 吃 M ...
- 关于『Markdown』:第一弹
关于『Markdown』:第一弹 建议缩放90%食用 声明: 在我之前已有数位大佬发布 "Markdown" 的语法知识点, 在此, 仅整理归类以及补缺, 方便阅读. 感谢 C20 ...
- Hadoop基础-MapReduce的工作原理第一弹
Hadoop基础-MapReduce的工作原理第一弹 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在本篇博客中,我们将深入学习Hadoop中的MapReduce工作机制,这些知识 ...
- Java基础-程序流程控制第一弹(分支结构/选择结构)
Java基础-程序流程控制第一弹(分支结构/选择结构) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.if语句 1>.if语句的第一种格式 if(条件表达式){ 语句体: ...
- RMQ_第一弹_Sparse Table
title: RMQ_第一弹_Sparse Table date: 2018-09-21 21:33:45 tags: acm RMQ ST dp 数据结构 算法 categories: ACM 概述 ...
- CentOS6安装各种大数据软件 第一章:各个软件版本介绍
相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...
随机推荐
- 如何使用autotools生成Makefile
安装autotools工具sudo apt-get install autoconf 一,四个代码文件init.s lcd.c addr.h uart.c 二,命令:autoscan 三,命令:vi ...
- (C#)Windows Shell 外壳编程系列6 - 执行
原文(C#)Windows Shell 外壳编程系列6 - 执行 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列5 - ...
- Ubuntu离线安装软件包
一.应用场景 a.当我们需要在多台电脑安装同一个软件,并且这个软件很大,下载需要很长时间时 b.需要安装软件的ubuntu不能上网 二.离线安装包的制作 2.1.通过如下指令下载XXXX软件所需要的d ...
- Sumsets(完全背包)
Sumsets Time Limit: 2000MS Memory Limit: 200000K Total Submissions: 15045 Accepted: 5997 Descrip ...
- 光学基础知识:白光、颜色混合、RGB、色彩空间
1665年,牛顿(Isaac Newton)进行了太阳光实验,让太阳光通过窗板的小圆孔照射在玻璃三角棱镜上,光束在棱镜中折射后,扩散为一个连续的彩虹颜色带,牛顿称之为光谱,表示连续的可见光谱.而可见光 ...
- 基于表单的身份验证(FBA)
https://technet.microsoft.com/zh-cn/library/ee806890(office.15).aspx http://www.tuicool.com/articles ...
- Spring源码地址和相关介绍的网址
Spring源码地址下载: https://github.com/spring-projects/spring-framework/tags >多图详解Spring框架的设计理念与设计模式:ht ...
- linux cmd: netstat
每天一个linux命令:netstat http://www.cnblogs.com/peida/archive/2013/03/08/2949194.html netstat命令用于显示与IP.T ...
- C# 常用参数
主函数调用 public static void Fun_Param() { ; ; ChangeValue(x, y); //外部调用Ref函数,必须初始化变量 ChangeValue(ref x, ...
- MyEclipse中spring MVC的配置
---恢复内容开始--- web.xml配置: <?xml version="1.0" encoding="UTF-8"?> <web-app ...