Three.js中sin()/cos()动画导致网格重叠问题求解
Three.js立方体运动重叠问题解决建议
我是JavaScript和Three.js新手,很高兴认识大家!
这段代码用于创建4个立方体和1个箭头,初始效果为四个立方体均匀分布在圆周路径上,箭头位于中心区域。
// Scene const scene = new THREE.Scene(); // Groups const cubes = new THREE.Group(); // Ambient Light const light = new THREE.AmbientLight(0xffffff, 1); scene.add(light) // Reference Circle or Path const circle = new THREE.CircleGeometry(5, 100) const stroke = new THREE.LineBasicMaterial({color : 'white'}) const ref = new THREE.Line(circle, stroke) scene.add(ref) // Mesh const geometry = new THREE.BoxGeometry(1, 1, 1) const material = new THREE.MeshBasicMaterial({ color: 'red' }) const mesh = new THREE.Mesh(geometry, material) // Mesh 2 const geometry2 = new THREE.BoxGeometry(1, 1, 1) const material2 = new THREE.MeshBasicMaterial({ color: 'blue' }) const mesh2 = new THREE.Mesh(geometry2, material2) // Mesh 3 const geometry3 = new THREE.BoxGeometry(1, 1, 1) const material3 = new THREE.MeshBasicMaterial({ color: 'green' }) const mesh3 = new THREE.Mesh(geometry3, material3) // Mesh 4 const geometry4 = new THREE.BoxGeometry(1, 1, 1) const material4 = new THREE.MeshBasicMaterial({ color: 'purple' }) const mesh4 = new THREE.Mesh(geometry4, material4) // Mesh 5 Arrow const geometry5 = new THREE.ConeGeometry(1, 4, 3) const material5 = new THREE.MeshBasicMaterial({ color: 'yellow' }) const arrow = new THREE.Mesh(geometry5, material5) scene.add(mesh, mesh2, mesh3, mesh4, arrow) const axesHelper = new THREE.AxesHelper(); scene.add(axesHelper) // Camera const aspect = { width: window.innerWidth, height: window.innerHeight } const camera = new THREE.PerspectiveCamera(75, aspect.width / aspect.height) camera.position.x = -0.15; camera.position.z = 10; scene.add(camera) // Renderer const canvas = document.querySelector('.draw') const renderer = new THREE.WebGLRenderer({ canvas }); renderer.setSize(aspect.width, aspect.height) renderer.render(scene, camera) const clock = new THREE.Clock(); const animate = () => { const time = clock.getElapsedTime() const a = time; let px; let pz; let r = 5; px = r * Math.cos(a); pz = r * Math.sin(a); mesh.position.set(px, pz, 0); mesh.rotation.x = time * Math.PI * 0.1; mesh.rotation.y = time * Math.PI * 0.3; mesh2.position.set(px, pz, 0); mesh2.rotation.x = time * Math.PI * 0.1; mesh2.rotation.y = time * Math.PI * 0.3; mesh3.position.set(px2, pz, 0); // 此处px2未定义,属于代码bug mesh3.rotation.x = time * Math.PI * 0.1; mesh3.rotation.y = time * Math.PI * 0.3; mesh4.position.set(px, pz, 0); mesh4.rotation.x = time * Math.PI * 0.1; mesh4.rotation.y = time * Math.PI * 0.3; arrow.rotation.y = time * Math.PI * 0.7; renderer.render(scene, camera) window.requestAnimationFrame(animate) } animate();
我遇到的问题是,当animate()循环启动时,所有几何体都重叠在一起,四个立方体和箭头挤在同一位置。请问有什么解决重叠的建议吗?比如添加某种延迟,但我不知道如何实现。我曾考虑为每个立方体创建4个循环,但程序运行效果不符合预期。请问有什么方法可以为每个网格添加延迟以避免重叠吗?
问题分析
当前代码中所有立方体使用相同的时间变量time计算位置,导致它们的坐标完全一致,自然会重叠。此外代码中mesh3用到的px2未定义,属于语法错误,需要先修正。
解决方法
方法1:角度偏移法(推荐)
让每个立方体在圆周上的运动角度相差固定值,这样它们会始终均匀分布在圆周上,不会重叠。四个立方体刚好可以各差90°(即Math.PI/2弧度):
修改animate函数如下:
const animate = () => { const time = clock.getElapsedTime() const r = 5; // 四个立方体的角度偏移量,依次相差90° const angleOffsets = [0, Math.PI/2, Math.PI, 3*Math.PI/2]; // 将立方体存入数组,循环处理减少重复代码 const cubes = [mesh, mesh2, mesh3, mesh4]; cubes.forEach((cube, index) => { // 每个立方体的运动角度 = 当前时间 + 偏移量 const currentAngle = time + angleOffsets[index]; const px = r * Math.cos(currentAngle); const pz = r * Math.sin(currentAngle); cube.position.set(px, pz, 0); cube.rotation.x = time * Math.PI * 0.1; cube.rotation.y = time * Math.PI * 0.3; }); arrow.rotation.y = time * Math.PI * 0.7; renderer.render(scene, camera) window.requestAnimationFrame(animate) }
方法2:延迟启动法
如果需要让立方体依次启动,可以给每个立方体的运动时间减去不同的延迟值,避免初始时重叠:
const animate = () => { const time = clock.getElapsedTime() const r = 5; // 每个立方体的延迟时间,单位秒 const delays = [0, 0.5, 1, 1.5]; const cubes = [mesh, mesh2, mesh3, mesh4]; cubes.forEach((cube, index) => { // 确保时间不为负,避免初始位置异常 const delayedTime = Math.max(0, time - delays[index]); const currentAngle = delayedTime; const px = r * Math.cos(currentAngle); const pz = r * Math.sin(currentAngle); cube.position.set(px, pz, 0); cube.rotation.x = delayedTime * Math.PI * 0.1; cube.rotation.y = delayedTime * Math.PI * 0.3; }); arrow.rotation.y = time * Math.PI * 0.7; renderer.render(scene, camera) window.requestAnimationFrame(animate) }
额外优化建议
- 复用几何体和材质:四个立方体的几何体和材质参数完全一致,可以只创建一份,然后实例化多个Mesh,减少内存占用:
const geometry = new THREE.BoxGeometry(1, 1, 1); const cubes = [ new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'red' })), new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'blue' })), new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'green' })), new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'purple' })) ]; cubes.forEach(cube => scene.add(cube));
内容的提问来源于stack exchange,提问作者user27057540
相关产品推荐
相关产品推荐

