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 }
最终效果如下: