0.前言
对于 ShaderEffect 的介绍请看 Qt 文档:https://doc.qt.io/qt-5/qml-qtquick-shadereffect.html
之前用 QtGraphicalEffects 模块的镜像渐变做过波纹效果,但是那个 GradientStop 不能放到 Repeator 里,要根据参数动态设置波纹大小就需要 createComponent 之类的。最近用 ShaderEffect 又重新实现了下波纹效果。感觉最麻烦的就是抗锯齿,最终效果勉强,不过没 QtGraphicalEffects 做的好,有空研究下他怎么实现的。
下图左侧 Shader,右侧渐变:
波纹就是通过设置每一段间隔范围的透明度来实现,在此基础上加一个偏移量加减透明度值,使之看起来在移动。
抗锯齿我使用的 smoothstep 函数,但是目前效果还不大理想,后面再研究下怎么优化。
2.实现代码(这里使用的 QML 默认的 OpenGL ES2.0 的 glsl)
Shader(就几句代码,懒得写注释了):
import QtQuick 2.12
//使用shader制作波纹效果
ShaderEffect{
id: control
width: 150
height: 150
//动画移动偏移量
property real offset: 0
//波纹间隔
property real spacing: 20
NumberAnimation {
target: control
property: "offset"
duration: 2000
from: 0
to: control.spacing
loops: Animation.Infinite //-1
running: true
}
vertexShader: "
uniform mat4 qt_Matrix;
attribute vec4 qt_Vertex;
attribute vec2 qt_MultiTexCoord0;
varying vec2 thePos;
void main() {
thePos = vec2(qt_MultiTexCoord0.x*2.0-1.0,-qt_MultiTexCoord0.y*2.0+1.0);
gl_Position = qt_Matrix * qt_Vertex;
}
"
fragmentShader: "
varying vec2 thePos;
uniform float qt_Opacity;
uniform float width;
uniform float offset;
uniform float spacing;
vec4 outColor;
float mod(float x,float y)
{
return x-y*floor(x/y);
}
void main()
{
outColor = vec4(1,0,0,0);
float aSmoothWidth=3.0/float(width);
// distance(pos)=[0,1],on center=0,on border=1
float dis=distance(thePos,vec2(0.0,0.0))*width;
float maxlen=float(int(width)/int(spacing*2.0))*spacing*2.0-spacing*2.0+offset*2.0;
if(dis0.99-aSmoothWidth)
outColor.a=smoothstep(0.99,0.98-aSmoothWidth,outColor.a);
// erasing
outColor.a=pow(outColor.a,2.0);
}
gl_FragColor = outColor * qt_Opacity;
gl_FragColor.rgb *= gl_FragColor.a;
}
"
}
渐变:
import QtQuick 2.12
import QtGraphicalEffects 1.0
//使用渐变制作波纹效果
RadialGradient{
id: control
implicitWidth: 150
implicitHeight: 150
property double wave_offset: 0.0
property color wave_color: "red"
property alias running: animation.running
NumberAnimation{
id: animation
target: control
property: "wave_offset"
from: 0
to: 0.1
duration: 2000
running: control.visible
loops: Animation.Infinite //-1
}
//待改进,根据参数来设置波纹数量
gradient: Gradient{
//很遗憾,不能用Repeater,可以试下createComponent,然后属性用binding绑定offset
GradientStop{ position: 0; color: "transparent" }
GradientStop{ position: control.wave_offset+0.001; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.01; color: "transparent" }
GradientStop{ position: control.wave_offset+0.05; color: "transparent" }
GradientStop{ position: control.wave_offset+0.1; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.11; color: "transparent" }
GradientStop{ position: control.wave_offset+0.15; color: "transparent" }
GradientStop{ position: control.wave_offset+0.2; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.21; color: "transparent" }
GradientStop{ position: control.wave_offset+0.25; color: "transparent" }
GradientStop{ position: control.wave_offset+0.3; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.31; color: "transparent" }
GradientStop{ position: control.wave_offset+0.35; color: "transparent" }
GradientStop{ position: control.wave_offset+0.4; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.41; color: "transparent" }
}
}