You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JS结合pixi.js实现自定义图片的布料/果冻拉伸交互效果

基于PixiJS实现图片拉伸(果冻/布料)交互效果方案

核心实现思路

不需要引入额外物理引擎,基于网格变形+简单弹簧物理模型即可实现目标效果:

  • 首先把目标图片拆解为顶点网格,不直接操作整张图片,而是将图片分割为N行N列的三角形网格,每个顶点存储初始坐标、当前坐标、运动速度三个属性
  • 给所有顶点绑定弹簧物理规则:顶点距离初始位置越远,受到的回弹拉力越大,同时加入阻尼系数避免无限回弹
  • 监听鼠标交互事件:按下时检测距离鼠标最近的网格顶点,绑定为跟随顶点,鼠标移动时带动该顶点偏移,松开后顶点自动回弹到初始位置

关键实现步骤

1. 初始化网格纹理

使用PixiJS内置的SimplePlane类快速创建可变形网格:

// 已提前创建PIXI.Application实例app
const texture = PIXI.Texture.from('目标图片资源路径');
// 定义网格行列数,数值越高变形越细腻,对应性能消耗越高
const plane = new PIXI.SimplePlane(texture, 20, 20);
app.stage.addChild(plane);

// 存储所有顶点的初始坐标,用于回弹计算
const originalPositions = plane.geometry.attributes.position.array.slice();
// 初始化顶点速度数组,用于物理计算
const velocities = new Array(originalPositions.length).fill(0);

2. 绑定鼠标交互事件

let draggingVertexIndex = -1;
const vertexSnapThreshold = 15; // 鼠标吸附顶点的检测距离阈值

plane.interactive = true;
// 鼠标按下时寻找最近的绑定顶点
plane.on('pointerdown', (e) => {
  const mouseLocalPos = e.data.getLocalPosition(plane);
  const positions = plane.geometry.attributes.position.array;
  let minDistance = Infinity;
  for (let i = 0; i < positions.length; i += 2) {
    const dx = positions[i] - mouseLocalPos.x;
    const dy = positions[i + 1] - mouseLocalPos.y;
    const distance = Math.hypot(dx, dy);
    if (distance < minDistance && distance < vertexSnapThreshold) {
      minDistance = distance;
      draggingVertexIndex = i;
    }
  }
});

// 鼠标移动时更新拖拽顶点位置
app.stage.on('pointermove', (e) => {
  if (draggingVertexIndex === -1) return;
  const mouseLocalPos = e.data.getLocalPosition(plane);
  const positions = plane.geometry.attributes.position.array;
  positions[draggingVertexIndex] = mouseLocalPos.x;
  positions[draggingVertexIndex + 1] = mouseLocalPos.y;
  plane.geometry.attributes.position.update();
});

// 鼠标松开时解除拖拽绑定
app.stage.on('pointerup pointerupoutside', () => {
  draggingVertexIndex = -1;
});

3. 加入弹簧物理回弹效果

在PixiJS的帧更新ticker中添加物理计算逻辑:

// 物理参数,可根据需求调整质感
const stiffness = 0.05; // 弹簧刚度,数值越大回弹速度越快
const damping = 0.92; // 阻尼系数,数值越小回弹衰减越快

app.ticker.add(() => {
  // 拖拽状态下不触发回弹计算
  if (draggingVertexIndex !== -1) return;
  const positions = plane.geometry.attributes.position.array;
  
  for (let i = 0; i < positions.length; i += 2) {
    // 计算当前顶点和初始位置的偏移量
    const offsetX = originalPositions[i] - positions[i];
    const offsetY = originalPositions[i + 1] - positions[i + 1];
    
    // 计算弹簧拉力对应的加速度
    const accelerationX = offsetX * stiffness;
    const accelerationY = offsetY * stiffness;
    
    // 更新顶点速度
    velocities[i] += accelerationX;
    velocities[i + 1] += accelerationY;
    velocities[i] *= damping;
    velocities[i + 1] *= damping;
    
    // 更新顶点坐标
    positions[i] += velocities[i];
    positions[i + 1] += velocities[i + 1];
  }
  // 提交顶点更新到渲染器
  plane.geometry.attributes.position.update();
});

效果优化建议

  • 若要实现更自然的布料效果,可以给相邻顶点添加联动约束:单个顶点偏移时,带动周边一定范围内的顶点做等比例小幅度偏移,避免单个顶点拉扯过于突兀
  • 网格行列数按需调整:图标类小尺寸图片用1010网格即可,大尺寸背景图建议控制在3030以内,避免性能损耗过高
  • 通过调整物理参数切换效果:刚度调低、阻尼调低是软质布料效果,刚度调高、阻尼调到0.9左右是Q弹果冻效果

内容的提问来源于stack exchange,提问作者sirotkin37

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 18:27:03