Three.js:如何缩放圆但不缩放其描边?
解决方案:运行时缩放TubeGeometry生成的描边圆
嘿,这个问题我太有共鸣了——直接碰Tube的顶点确实会一脸懵,因为那些顶点是路径细分+厚度偏移后的结果,和原路径完全不是一回事。给你两个实用的方向,看哪种更贴合你的需求:
方案1:复用原路径曲线,高效更新几何体
如果你觉得“重新创建TubeGeometry”不算完全不可接受,其实可以通过复用原路径的曲线对象,把开销降到最低:
首先创建的时候,保存好原始的圆形曲线引用,而不是只存Path:
// 保存核心曲线对象,方便后续修改 const circleCurve = new THREE.CircleCurve(0, 0, 5, 0, Math.PI * 2); const path = new THREE.Path(circleCurve.getPoints(64)); // 描边厚度设为你需要的值 const tubeGeo = new THREE.TubeGeometry(path, 64, 0.3, 8, true); const strokeCircle = new THREE.Mesh(tubeGeo, new THREE.MeshBasicMaterial({ color: 0xff0000, transparent: true, opacity: 0.8, side: THREE.DoubleSide })); scene.add(strokeCircle);
运行时缩放时,只需要修改曲线的半径,然后重新生成几何体(注意释放旧资源):
// 比如要缩放到半径10 circleCurve.radius = 10; // 更新路径的曲线 path.curves[0] = circleCurve; // 释放旧几何体资源,避免内存泄漏 strokeCircle.geometry.dispose(); // 用更新后的路径生成新几何体 strokeCircle.geometry = new THREE.TubeGeometry(path, 64, 0.3, 8, true);
这个方法代码简洁,对于简单的圆形来说,性能开销几乎可以忽略,而且完全保留描边厚度的可控性。
方案2:直接操作顶点,完全避免重建几何体
如果你的场景对性能要求极高,不想碰几何体重建,可以直接计算并修改Tube的顶点。核心思路是:把每个顶点拆分为「路径上的基准点」和「描边偏移向量」,只缩放基准点,保留偏移向量的长度(这样描边厚度不变):
先在初始化时保存原始半径和描边厚度:
const initialRadius = 5; const strokeThickness = 0.3; // 初始化TubeMesh的代码和上面一样...
运行时缩放的代码:
const targetRadius = 10; const scaleRatio = targetRadius / initialRadius; const positionAttr = strokeCircle.geometry.attributes.position; const vertices = positionAttr.array; for (let i = 0; i < vertices.length; i += 3) { const x = vertices[i]; const y = vertices[i + 1]; // 计算当前顶点到圆心的距离(原始路径上的基准点距离) const originalDist = Math.sqrt(x * x + y * y); // 得到基准点的方向向量 const dirX = x / originalDist; const dirY = y / originalDist; // 计算原始基准点的位置(减去偏移向量) const originalBaseX = dirX * initialRadius; const originalBaseY = dirY * initialRadius; // 计算描边的偏移向量(保持长度不变) const offsetX = x - originalBaseX; const offsetY = y - originalBaseY; // 缩放后的基准点 + 原始偏移 = 新顶点位置 vertices[i] = dirX * targetRadius + offsetX; vertices[i + 1] = dirY * targetRadius + offsetY; } // 标记顶点属性需要更新,Three.js才会重新渲染 positionAttr.needsUpdate = true; // 如果用了受法线影响的材质,还要重新计算法线 strokeCircle.geometry.computeVertexNormals();
这个方法完全不用重建几何体,直接修改底层顶点数据,性能最优,而且完美保持描边厚度不变。
避坑提醒
别用mesh.scale来缩放——这会把描边厚度也一起缩放,破坏你原本“描边厚度可控”的需求。
内容的提问来源于stack exchange,提问作者Filip Petrovic
相关产品推荐
相关产品推荐

