QML进阶(七)-OpenGL渲染着色器效果实现

通过QML的ShaderEffect和ShaderEffectSource元素,我们可以运用OpenGL的能力实现各种各样的渲染效果。着色器的渲染算法是通过OpengGL的渲染语言实现的。这意味着,我们需要实现QML代码和着色器代码的混合编程,在程序执行的时候对应的着色器程序会被发送到GPU上编译运行。QML的着色器程序允许用户与OpenGL进行实时交互,动态修改。

OpenGL着色器

OpenGL的着色器主要分为两种:顶点着色器(vertex shader)和片源着色器(FragmentShader)。顶点着色器在接收到顶点数据之后,将顶点数据信息分配给gl_Position变量。在下一阶段中,顶点模型会被分割、转化,并实现栅格化,形成一个个小三角,为下一步像素渲染做好准备。在片源着色器程序中,色值被设置到gl_FragColor变量中,并最终渲染到对应的分割块中。整个流程中,顶点着色器负责尺寸分割,片源着色器负责颜色渲染。具体流程如下图所示:

QML着色器元素

下面以一个例子说明一下QML中着色器元素的使用方法:

import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    Rectangle {
        width: 480; height: 240
        color: '#1e1e1e'

        Row {
            anchors.centerIn: parent
            spacing: 20
            //需要被主色器操作的图片
            Image {
                id: sourceImage
                width: 80; height: width
                source: 'qrc:/transform.png'
            }
            ShaderEffect {
                id: effect
                width: 80; height: width
                property variant source: sourceImage
            }
            ShaderEffect {
                id: effect2
                width: 80; height: width

                //指定输入的图片源
                property variant source: sourceImage

                //顶点着色器程序
                vertexShader: "
                    uniform highp mat4 qt_Matrix;
                    attribute highp vec4 qt_Vertex;
                    attribute highp vec2 qt_MultiTexCoord0;
                    varying highp vec2 qt_TexCoord0;
                    void main() {
                        qt_TexCoord0 = qt_MultiTexCoord0;
                        gl_Position = qt_Matrix * qt_Vertex;
                    }"

                //片源着色器程序
                fragmentShader: "
                    varying highp vec2 qt_TexCoord0;
                    uniform sampler2D source;
                    uniform lowp float qt_Opacity;
                    void main() {
                        gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;
                    }"
            }
        }
    }
}

 这个程序中着色器并没有对图片执行任何操作,显示效果如下图所示:

QML进阶(七)-OpenGL渲染着色器效果实现_第1张图片

下面详细介绍一下着色程序中的基本类型和一些关键字:

顶点着色器

//顶点着色器程序
vertexShader: "
	uniform highp mat4 qt_Matrix;
	attribute highp vec4 qt_Vertex;
	attribute highp vec2 qt_MultiTexCoord0;
	varying highp vec2 qt_TexCoord0;
	void main() {
		qt_TexCoord0 = qt_MultiTexCoord0;
		gl_Position = qt_Matrix * qt_Vertex;
	}"

shader程序中的关键字的含义

uniform 用来定义常量,代表着在处理过程中不会变化的值

attribute 定义用来连接外部数据的变量

varying 用来定义在两个着色器之间传递的数据

highp 定义高精度值

lowp 定义低精度的值

mat4 定义4x4的矩阵

vec2 定义维度为2的容器

sampler2D 定义2D的纹理

float 定义浮点数

qt_Matric代表着模型-视图-投影矩阵

qt_Vertex代表着当前的顶点位置

qt_MultiTexCoord0: 代表着纹理的坐标

qt_TexCoord0: 和其它着色器共享的纹理坐标

//main函数是着色器程序的入口函数
void main() {
           //在传到片源着色器程序的时候纹理图片坐标不变化
		qt_TexCoord0 = qt_MultiTexCoord0;
           //顶点着色器的顶点坐标位置也不发生变化
           //投影矩阵没有添加数据不会对顶点信息进行修改
		gl_Position = qt_Matrix * qt_Vertex;
	}"

片源着色器

片源着色器从顶点着色器接收到顶点的坐标和纹理的坐标,然后进行颜色渲染,程序中我们可以通过修改qt_Opacity来控制图片的透明度。每一个片源着色器最终输出的都是gl_FragColor变量,该变量代表着程序输出到屏幕上的颜色。

fragmentShader: "
    varying highp vec2 qt_TexCoord0;
    uniform sampler2D source;
    uniform lowp float qt_Opacity;
    void main() {
        //纹理按照原始的位置进行显示
        gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity;
    }"

 片源着色器程序的各种效果

