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

Three.js渲染过程中如何调整动画运行速度

Three.js平面顶点动画平滑减速解决方案

你当前代码动画速度过快、过渡生硬的核心原因是每帧都为所有顶点生成全新的随机z值,没有过渡过程,视觉上呈现为快速闪烁跳变。setTimeout只会降低渲染帧率,不会改变z值跳变的逻辑,因此无法实现平滑放缓的效果。

下面提供两种可直接落地的实现方案:

方案一:插值过渡+定时更新目标值(易实现,可控性强)

实现逻辑

为每个顶点维护「当前z值」和「目标z值」两个变量,仅间隔固定时间更新一次目标值,每帧让当前z值缓慢向目标值靠拢,实现平滑过渡。

代码修改

  1. 初始化部分新增变量:
const geometry = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
const material = new THREE.MeshBasicMaterial( { side: THREE.DoubleSide, wireframe: true } );
const mesh = new THREE.Mesh( geometry, material );
const positions = geometry.attributes.position.array;
scene.add(mesh);

// ----- 以下为新增代码 -----
// 存储每个顶点的当前z值和目标z值
const vertexCount = geometry.attributes.position.count;
const currentZ = new Array(vertexCount).fill(0);
const targetZ = new Array(vertexCount).fill(0);
// 平滑过渡速度:取值0~1,数值越小过渡越慢
const smoothSpeed = 0.02;
// 目标值更新间隔:单位毫秒,数值越大整体动画节奏越慢
const updateInterval = 500;
let lastUpdateTime = Date.now();
  1. 修改render函数的顶点更新逻辑:
function render() {
  mesh.rotateZ(0.001)
  const geoArray = geometry.attributes.position;
  const now = Date.now();

  // 仅到间隔时间才更新所有顶点的目标z值
  if (now - lastUpdateTime > updateInterval) {
    for (let i = 0; i < geoArray.count; i++) {
      targetZ[i] = Math.round(Math.random() * -2);
    }
    lastUpdateTime = now;
  }

  // 每帧让当前z值向目标z值线性插值
  for (let i = 0; i < geoArray.count; i++) {
    currentZ[i] += (targetZ[i] - currentZ[i]) * smoothSpeed;
    geoArray.setZ(i, currentZ[i]);
  }

  mesh.geometry.attributes.position.needsUpdate = true;
  camera.updateProjectionMatrix()
  renderer.render(scene, camera)
}

方案二:噪声函数驱动连续动画(效果更自然)

实现逻辑

用连续的Perlin/Simplex噪声函数,输入顶点索引和时间参数生成连续变化的z值,天然没有跳变,调整时间系数就能直接控制动画速度,视觉效果更自然流畅。

代码示例

// 动画速度系数,数值越小变化越慢
const noiseSpeed = 0.0005;

function render() {
  mesh.rotateZ(0.001)
  const geoArray = geometry.attributes.position;
  const time = Date.now() * noiseSpeed;

  for (let i = 0; i < geoArray.count; i++) {
    // 用噪声生成连续z值,映射到你需要的-2~0范围
    const noiseVal = THREE.MathUtils.smoothstep(THREE.MathUtils.randFloat(-1, 1), -1, 1);
    // 也可以替换为你引入的Perlin/Simplex噪声函数,效果更好
    const z = (noiseVal * 0.5 - 0.5) * 2;
    geoArray.setZ(i, Math.round(z));
  }

  mesh.geometry.attributes.position.needsUpdate = true;
  camera.updateProjectionMatrix()
  renderer.render(scene, camera)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 14:27:03