获取CatmullRomCurve3曲线上原始控制点的0-1参数位置
获取CatmullRomCurve3控制点的参数位置并生成分段点
嘿,这个需求我刚好折腾过!要实现你想要的效果,其实分两步走就好:先找到每个原始控制点对应的曲线参数t(范围0到1),然后基于这些t值在相邻控制点的区间里生成等分的分段点。
第一步:获取原始控制点对应的参数t
Three.js的CatmullRomCurve3内部用参数u对应控制点的索引(比如第i个控制点对应u=i),而我们需要把这个u映射到曲线的标准参数t(0到1)。直接用曲线自带的getUtoTmapping(u, distance)方法就能搞定——这个方法会根据你设置的参数化方式(默认是centripetal,也可设为uniform或chordal),准确计算出对应控制点的t值。
代码示例:
// 假设你已经有了points数组和curve实例 const curve = new THREE.CatmullRomCurve3(points); // 生成每个原始控制点对应的t值数组 const controlPointTs = points.map((_, index) => curve.getUtoTmapping(index, 0));
这里controlPointTs[0]肯定是0(对应第一个点),controlPointTs[points.length-1]肯定是1(对应最后一个点),中间的t值会根据曲线的参数化规则自动计算,比手动假设线性分布要准确得多。
第二步:在相邻控制点间生成等分分段点
有了每个控制点的t值后,就可以在每一对相邻的t区间里,按指定的分段数生成点了。比如你要在每两个相邻控制点之间生成10个分段,那每个区间需要11个点(包括两端),然后去掉重复的端点(前一个区间的终点就是后一个区间的起点)。
写个工具函数实现这个逻辑:
function generateSegmentedPoints(curve, segmentsPerInterval) { // 先拿到所有控制点对应的t值 const controlPointTs = curve.points.map((_, idx) => curve.getUtoTmapping(idx, 0)); const segmentedPoints = []; // 遍历每一对相邻的控制点t值 for (let i = 0; i < controlPointTs.length - 1; i++) { const tStart = controlPointTs[i]; const tEnd = controlPointTs[i + 1]; // 计算每个分段的t步长 const step = (tEnd - tStart) / segmentsPerInterval; // 生成当前区间的所有点(包括起点) for (let j = 0; j <= segmentsPerInterval; j++) { const currentT = tStart + step * j; segmentedPoints.push(curve.getPointAt(currentT)); } // 除了最后一个区间,都去掉重复的终点(避免和下一个区间的起点重复) if (i !== controlPointTs.length - 2) { segmentedPoints.pop(); } } return segmentedPoints; } // 使用示例:每个相邻控制点间生成10个分段 const finalPoints = generateSegmentedPoints(curve, 10);
补充说明
- 如果你的曲线设置了
closed: true(闭合曲线),最后一个控制点的t值不会是1,这时候需要调整逻辑——不过从你的描述来看,应该是开放曲线(第一个点对应0,最后一个对应1),所以不用管这个情况。 - 曲线的参数化方式会影响
t值的分布:uniform是均匀分布,chordal基于弦长,centripetal基于弦长的平方根,getUtoTmapping会自动适配你设置的方式,不用手动计算。
内容的提问来源于stack exchange,提问作者Marcoq
相关产品推荐
相关产品推荐