import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    Rectangle {
        width: 600; height: 240
        color: '#1e1e1e'

        Row {
            anchors.centerIn: parent
            spacing: 20

            //原始图片
            Image {
                id: sourceImage
                width: 80; height: width
                source: 'qrc:/transform.png'
            }

            /***显示成灰色***/
            //vect4(Red,Green,Blue,Alpa)
            ShaderEffect {
                id: effect
                width: 80; height: width
                property variant source: sourceImage
                //片源着色器程序
                //显示成单一固定颜色
                fragmentShader: "
                    uniform lowp float qt_Opacity;
                    void main() {
                        gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0) * qt_Opacity;
                    }"
            }

            /***添加灰色蒙版***/
            ShaderEffect {
                id: effect2
                width: 80; height: width

                //指定输入的图片源
                property variant source: sourceImage
                //片源着色器程序
                fragmentShader: "
                    varying highp vec2 qt_TexCoord0;
                    uniform sampler2D source;
                    uniform lowp float qt_Opacity;
                    void main() {
                        gl_FragColor = texture2D(source, qt_TexCoord0) * vec4(0.5, 0.5, 0.5, 1.0) * qt_Opacity;
                    }"
            }

            /***通过外部通道手动指定渲染通道的颜色***/
            //除了红色通道之外的其它的值都是1不会影响最终效果,只有红色通道影响最终效果
            ShaderEffect {
                id: effect3
                width: 80; height: width
                property variant source: sourceImage
                //指定红色通道的值为0.3
                property real redChannel: 0.3
                fragmentShader: "
                    varying highp vec2 qt_TexCoord0;
                    uniform sampler2D source;
                    uniform lowp float qt_Opacity;
                    uniform lowp float redChannel;
                    void main() {
                        gl_FragColor = texture2D(source, qt_TexCoord0) * vec4(redChannel, 1.0, 1.0, 1.0) * qt_Opacity;
                    }"
            }
            /***动态修改红色通道的值***/
            ShaderEffect {
                id: effect4
                width: 80; height: width
                property variant source: sourceImage
                property real redChannel: 0.3
                NumberAnimation on redChannel {
                    from: 0.0; to: 1.0; loops: Animation.Infinite; duration: 4000
                }

                fragmentShader: "
                   varying highp vec2 qt_TexCoord0;
                   uniform sampler2D source;
                   uniform lowp float qt_Opacity;
                   uniform lowp float redChannel;
                   void main() {
                       gl_FragColor = texture2D(source, qt_TexCoord0) * vec4(redChannel, 1.0, 1.0, 1.0) * qt_Opacity;
                   }"
            }

        }
    }
}

QML进阶(七)-OpenGL渲染着色器效果实现_第2张图片

片源着色器波动效果

import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    Rectangle {
        width: 600; height: 240
        color: '#1e1e1e'

        Row {
            anchors.centerIn: parent
            spacing: 20

            //原始图片
            Image {
                id: sourceImage
                width: 160; height: width
                source: 'qrc:/transform.png'
            }
            //波动效果
            ShaderEffect {
                width: 160; height: width
                property variant source: sourceImage

                //频率为8
                property real frequency: 8
                //幅度为0.1
                property real amplitude: 0.1
                //事件从0到2PI
                property real time: 0.0
                NumberAnimation on time {
                    from: 0; to: Math.PI*2; duration: 1000; loops: Animation.Infinite
                }

                fragmentShader: "
                       varying highp vec2 qt_TexCoord0;
                       uniform sampler2D source;
                       uniform lowp float qt_Opacity;
                       uniform highp float frequency;
                       uniform highp float amplitude;
                       uniform highp float time;
                       void main() {
                           //指定正弦波
                           highp vec2 pulse = sin(time - frequency * qt_TexCoord0);
                           highp vec2 coord = qt_TexCoord0 + amplitude * vec2(pulse.x, -pulse.x);
                           gl_FragColor = texture2D(source, coord) * qt_Opacity;
                       }"
            }
        }
    }
}

显示效果如下图所示:

QML进阶(七)-OpenGL渲染着色器效果实现_第3张图片 

顶点着色器的各种效果

顶点着色器用来控制纹理的各个顶点的位置。通常情况下,顶点着色器可以指定四个位置(top-left、top-right、bottom-left、bottom-right).每个顶点的位置的类型都是vec4。下面介绍一下,通过顶点着色器控制的各种特效。

动态对图片进行缩放

