qml+shader实现steam平台上游戏库中卡片选中特效


最近使用Qt在做一个项目中涉及到大量卡片列表的需求,为了让界面展示更加丰富,打算实现类似steam中鼠标滑过时的效果:

经过分析可知,当鼠标滑过时动效分为两个部分:

1)  图片的翻转动画:使用PropertyAnimation驱动卡片沿指定的轴翻转

2   图片上的光影动画:使用PropertyAnimation驱动指定变量发生变化,该变量传入到着色器中,控制光带移动

好在Qml同时支持动画和着色器,实现代码如下

  1 import QtQuick 2.0
  2 Item {
  3     id: shadercard
  4     property string mypicpath: "qrc:/images3/images3/test.png"  //图片路径
  5     property real    vpos:-0.8                                 //图片光影位置
  6 
  7     ShaderEffect  {
  8         id:shadereffect
  9         anchors.fill: parent
 10 
 11         //将光影位置传到着色器中
 12         property real       iposStartX: vpos
 13 
 14         //将图片作为通道传到着色器中
 15         property variant iChannel0: Image {
 16             source: mypicpath
 17         }
 18 
 19         //顶点着色器,没做什么
 20         vertexShader: "
 21         uniform highp mat4 qt_Matrix;
 22         attribute highp vec4 qt_Vertex;
 23         attribute highp vec2 qt_MultiTexCoord0;
 24         varying highp vec2 coord;
 25         void main() {
 26             coord = qt_MultiTexCoord0;
 27             gl_Position = qt_Matrix * qt_Vertex;
 28         }"
 29 
 30 
 31         fragmentShader:"
 32 
 33         uniform float  iposStartX;         //光影位置
 34         uniform vec3   iResolution;  //图片大小
 35         uniform sampler2D   iChannel0;  //图片数据
 36         varying highp vec2 coord;
 37 
 38         #define ANGLE 60.0   //光影斜着的角度
 39 
 40 
 41         float thresholdY = 0.5;  //控制光影的宽带
 42         float blur = 0.065;      //控制光带边缘的模糊程度
 43         float alphaFactor = 0.8; //控制光带的明暗程度
 44 
 45         float colFactor(vec2 uv, float thresholdX, float blur){
 46             float tempY = uv.x * cos(radians(ANGLE)) + iposStartX; //根据x的位置,以Angle的角度计算y的位置
 47             float intervalY = uv.y - tempY;                        //将增加的Y值加上
 48             return smoothstep(thresholdY, thresholdY - blur, abs(intervalY)) * alphaFactor; //根据intervalY的位置进行smoothstep,在画出光带
 49         }
 50         void main(void)
 51         {
 52            vec4 back = texture(iChannel0, coord);
 53            float factor = colFactor(coord, thresholdY, blur);
 54            vec3 col =  back.xyz +  vec3(0.2) *factor;
 55            gl_FragColor = vec4(col,1.0);
 56         }
 57     "
 58     }
 59 
 60     //控制卡牌翻转
 61     transform: Rotation{
 62         id:animationrotate
 63         origin.x:testimnage.width/2.0
 64         origin.y:-testimnage.height/2.0
 65         axis{x:1;y:0;z:0}
 66         angle: 0
 67 
 68     }
 69 
 70     //两个动画,分别控制翻转角度和光带位置
 71     PropertyAnimation{
 72         id:animation
 73         target:animationrotate
 74         easing.type:Easing.OutQuad
 75         properties: "angle"
 76         duration: 500
 77     }
 78     PropertyAnimation{
 79         id:animation2
 80         easing.type:Easing.OutQuad
 81         target:testimnage
 82         properties: "vpos"
 83         duration: 500
 84     }
 85 
 86     //鼠标事件
 87     MouseArea{
 88         anchors.fill: parent
 89         hoverEnabled: true
 90 
 91         onEntered: {
 92 
 93             if(animation.running)
 94             {
 95                 animation.running = false
 96                 animation2.running = false
 97             }
 98             animation.to=3
 99             animation2.to = -0.3
100             animation.running=true;
101             animation2.running=true;
102 
103 
104         }
105         onExited: {
106             if(animation.running)
107             {
108                 animation.running = false
109                 animation2.running = false
110             }
111             animation.to=0
112             animation2.to = -0.8
113             animation.running=true;
114             animation2.running=true;
115 
116         }
117     }
118 }

最终效果如下: