如何为Three.js 3D对象(球体几何体)设置固定尺寸?
解决Three.js球体随视图缩放尺寸变化的问题
要让球体像地图标记一样在缩放视图时保持屏幕尺寸不变,有两种实用方案:
方案1:使用Sprite(推荐,简单高效)
Sprite是面向相机的2D精灵,天生不会随相机透视缩放改变屏幕大小,适合做标记类元素。可以用Canvas生成圆形纹理模拟球体效果:
// 生成圆形纹理 const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 64; const ctx = canvas.getContext('2d'); // 绘制白色填充、红色描边的圆形 ctx.beginPath(); ctx.arc(32, 32, 30, 0, Math.PI * 2); ctx.fillStyle = '#ffffff'; ctx.fill(); ctx.strokeStyle = '#ff0000'; ctx.lineWidth = 2; ctx.stroke(); // 创建纹理和精灵材质 const texture = new THREE.Texture(canvas); texture.needsUpdate = true; const spriteMaterial = new THREE.SpriteMaterial({ map: texture, depthTest: false, depthWrite: false }); // 创建精灵并设置位置 const marker = new THREE.Sprite(spriteMaterial); marker.position.copy(SomeVector3Object); // 调整精灵的屏幕大小(根据需求修改) marker.scale.set(0.5, 0.5, 1); scene.add(marker);
方案2:动态调整Mesh缩放(适合必须用3D模型的场景)
如果一定要用Sphere Mesh,需要在动画循环中根据相机到球体的距离实时计算缩放比例,抵消透视带来的大小变化:
// 原球体初始化代码(补全材质的闭合括号) let sphereGeometry = new THREE.SphereGeometry(0.4, 10, 10); let sphereMaterial = new THREE.MeshLambertMaterial({ color: '#ffffff', depthTest: false, depthWrite: false }); let sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); sphere.position.copy(SomeVector3Object); sphere.visible = true; scene.add(sphere); // 在动画循环中更新缩放 function animate() { requestAnimationFrame(animate); // 计算相机与球体的距离 const distance = camera.position.distanceTo(sphere.position); // 设定球体在屏幕上的目标高度(单位:像素) const targetScreenHeight = 50; // 将相机视场角转为弧度 const fovRad = THREE.MathUtils.degToRad(camera.fov); // 计算缩放因子,抵消透视效果 const scaleFactor = (targetScreenHeight / window.innerHeight) * distance / Math.tan(fovRad / 2); // 应用缩放(保持球体比例) sphere.scale.setScalar(scaleFactor); renderer.render(scene, camera); } animate();
额外提示
- 若使用正交相机(
OrthographicCamera),物体默认不会随距离改变大小,无需额外处理;上述方案针对透视相机(PerspectiveCamera)。 - 原代码存在语法错误:
MeshLambertMaterial的初始化缺少闭合的});,需要补全。
内容的提问来源于stack exchange,提问作者Aakash Govardhane
相关产品推荐
相关产品推荐

