前言
在Web图形开发中,Canvas技术为我们提供了丰富的视觉表现能力。今天,我将分享如何使用Pixi.js框架及其滤镜系统,实现一个具有随机水波纹和鼠标交互的水波纹特效。本教程基于Pixi.js 7.4.2版本,通过实际代码演示如何创建动态的视觉体验。
实现效果预览:
- 随机生成的水波纹扩散效果
- 点击屏幕任意位置触发水波纹
- 多种滤镜叠加的视觉体验

一、环境搭建与项目创建
shell
# 创建Vite项目
npm create vite@latest . -- --template vue
# 安装Pixi.js 7.4.2版本
npm install pixi.js@7.4.2
# 安装Pixi滤镜库
npm install pixi-filters@5.1.0
1.2 版本说明
- Pixi.js 7.4.2:这是目前稳定的版本,提供了优秀的性能和API支持
- pixi-filters 5.1.0:官方滤镜库,包含多种特效滤镜
二、完整代码实现
下面是一个完整的Vue单文件组件实现:
注意: 需要删除vite构建项目的基本样式,因为这里将一些全局的样式也写在这里了,所以为了能生效,<style>标签不能使用scope
javascript
<template>
<div class="canvas-container">
<!-- Pixi.js画布将通过JavaScript动态添加到此处 -->
</div>
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue';
import * as PIXI from 'pixi.js';
import { ShockwaveFilter } from 'pixi-filters';
// Pixi应用实例
let app = null;
onMounted(() => {
initPixiApp();
});
onUnmounted(() => {
// 清理资源
if (app) {
app.destroy(true);
app = null;
}
});
const initPixiApp = () => {
// 1. 创建Pixi应用
app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x1099bb, // 背景颜色
resolution: window.devicePixelRatio || 1, // 适配高清屏幕
antialias: true, // 开启抗锯齿
resizeTo: window, // 自适应窗口大小
});
// 将Pixi画布添加到DOM
document.querySelector('.canvas-container').appendChild(app.view);
// 2. 创建容器
const container = new PIXI.Container();
app.stage.addChild(container);
// 3. 创建背景精灵
// 注意:你需要准备一张名为tree.jpg的图片放在public/textures目录下
const texture = PIXI.Texture.from('/textures/tree.jpg');
const sprite = new PIXI.Sprite(texture);
// 居中并缩放图片
sprite.anchor.set(0.5);
sprite.scale.set(0.5);
sprite.position.set(app.screen.width / 2, app.screen.height / 2 - 300);
container.addChild(sprite);
// 4. 创建文字元素
const text = new PIXI.Text('Hello Tree', {
fontFamily: "Arial",
fontSize: 30 + Math.floor(app.screen.width * 0.1),
align: 'center',
fill: 0xffffff,
dropShadow: true,
dropShadowColor: '#000000',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 2,
dropShadowDistance: 20
});
text.anchor.set(0.5);
text.position.set(app.screen.width / 2, app.screen.height / 2);
container.addChild(text);
// 5. 创建置换滤镜(增强波纹效果)
// 注意:需要一张名为replace.png的置换贴图
const displaceSprite = PIXI.Sprite.from("/textures/replace.png");
displaceSprite.scale.set(0.1);
displaceSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT; // 设置为重复模式
const displaceFilter = new PIXI.DisplacementFilter(displaceSprite);
container.addChild(displaceSprite);
// 6. 创建多个水波纹滤镜(实现复杂效果)
// 第一个水波纹滤镜(主波纹)
const waveFilter1 = new ShockwaveFilter([
Math.random() * app.screen.width,
Math.random() * app.screen.height
], {
radius: 180, // 波纹半径
wavelength: 30, // 波长
amplitude: 10, // 振幅
strength: 100, // 强度
speed: 500, // 扩散速度
waveLength: 100,
}, 0);
// 第二个水波纹滤镜(辅助波纹1)
const waveFilter2 = new ShockwaveFilter([
Math.random() * app.screen.width,
Math.random() * app.screen.height
], {
radius: 40,
wavelength: 30,
amplitude: 10,
strength: 100,
speed: 200,
waveLength: 100,
}, 0);
// 第三个水波纹滤镜(辅助波纹2)
const waveFilter3 = new ShockwaveFilter([
Math.random() * app.screen.width,
Math.random() * app.screen.height
], {
radius: 40,
wavelength: 30,
amplitude: 10,
strength: 100,
speed: 200,
waveLength: 100,
}, 0);
// 7. 应用所有滤镜
container.filters = [displaceFilter, waveFilter1, waveFilter2, waveFilter3];
// 8. 动画循环
app.ticker.add((delta) => {
// 更新置换贴图位置(创建流动效果)
displaceSprite.position.x += 1;
displaceSprite.position.y += 1;
// 更新各个水波纹滤镜
updateWaveFilter(waveFilter1, 1);
updateWaveFilter(waveFilter2, 1.5);
updateWaveFilter(waveFilter3, 2);
});
// 9. 鼠标点击交互
app.view.addEventListener('click', (e) => {
// 点击时重置第一个水波纹的位置和时间
waveFilter1.center = [e.clientX, e.clientY];
waveFilter1.time = 0;
});
// 10. 窗口大小调整处理
window.addEventListener('resize', () => {
app.renderer.resize(window.innerWidth, window.innerHeight);
sprite.position.set(app.screen.width / 2, app.screen.height / 2 - 300);
text.position.set(app.screen.width / 2, app.screen.height / 2);
});
};
// 更新水波纹滤镜的辅助函数
function updateWaveFilter(filter, resetTime) {
// 更新时间,控制波纹扩散
filter.time += 0.01;
// 重置时间并随机位置
if (filter.time > resetTime) {
filter.time = 0;
filter.center = [
Math.random() * app.screen.width,
Math.random() * app.screen.height
];
}
}
</script>
<style>
.canvas-container {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
overflow: hidden;
}
/* 重置全局样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
overflow: hidden;
}
/* 确保Canvas占满屏幕 */
canvas {
display: block;
width: 100vw;
height: 100vh;
}
</style>
三、核心代码解析
3.1 ShockwaveFilter参数详解
javascript
const waveFilter = new ShockwaveFilter([
centerX, centerY // 波纹中心位置
], {
radius: 180, // 波纹最大半径
wavelength: 30, // 波长,控制波纹间距
amplitude: 10, // 振幅,控制波纹高度
strength: 100, // 强度,影响扭曲程度
speed: 500, // 波纹扩散速度
waveLength: 100, // 初始波长
}, 0); // 初始时间
3.2 随机水波纹实现原理
javascript
// 通过定时重置滤波器中心位置实现随机波纹
function updateWaveFilter(filter, resetTime) {
filter.time += 0.01;
if(filter.time > resetTime) {
filter.time = 0;
// 随机生成新的波纹中心
filter.center = [
Math.random() * app.screen.width,
Math.random() * app.screen.height
];
}
}
3.3 鼠标交互实现
javascript
app.view.addEventListener('click', (e) => {
// 将鼠标点击坐标设置为波纹中心
waveFilter1.center = [e.clientX, e.clientY];
waveFilter1.time = 0; // 重置时间开始新波纹
});
总结
通过本教程,我们学习了:
- Pixi.js基础应用创建:初始化、精灵创建、容器管理
- 滤镜系统使用:ShockwaveFilter水波纹滤镜和DisplacementFilter置换滤镜
- 动画循环实现:使用app.ticker创建动态效果
- 交互功能添加:响应鼠标点击事件
附件
上面使用到了DisplacementFilter置换滤镜,这是需要一张置换滤镜的图片的,在这里附带上了,主要是通过黑白色的图片进行置换.
