基于Qt和GLSL的着色器例子

来源:互联网 发布:金字塔量化交易软件 编辑:程序博客网 时间:2024/06/05 14:46

基于Qt和GLSL的着色器例子

         我的计算机换成新的了,可以支持OpenGL2.0以及以上的规范,这样我开始正式涉足OpenGL高级的内容了。目前我的OpenGL基础库是Qt,它有完备的功能,以及对OpenGL一层好的封装,所以用它来开发基于OpenGL的应用程序非常合适。下面是我就来介绍一下如何开发基于Qt和GLSL的程序。

         GLSL是在OpenGL2.0时开始引入的一种语言,它可以让开发者定制自己的着色方式,而不是像原来一样走固定渲染管线。我们知道如果要达到一些色彩的渲染效果,需要一大堆以gl开头的函数,如glLightfv()、glMaterialfv()、glFogv()等等,而使用GLSL,则可以很简单地使用OpenGL的着色语言来达到上述函数的效果,有时候使用上述函数无法达到的效果,GLSL都可以做到。使用GLSL还有一个好处就是如果需要在运行时改变渲染效果,那么使用GLSL是非常方便的,而OpenGL2.0以前的那些函数可能因为需要调换次序等原因无法做到这样的效果。综上所述,GLSL对于开发现代应用程序还是非常有用的。

演示程序下载地址:这里

源代码下载地址:这里

         那么该如何制作一个简单的基于Qt和GLSL的程序呢?首先从我们熟悉的GLWidget开始。

class GLWidget: public QGLWidget,        protected QOpenGLFunctions{    Q_OBJECTpublic:    GLWidget( QWidget* pParent = 0 );    void initializeGL( void );    void resizeGL( int width, int height );    void paintGL( void );public slots:    void CompileAndLinkVertexShader( const QString& shaderText );    void CompileAndLinkFragmentShader( const QString& shaderText );protected:    void mousePressEvent( QMouseEvent* pEvent );    void mouseReleaseEvent( QMouseEvent* pEvent );    void mouseMoveEvent( QMouseEvent* pEvent );    void wheelEvent( QWheelEvent* pEvent );private:    void CubeVertices( GLfloat length );    void CubeColors( void );    void SetupShaders( void );    // 摄像机    Camera          m_Camera;    // 鼠标事件需要    QPoint          m_LastPos;    // 顶点缓存和颜色缓存    GLuint          m_VertexBuffer, m_ColorBuffer;    // 着色器    QOpenGLShader               *m_pVertexShader, *m_pFragmentShader;    // 着色器程序    QOpenGLShaderProgram        m_ShaderProgram;    // 维持宽高比的参数    qreal           m_AspectRatio;};

         为了保证OpenGL函数调用的正确性,我们需要让我们的GLWidget继承于QOpenGLFunctions,QOpenGLFunctions类的作用是用来提供有保证的OpenGL/ES2.0函数,通常使用OpenGL函数的类需要继承它。随后我们定义了两个着色器类(QOpenGLShader类)的指针m_pVertexShader和m_pFragmentShader。之所以定义为指针是有原因的,上面一篇文章讲述了这些原因。QOpenGLShaderProgram类可以为对象也可以为指针,这依大家的喜好而定。

         随后是GLWidget类的实现,这里我截取了重要的SetupShaders()函数来给大家分享。

void GLWidget::SetupShaders( void ){    m_pVertexShader = new QOpenGLShader( QOpenGLShader::Vertex,                                         &m_ShaderProgram );    CHECK( m_pVertexShader->compileSourceCode( g_VertexShaderText ),           m_pVertexShader->log( ) );    m_pFragmentShader = new QOpenGLShader( QOpenGLShader::Fragment,                                           &m_ShaderProgram );    CHECK( m_pFragmentShader->compileSourceCode( g_FragmentShaderText ),           m_pFragmentShader->log( ) );    CHECK( m_ShaderProgram.addShader( m_pVertexShader ),           m_ShaderProgram.log( ) );    CHECK( m_ShaderProgram.addShader( m_pFragmentShader ),           m_ShaderProgram.log( ) );    CHECK( m_ShaderProgram.link( ),           m_ShaderProgram.log( ) );    m_ShaderProgram.bind( );}

         如代码所示,CHECK()宏是用来检测是否出错的。这段代码,简单地说其实需要五步。首先要通过new运算符在内存中创建空间,然后调用QOpenGLShader::compileSourceCode()函数来将源代码编译成二进制格式,再使用QOpenGLShaderProgram::addShader()函数来装入shader对象,第四步是使用QOpenGLShaderProgram::link()函数来进行链接,最后一步则是将使用QOpenGLShaderProgram::bind()函数将着色器程序绑定至当前的context()中。这样的话就可以在屏幕上呈现着色的效果了。

         我制作的这个小例子还带了一个着色器编辑器,像这样:


支持即时编译链接着色器,支持在GLSL规定的语法高亮,有关语法高亮的内容,感兴趣的同学可以下载一下。

最后,如果大家有好的意见和建议,可以通过程序的反馈功能将自己想说的联系我,我会及时回复的。

演示程序下载地址:这里

源代码下载地址:这里