Three.js关键帧插值问题:缩放设为0时画面异常
Hey there! I totally get why this scaling glitch is frustrating—you’re trying to toggle an object’s visibility by keyframing its scale from 1 to 0, but Three.js’s default interpolation is creating weird in-between frames that mess up your render. Let’s walk through a few solid solutions to fix this:
1. Disable Interpolation for Scale Tracks
The root issue here is that Three.js uses linear interpolation by default between keyframes, so it’s calculating tiny scale values between your 1 and 0 keyframes. To skip those in-between steps, you can switch the interpolation mode to discrete/step interpolation for all scale-related animation tracks:
// After loading your GLTF/FBX model model.animations.forEach(animation => { animation.tracks.forEach(track => { // Target any track that controls an object's scale if (track.name.includes('.scale')) { track.setInterpolation(THREE.InterpolationDiscrete); } }); });
This tells Three.js to jump directly from the 1 scale value to 0 without any smooth transition—no more glitchy intermediate frames.
2. Use Visibility Instead of Scaling to 0
Scaling an object to 0 isn’t the most reliable way to hide it (it can cause rendering oddities like flipped normals or z-fighting). A better approach is to animate the object’s visible property directly. Here’s how to either set this up in your 3D software or convert existing scale animations to visibility animations in Three.js:
Option A: Set Up Visibility Keyframes in Your 3D Tool
In Blender/Cinema 4D, instead of keyframing scale, keyframe the object’s visibility property (e.g., in Blender, toggle the eye icon in the outliner and set keyframes for that state). Export the animation as GLTF/FBX, and Three.js will pick up the visibility tracks automatically.
Option B: Convert Scale Tracks to Visibility Tracks in Code
If you already have scale animations and don’t want to re-export, you can rewrite the animation tracks:
model.animations.forEach(animation => { const updatedTracks = []; animation.tracks.forEach(track => { if (track.name.includes('.scale')) { // Extract the object's name from the track path (e.g., "Cube.scale" → "Cube") const objectPath = track.name.split('.')[0]; // Create a new visibility track that matches your scale keyframes const visibilityTrack = new THREE.BooleanKeyframeTrack( `${objectPath}.visible`, track.times, // Reuse the same keyframe timings track.values.map(scaleValue => scaleValue > 0) // Scale > 0 = visible, else hidden ); updatedTracks.push(visibilityTrack); } else { // Keep non-scale tracks as-is updatedTracks.push(track); } }); animation.tracks = updatedTracks; });
This replaces your scale animation with a clean visibility toggle that has no interpolation issues.
3. Override Keyframe Timings to Eliminate Interpolation
If you absolutely need to use scaling instead of visibility, you can force the two keyframes (scale 1 and scale 0) to occur at the exact same time. This removes any window for interpolation:
model.animations.forEach(animation => { animation.tracks.forEach(track => { if (track.name.includes('.scale')) { // Assuming your keyframes are at times [50, 51] // Set the second keyframe's time to match the first track.times[1] = track.times[0]; // Optimize the track to remove redundant data track.optimize(); } }); });
With both keyframes at the same timestamp, Three.js will jump instantly from scale 1 to 0 without any in-between values.
内容的提问来源于stack exchange,提问作者Christian Tielmann