import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    Rectangle {
        width: 480; height: 240
        color: '#1e1e1e'
        Row{
            spacing:20
            Image {
                id: sourceImage
                width: 160; height: width
                source: "qrc:/transform.png"
            }
            ShaderEffect {
                id: sacleEffect
                width: 160; height: width
                property variant source: sourceImage
                property bool minimized: false
                //点击的时候修改标志位minimized来对状态进行修改
                MouseArea {
                    anchors.fill: parent
                    onClicked: sacleEffect.minimized = !sacleEffect.minimized
                }
                property real minimize: 0.0
                //minimized为1的时候的动画
                //注意minimized是标志位bool类型, mimimize是变化程度是real类型,两个是不同的变量
                SequentialAnimation on minimize {
                    id: animMinimize
                    running: sacleEffect.minimized
                    PauseAnimation { duration: 300 }
                    //minimize从0变到1
                    NumberAnimation { to: 1; duration: 700; easing.type: Easing.InOutSine }
                    PauseAnimation { duration: 1000 }
                }
                //minimized为0的时候的动画
                SequentialAnimation on minimize {
                    id: animNormalize
                    running: !sacleEffect.minimized
                    //minimize从1变到0
                    NumberAnimation { to: 0; duration: 700; easing.type: Easing.InOutSine }
                    PauseAnimation { duration: 1300 }
                }
                //顶点着色器程序
                //mix是差值函数原理如下
                //mix(qt_Vertex.y,height,minimize) = qt_Vertex.y*(1-minimize) + height*minimize
                //mimizmize为1的时候最大显示,为0的时候不显示
                vertexShader: "
               uniform highp mat4 qt_Matrix;
               attribute highp vec4 qt_Vertex;
               attribute highp vec2 qt_MultiTexCoord0;
               varying highp vec2 qt_TexCoord0;
               uniform highp float minimize;
               uniform highp float width;
               uniform highp float height;
               void main() {
                   qt_TexCoord0 = qt_MultiTexCoord0;
                   highp vec4 pos = qt_Vertex;
                   pos.y = mix(qt_Vertex.y, height, minimize);
                   pos.x = mix(qt_Vertex.x, width, minimize);
                   gl_Position = qt_Matrix * pos;
               }"
            }
        }

    }
}

效果如下所示:

QML进阶(七)-OpenGL渲染着色器效果实现_第4张图片 

通过定点着色器实现的其它特效,主要涉及到一些矩阵变化和数学领域的知识,就不详细介绍了。

import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 680
    height: 480
    Rectangle {
        width: 680; height: 240
        color: '#1e1e1e'
        Row{
            spacing:20
            Image {
                id: sourceImage
                width: 160; height: width
                source: "qrc:/transform.png"
            }
            ShaderEffect {
                id: sacleEffect
                width: 160; height: width
                property variant source: sourceImage
                property bool minimized: false
                //点击的时候修改标志位minimized来对状态进行修改
                MouseArea {
                    anchors.fill: parent
                    onClicked: sacleEffect.minimized = !sacleEffect.minimized
                }
                property real minimize: 0.0
                //minimized为1的时候的动画
                //注意minimized是标志位bool类型, mimimize是变化程度是real类型,两个是不同的变量
                SequentialAnimation on minimize {
                    id: animMinimize
                    running: sacleEffect.minimized
                    PauseAnimation { duration: 300 }
                    //minimize从0变到1
                    NumberAnimation { to: 1; duration: 700; easing.type: Easing.InOutSine }
                    PauseAnimation { duration: 1000 }
                }
                //minimized为0的时候的动画
                SequentialAnimation on minimize {
                    id: animNormalize
                    running: !sacleEffect.minimized
                    //minimize从1变到0
                    NumberAnimation { to: 0; duration: 700; easing.type: Easing.InOutSine }
                    PauseAnimation { duration: 1300 }
                }
                vertexShader: "
                        uniform highp mat4 qt_Matrix;
                        uniform highp float minimize;
                        uniform highp float height;
                        uniform highp float width;
                        attribute highp vec4 qt_Vertex;
                        attribute highp vec2 qt_MultiTexCoord0;
                        varying highp vec2 qt_TexCoord0;
                        void main() {
                            qt_TexCoord0 = qt_MultiTexCoord0;
                            highp vec4 pos = qt_Vertex;
                            pos.y = mix(qt_Vertex.y, height, minimize);
                            highp float t = pos.y / height;
                            pos.x = mix(qt_Vertex.x, width, t * minimize);
                            gl_Position = qt_Matrix * pos;
                        }"
            }
            ShaderEffect {
                id: genieEffect
                width: 160; height: width
                property variant source: sourceImage
                mesh: GridMesh { resolution: Qt.size(10, 10) }
                property real minimize: 0.0
                property real bend: 0.0
                property bool minimized: false
                property real side: 1.0
                MouseArea {
                    anchors.fill: parent
                    onClicked: parent.minimized = !parent.minimized
                }

                ParallelAnimation {
                    id: animMinimize1
                    running: genieEffect.minimized
                    SequentialAnimation {
                        PauseAnimation { duration: 300 }
                        NumberAnimation {
                            target: genieEffect; property: 'minimize';
                            to: 1; duration: 700;
                            easing.type: Easing.InOutSine
                        }
                        PauseAnimation { duration: 1000 }
                    }
                    SequentialAnimation {
                        NumberAnimation {
                            target: genieEffect; property: 'bend'
                            to: 1; duration: 700;
                            easing.type: Easing.InOutSine }
                        PauseAnimation { duration: 1300 }
                    }
                }

                ParallelAnimation {
                    id: animNormalize1
                    running: !genieEffect.minimized
                    SequentialAnimation {
                        NumberAnimation {
                            target: genieEffect; property: 'minimize';
                            to: 0; duration: 700;
                            easing.type: Easing.InOutSine
                        }
                        PauseAnimation { duration: 1300 }
                    }
                    SequentialAnimation {
                        PauseAnimation { duration: 300 }
                        NumberAnimation {
                            target: genieEffect; property: 'bend'
                            to: 0; duration: 700;
                            easing.type: Easing.InOutSine }
                        PauseAnimation { duration: 1000 }
                    }
                }

                vertexShader: "
                    uniform highp mat4 qt_Matrix;
                    attribute highp vec4 qt_Vertex;
                    attribute highp vec2 qt_MultiTexCoord0;
                    uniform highp float height;
                    uniform highp float width;
                    uniform highp float minimize;
                    uniform highp float bend;
                    uniform highp float side;
                    varying highp vec2 qt_TexCoord0;
                    void main() {
                        qt_TexCoord0 = qt_MultiTexCoord0;
                        highp vec4 pos = qt_Vertex;
                        pos.y = mix(qt_Vertex.y, height, minimize);
                        highp float t = pos.y / height;
                        t = (3.0 - 2.0 * t) * t * t;
                        pos.x = mix(qt_Vertex.x, side * width, t * bend);
                        gl_Position = qt_Matrix * pos;
                    }"
            }

        }

    }
}

