zoukankan      html  css  js  c++  java
  • 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>     主循环

    [cpp] view plaincopy
     
    1. #include <GL/glut.h>  
    2. void myDisplay(void)  
    3. {  
    4.      glClear(GL_COLOR_BUFFER_BIT);  
    5.      glRectf(-0.5f, -0.5f, 0.5f, 0.5f);  
    6.      glFlush();  
    7. }  
    8. int main(int argc, char *argv[])  
    9. {  
    10.      glutInit(&argc, argv);  
    11.      glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);  
    12.      glutInitWindowPosition(100, 100);  
    13.      glutInitWindowSize(400, 400);  
    14.      glutCreateWindow("第一个OpenGL程序");  
    15.      glutDisplayFunc(&myDisplay);  
    16.      glutMainLoop();  
    17.      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渲染之前触发,在改变窗口大小的时候也会触发

    然后我们来介绍几个槽函数:

    [cpp] view plaincopy
     
    1. void Squircle::sync()  
    2. {  
    3.     if (!m_renderer) {  
    4.         m_renderer = new SquircleRenderer();  
    5.         connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection);  
    6.     }  
    7.     m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());  
    8. }  

    比较多哈,其实前一部分只用了一次,如果没有实例化显示的类SquircleRenderer,则实例化一个,然后将paint()函数绑定信号:beforeRendering

    后一部分很简单,调用显示类的setViewportSize函数:

    voidsetViewportSize(constQSize&size)

     {

     m_viewportSize=size;

    }

    这个函数的作用就是将当前的窗口尺寸给m_viewportSize,而m_viewportSize就是opengl函数glViewport,所用到的长和宽,这个函数知道opengl的都明白的。

    好,下一个槽函数:

    [cpp] view plaincopy
     
    1. void Squircle::cleanup()  
    2. {  
    3.     if (m_renderer) {  
    4.         delete m_renderer;  
    5.         m_renderer = 0;  
    6.     }  
    7. }  

    这个函数,很简单,就是清除画面,什么时候执行呢:看这个:

            connect(win,SIGNAL(sceneGraphInvalidated()),this,SLOT(cleanup()),Qt::DirectConnection);

    sceneGraphInvalidated:这个信号在scene grarh失效的时候触发,意思就是你关闭了窗口了,scene grarh失效,然后画面清除。

     
     

    下边是最重要的槽函数了:paint函数:(此函数连接了beforerendering信号,这个信号在改变窗口大小的时候触发,这样就可以保证在改变窗口是重新调用paint函数来重绘)

    [cpp] view plaincopy
     
    1. void SquircleRenderer::paint()  
    2. {  
    3.     if (!m_program) {  
    4.         m_program = new QOpenGLShaderProgram();  
    5.   
    6.         m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,  
    7.                                            "attribute highp vec4 vertices;"  
    8.                                            "varying highp vec2 coords;"  
    9.                                            "void main() {"  
    10.                                            "    gl_Position = vertices;"  
    11.                                            "    coords = vertices.xy;"  
    12.                                            "}");  
    13.         m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,  
    14.                                            "uniform mediump vec4 color; "  
    15.                                            "void main(void) "  
    16.                                            "{ "  
    17.                                            "   gl_FragColor = color; "  
    18.                                            "}");  
    19.         m_program->bindAttributeLocation("vertices", 0);  
    20.         m_program->link();  
    21.     }  
    22.     m_program->bind();  
    23.     {  
    24.   
    25.         m_program->enableAttributeArray(0);  
    26.   
    27.         float values[] = {  
    28.             -1, -1,  
    29.             1, -1,  
    30.             -1, 1,  
    31.             1, 1  
    32.         };  
    33.         m_program->setAttributeArray(0, GL_FLOAT, values, 2);  
    34.   
    35.         int colorLocation = m_program->uniformLocation("color");  
    36.         QColor color(255, 0, 0, 100);  
    37.         m_program->setUniformValue(colorLocation, color);  
    38.   
    39.         glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());  
    40.         glDisable(GL_DEPTH_TEST);  
    41.         glDrawArrays(GL_TRIANGLES, 0, 3);  
    42.   
    43.         m_program->disableAttributeArray(0);  
    44.     }  
    45.     m_program->release();  
    46. }  
    这些我也有很多不懂,先实例化一个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

  • 相关阅读:
    [USACO5.1]二维凸包模板
    HTML 5 Web 存储
    计算两个坐标点的距离(高德or百度)
    Cache的一些总结
    PowerDesigner最基础的使用方法
    MongoDB安装
    MangoDB CSharp Driver
    Linq语法详细
    where用法
    .Net下二进制形式的文件存储与读取
  • 原文地址:https://www.cnblogs.com/findumars/p/5125226.html
Copyright © 2011-2022 走看看