ThreeJS中使用OBJLoader加载3D模型后无法实现顶点动画的问题
Alright, let's figure out why your vertex animation isn't working with that OBJ model in Three.js. I spot a few common pitfalls in your code snippet—let's break them down and fix this step by step.
First, let's address the core issues with your current approach:
1. You're using outdated Geometry properties with BufferGeometry
OBJLoader in modern Three.js (r125+) loads models using BufferGeometry by default, not the old Geometry type. The verticesNeedUpdate property only applies to the deprecated Geometry—for BufferGeometry, you need to work with attribute arrays instead.
2. You're not updating vertices in an animation loop
Setting verticesNeedUpdate once during model load won't trigger ongoing animation. Vertex changes need to be recalculated every frame in your render loop.
3. Missing checks for Mesh objects
Your traverse call might hit non-Mesh objects (like groups), so you should verify the child is a Mesh before modifying geometry.
Here's the corrected implementation:
var loader = new THREE.OBJLoader(); // Store original vertex data to avoid animation drift let originalPositions = null; loader.load('assets/models/head/lee-perry-smith-head-scan.obj', function (object) { var faceMaterial = getMaterial('standard', 'rgb(255,200,200)'); object.traverse(function(child) { // Target only Mesh objects with the correct name if (child.isMesh && child.name === 'Infinite') { child.material = faceMaterial; // Save original vertex positions (clone the array to preserve defaults) originalPositions = child.geometry.attributes.position.array.slice(); } }); scene.add(object); }); // Add this animation loop (replace with your existing render loop if you have one) function animate() { requestAnimationFrame(animate); // Update vertices every frame scene.traverse(function(child) { if (child.isMesh && child.name === 'Infinite' && originalPositions) { const positionAttribute = child.geometry.attributes.position; const positions = positionAttribute.array; // Example animation: sine wave distortion on Y-axis const time = Date.now() * 0.001; for (let i = 0; i < positions.length; i += 3) { const originalY = originalPositions[i + 1]; // Modify Y position based on time and X coordinate for a wave effect positions[i + 1] = originalY + Math.sin(time + originalPositions[i] * 0.1) * 0.5; } // Tell Three.js the position data has changed positionAttribute.needsUpdate = true; } }); renderer.render(scene, camera); } animate();
Key fixes explained:
- BufferAttribute instead of vertices: We use
child.geometry.attributes.positionto access vertex data, which is the correct approach for modern Three.js. - Original vertex storage: Saving initial positions prevents animation drift (we don't overwrite the base data every frame).
- Animation loop updates: Vertex modifications happen inside the
animatefunction, so they refresh every frame to create smooth motion. needsUpdateflag: SettingpositionAttribute.needsUpdate = trueafter modifying the array tells Three.js to re-render the updated geometry.- Mesh type check: Added
child.isMeshto avoid errors when traversing non-Mesh objects like empty groups.
If you're still stuck, double-check:
- That the child object's name is exactly
'Infinite'(case-sensitive!) - That your
getMaterialfunction returns a validTHREE.Materialinstance - That your animation loop is actually running and calling
renderer.render()every frame
内容的提问来源于stack exchange,提问作者Zain Bokhari