QML进阶(七)-OpenGL渲染着色器效果实现_第5张图片 

QML中的图像效果库

QML中对常用的图像效果进行了封装,我们可以直接拿来就用,同时这个封装库也是一个很好的学习资料,我们可以根据其中的例子进行参考,实现自己想要的图像效果。

下面以一个模糊效果为例,说明一下这个库的使用方法:

import QtQuick 2.0
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2
import QtGraphicalEffects 1.0

ApplicationWindow {
    visible: true
    width: 680
    height: 480
    Rectangle {
        width: 480; height: 240
        color: '#1e1e1e'

        Row {
            anchors.centerIn: parent
            spacing: 16

            Image {
                id: sourceImage
                source: "qrc:/transform.png"
                width: 200; height: width
                sourceSize: Qt.size(parent.width, parent.height)
                smooth: true
            }

            FastBlur {
                width: 200; height: width
                source: sourceImage
                radius: blurred?32:0
                property bool blurred: false

                Behavior on radius {
                    NumberAnimation { duration: 1000 }
                }

                MouseArea {
                    id: area
                    anchors.fill: parent
                    onClicked: parent.blurred = !parent.blurred
                }
            }
        }
    }
}

 

效果如下:

QML进阶(七)-OpenGL渲染着色器效果实现_第6张图片

图像库效果列表如下,供参考

类别

效果

介绍

Blend

Blend

merges two source items by using a blend mode

Color

BrightnessContrast

adjusts brightness and contrast

Colorize

sets color in the HSL color space

ColorOverlay

applies a color layer

Desaturate

reduces color saturation

GammaAdjust

adjusts luminance

HueSaturation

adjusts colors in the HSL color space

LevelAdjust

adjusts colors in the RGB color space

Gradient

ConicalGradient

draws a conical gradient

LinearGradient

draws a linear gradient

RadialGradient

draws a radial gradient

Distortion

Displace

moves the pixels of the source item according to the specified displacement source

Drop Shadow

DropShadow

draws a drop shadow

InnerShadow

draws an inner shadow

Blur

FastBlur

applies a fast blur effect

GaussianBlur

applies a higher quality blur effect

MaskedBlur

applies a varying intensity blur effect

RecursiveBlur

blurs repeatedly, providing a strong blur effect

Motion Blur

DirectionalBlur

applies a directional motion blur effect

RadialBlur

applies a radial motion blur effect

ZoomBlur

applies a zoom motion blur effect

Glow

Glow

draws an outer glow effect

RectangularGlow

draws a rectangular outer glow effect

Mask

OpacityMask

masks the source item with another item

ThresholdMask

masks the source item with another item and applies a threshold value

你可能感兴趣的:(QT,着色器,qt,QML,c++,OpenGL)