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

Three.js中如何让THREE.Points同步变形目标动画?

Answer

Great question—this is a super common gotcha with morph targets in Three.js, since they apply deformations directly on the GPU without modifying the original geometry's CPU-side data. Let's break down your options clearly:


1. Alternative Solutions (Beyond CPU Calculation)

The best alternatives all leverage GPU-side morphing to keep performance high, avoiding costly CPU vertex updates:

  • Custom ShaderMaterial for Points: Since THREE.PointsMaterial doesn't natively support morph targets, you can extend the built-in points shader to include morph target logic. This lets your points deform on the GPU in sync with the cube, no CPU overhead.
  • Reuse the Mesh's Morph Target Data: The loaded cube's geometry already contains all the shape key vertex offsets—you just need to make your points material use that data.

2. Efficiently Sync Points with Cube Morph Animation

The optimal approach is to make your THREE.Points use GPU-based morph targets, mirroring how the cube mesh works. Here's a step-by-step implementation:

Step 1: Ensure Geometry Includes Morph Targets

When you load your Blender model (exported with shape keys enabled), the resulting BufferGeometry will have a morphTargets array containing the shape key vertex data.

Step 2: Create a Morph-Aware Points Shader

We'll extend Three.js's built-in points shader to handle morph targets. This way, we reuse the existing points rendering logic while adding deformation support:

// Assume you've loaded your cube mesh as `cubeMesh`
const geometry = cubeMesh.geometry;

// Clone the built-in points shader uniforms and add morph influences
const pointShader = THREE.ShaderLib.points;
const uniforms = THREE.UniformsUtils.clone(pointShader.uniforms);
uniforms.morphTargetInfluences = { value: cubeMesh.morphTargetInfluences }; // Reuse the cube's influence array

// Modify the vertex shader to apply morph target deformations
const vertexShader = `
  uniform float morphTargetInfluences[ NUM_MORPH_TARGETS ];
  ${pointShader.vertexShader.replace(
    '#include <begin_vertex>',
    `
      #include <begin_vertex>
      // Apply morph target deformations
      #ifdef USE_MORPHTARGETS
        vec3 morphed = vec3(0.0);
        float totalWeight = 0.0;
        for (int i = 0; i < NUM_MORPH_TARGETS; i++) {
          float influence = morphTargetInfluences[i];
          if (influence > 0.0) {
            morphed += (morphTargets[i].attributes.position.xyz - position) * influence;
            totalWeight += influence;
          }
        }
        transformed += morphed * smoothstep(0.0, 1.0, totalWeight);
      #endif
    `
  )}
`;

// Create the shader material with morph target defines
const pointMaterial = new THREE.ShaderMaterial({
  uniforms: uniforms,
  vertexShader: vertexShader,
  fragmentShader: pointShader.fragmentShader,
  transparent: true,
  defines: {
    USE_MORPHTARGETS: '',
    NUM_MORPH_TARGETS: geometry.morphTargets.length.toString()
  }
});

// Create your points with the modified material
const points = new THREE.Points(geometry, pointMaterial);
scene.add(points);

Step 3: Sync the Animation

Since we're reusing cubeMesh.morphTargetInfluences directly in the points material's uniforms, any changes you make to the cube's influence values will automatically propagate to the points:

// Example animation loop
function animate() {
  requestAnimationFrame(animate);
  // Update the cube's morph influence (same affects points)
  cubeMesh.morphTargetInfluences[0] = (Math.sin(Date.now() * 0.001) + 1) / 2;
  renderer.render(scene, camera);
}
animate();

What If You Need CPU-Side Deformed Geometry?

If you absolutely need the CPU-side deformed vertex data (e.g., for collision detection), you can compute it efficiently in batches using BufferAttribute methods, but note this will still have performance costs for large geometries:

const originalPos = geometry.attributes.position.array;
const morphPos = geometry.morphTargets[0].attributes.position.array;
const influence = cubeMesh.morphTargetInfluences[0];

// Update the points' position attribute directly
const updatedPos = points.geometry.attributes.position.array;
for (let i = 0; i < originalPos.length; i += 3) {
  updatedPos[i] = originalPos[i] + (morphPos[i] - originalPos[i]) * influence;
  updatedPos[i+1] = originalPos[i+1] + (morphPos[i+1] - originalPos[i+1]) * influence;
  updatedPos[i+2] = originalPos[i+2] + (morphPos[i+2] - originalPos[i+2]) * influence;
}
points.geometry.attributes.position.needsUpdate = true;

This is only recommended if GPU-side morphing isn't feasible for your use case.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:22:27