效果
分析
上图是一个动态扭曲效果。它展示了从原始纹理坐标空间开始的逐步过程,移动坐标原点到中心,根据距离和时间变量计算扭曲,以及最后的偏移纹理坐标和产生的动态扭曲效果。效果中体现了像素的移动,因此可以用Shader来处理,具体主要再片源着色器中处理。
- 首先,将纹理坐标的原点移动到纹理的中心。
- 计算每个点到中心的距离,并使用这个距离乘以时间变量来计算一个偏移角度,实现动态的扭曲效果。
- 使用偏移角度计算偏移后的纹理坐标。
- 根据偏移后的坐标,从纹理中取色,实现扭曲效果。
这里用Cocos Creator 2.4.12的版本创建Effect文件
typescript
// 小南-扭曲黑洞
CCEffect %{
techniques:
- passes:
- vert: vs
frag: fs
blendState:
targets:
- blend: true
rasterizerState:
cullMode: none
properties:
texture: { value: white }
time: { value: 0.0 }
}%
CCProgram vs %{
precision highp float;
#include <cc-local>
#include <cc-global>
#include <skinning>
in vec4 a_position;
in vec2 a_uv0;
out vec2 v_uv;
void main() {
gl_Position = cc_matViewProj * a_position;
v_uv = a_uv0;
}
}%
CCProgram fs %{
precision highp float;
#include <cc-global>
#include <cc-local>
in vec2 v_uv;
uniform sampler2D texture;
uniform c{
// 用于控制扭曲的时间
float time;
};
void main() {
// 将坐标原点移到纹理中心
vec2 p = v_uv - 0.5;
float distanceToCenter = length(p);
// 计算偏移角度,与距离成正比
float offsetAngle = distanceToCenter * time;
// 计算偏移后的坐标
vec2 offsetCoord = vec2(
p.x * cos(offsetAngle) - p.y * sin(offsetAngle),
p.x * sin(offsetAngle) + p.y * cos(offsetAngle)
);
// 归一化坐标
vec2 normalizedCoord = offsetCoord + 0.5;
// 输出颜色
gl_FragColor = texture2D(texture, normalizedCoord);
}
}%
在项目中通过传值time
来控制扭曲的效果,代码如下:
typescript
const { ccclass, property } = cc._decorator;
@ccclass
export default class distortEffect extends cc.Component {
@property(cc.Node)
bg: cc.Node = null;
protected start(): void {
this.schedule(this.onDistort.bind(this), 0.1, 360, 6);
}
private progress = 0;
onDistort() {
this.progress += 0.1;
// 根据滑动的值设置材质
this.bg.getComponent(cc.Sprite).getMaterial(0).setProperty('time', this.progress * 30);
}
}
设置好背景图bg
后,通过计时器来控制shader中time
的值,至此,就实现完了动态扭曲的效果。