查看完整版本: [-- Qml特效15-暗流涌动 --]

QTCN开发网 -> Qt 作品展 -> Qml特效15-暗流涌动 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

dd759378563 2019-06-11 14:14

Qml特效15-暗流涌动

Qml特效15-暗流涌动

作者 涛哥



目录简介


简介


这是《Qml特效》系列文章的第15篇,涛哥将会教大家一些Qml特效和动画相关的知识。
前12篇是进场动画效果 参考了WPS版ppt的动画,12种基本效果已经全部实现,可以到github TaoQuick项目中预览:
进场动画预览


因为效果都比较简单,就没有写太多说明。
没有13
没有13
没有13
从14篇开始,做一些特殊的效果和动画,同时会讲解相关的知识。

关于文章


文章主要发布在涛哥的博客涛哥的知乎专栏-Qt进阶之路

暗流涌动 效果预览


流动的箭头,以及倒影
[attachment=20462]
其中用到的知识点有: Qml路径动画。
当然还有一些预备知识:做特效和动画,要用到QtQuick的动画系统,以及ShaderEffect特效。

QtQuick动画系统



动画组件


Qt动画系统,在帮助文档有详细的介绍,搜索关键词”Animation”,涛哥在这里说一些重点。涛哥用思维导图列出了Qml中所有的动画组件:

[attachment=20463]


  • 右边带虚线框的部分比较常用,是做动画必须要掌握的,尤其是属性动画PropertyAnimation和数值动画NumberAinmation。
    常见的各种坐标动画、宽高动画、透明度动画、颜色动画等等,都可以用这些组件来实现。
  • 底下的States、Behavior 和 Traisitions,也是比较常用的和动画相关的组件。可在帮助文档搜索
    关键词”Qt Quick States”、”Behavior”、”Animation and Transitions”。后续的文章,涛哥会专门讲解。
  • 左边的Animator系列,属于Scene Graph渲染层面的优化,其属性Change信号只在最终值时发出,不发出中间值,使用的时候需要注意。
  • 顶上的AnimationController,属于高端玩家,用来控制整个动画的进度。


动画的使用



用例一 直接声明动画


直接声明动画,指定target和property,之后可以在槽函数/js脚本中通过id控制动画的运行。也可以通过设定loops 和 running属性来控制动画
  1. Rectangle {
          id: flashingblob
          width: 75; height: 75
          color: "blue"
          opacity: 1.0

          MouseArea {
              anchors.fill: parent
              onClicked: {
                  animateColor.start()
                  animateOpacity.start()
              }
          }

          PropertyAnimation {id: animateColor; target: flashingblob; properties: "color"; to: "green"; duration: 100}

          NumberAnimation {
              id: animateOpacity
              target: flashingblob
              properties: "opacity"
              from: 0.99
              to: 1.0
              loops: Animation.Infinite
              easing {type: Easing.OutBack; overshoot: 500}
         }
      }




用例二 on语法


on语法可以使用动画组件,也可以用Behavior,直接on某个特定的属性即可。效果一样。on动画中,如果直接指定了running属性,默认就会执行这个动画。
也可以不指定running属性,其它地方修改这个属性时,会自动按照动画来执行。


示例代码 on动画
  1. Rectangle {
          width: 100; height: 100; color: "green"
          RotationAnimation on rotation {
              loops: Animation.Infinite
              from: 0
              to: 360
              running: true
          }
      }
示例代码 Behavior 动画
  1. import QtQuick 2.0

      Rectangle {
          id: rect
          width: 100; height: 100
          color: "red"

          Behavior on width {
              NumberAnimation { duration: 1000 }
          }

          MouseArea {
              anchors.fill: parent
              onClicked: rect.width = 50
          }
      }





用例三 Transitions或状态机


过渡动画和状态机动画,本质还是直接使用动画组件。只不过是把动画声明并存储起来,以在状态切换时使用。这里先不细说了,后面会有系列文章<Qml特效-页面切换动画>,会专门讲解。

ShaderEffect


动画只能控制组件的属性整体的变化,做特效需要精确到像素。Qml中提供了ShaderEffect这个组件,就能实现像素级别的操作。
Qml中有一个模块QtGraphicalEffects,提供了部分特效,就是使用ShaderEffect实现的。使用ShaderEffect实现特效,需要有一些OpenGL/DirectX知识,了解GPU渲染管线,同时也需要一些数学知识。
大名鼎鼎的ShaderToy网站,就是使用Shader实现各种像素级别的酷炫特效。ShaderToy
作者iq大神ShaderToy上面的特效都是可以移植到Qml中的。
使用Shader开发,需要一定的图形学知识。其中使用GLSL需要熟悉OpenGL, 使用HLSL需要熟悉DirectX。

暗流涌动 效果源码



组件的封装


封装了一个组件
  1. //TArrow.qml
    import QtQuick 2.12
    import QtQuick.Controls 2.12
    Image {
        id: root
        x: 10
        y: 10
        source: "qrc:/EffectImage/Img/arrow.png"
        visible: false
        function run() {
            visible = true;
            pathAnimation.start();
        }
        PathAnimation {
            id: pathAnimation
            target: root
            loops: -1
            duration: 2400
            orientation: PathAnimation.TopFirst
            path: Path{
                startX: 10
                startY: 10
                PathCurve { x: 60; y: 15}
                PathCurve { x: 110; y: 205}
                PathCurve { x: 210; y: 200}
                PathCurve { x: 260; y: 35}
                PathCurve { x: 310; y: 25}
            }
        }
    }




原理


很简单的路径动画,使用的箭头图片是这张:




组件的使用
  1. import QtQuick 2.12
    import QtQuick.Controls 2.12
    import "../Effects/"
    Rectangle {
        anchors.fill: parent
        color: "black"
        Item {
            id: arrowItem
            x: 10
            y: 10
            width: 300
            height: 300
            TArrow {
                id: arrow1
            }
            TArrow {
                id: arrow2
            }
            TArrow {
                id: arrow3
            }
            TArrow {
                id: arrow4
            }
            TArrow {
                id: arrow5
            }
            TArrow {
                id: arrow6
            }
            TArrow {
                id: arrow7
            }
            TArrow {
                id: arrow8
            }
            TArrow {
                id: arrow9
            }
        }
        Item {
            id: mirrorItem
            x: arrowItem.x
            y: arrowItem.y + arrowItem.height
            width: arrowItem.width
            height: arrowItem.height
            opacity: 0.3
            layer.enabled: true
            layer.effect: Component {
                ShaderEffectSource {
                    sourceItem: arrowItem
                    textureMirroring: ShaderEffectSource.MirrorVertically
                }
            }
            transform: Rotation {
                origin.x: mirrorItem.width / 2
                origin.y: mirrorItem.height / 2
                axis {x: 1; y: 0; z: 0}
                angle: 180
            }
        }
        Component.onCompleted: {
            seAnimation.start()
        }
        SequentialAnimation {
            id: seAnimation
            ScriptAction {script: arrow1.run()}
            PauseAnimation {duration: 200 }
            ScriptAction {script: arrow2.run()}
            PauseAnimation {duration: 200 }
            ScriptAction {script: arrow3.run()}

            PauseAnimation {duration: 500 }

            ScriptAction {script: arrow4.run()}
            PauseAnimation {duration: 200 }
            ScriptAction {script: arrow5.run()}
            PauseAnimation {duration: 200 }
            ScriptAction {script: arrow6.run()}

            PauseAnimation {duration: 500 }

            ScriptAction {script: arrow7.run()}
            PauseAnimation {duration: 200 }
            ScriptAction {script: arrow8.run()}
            PauseAnimation {duration: 200 }
            ScriptAction {script: arrow9.run()}
            PauseAnimation {duration: 200 }
        }
    }



动画比较简单粗暴。

倒影这里,和《Qml特效14-跟上节奏》使用的不一样,使用的是Item的layer属性

layer.enabled: true

layer.effect: Component {
ShaderEffectSource {
...
}
}







liulin188 2019-06-12 09:51

john_duan 2019-06-13 16:02

liudianwu 2019-06-13 20:49

qyvlik 2019-06-14 08:52
大佬,能单独来份 ShaderEffect 的入门教学吗?例如在 QML 中使用 GLSL 需要哪些具体的知识,怎么做出一个好看的特效。

dd759378563 2019-06-14 14:22
qyvlik:
大佬,能单独来份 ShaderEffect 的入门教学吗?例如在 QML 中使用 GLSL 需要哪些具体的知识,怎么做出一个好看的特效。

吓我一跳, qyvlik 你才是大佬,我从你的CSDN学了不少东西呢。
我学习过OpenGL,懂一点图形学,
那我这周末试着总结一下,写好了通知你。

richards 2019-06-15 14:43
大佬 你的导图是什么软件画的

bobpan 2019-07-13 11:22


查看完整版本: [-- Qml特效15-暗流涌动 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled