p5.js使用curveVertex绘图光标快移时出现异常环路问题
问题根源
curveVertex() 基于Catmull-Rom样条算法实现平滑曲线,计算每段曲线弧度时需要用到段前后各1个参考控制点,出现意外环路、扭曲变形是三个问题共同导致的:
- 绘制路径时没有在首尾重复添加第一个、最后一个锚点,曲线首尾段缺少约束,容易出现无规则偏移
- 鼠标快速移动时,帧间采集的鼠标坐标间距差异极大,Catmull-Rom算法在间距不均的点之间计算时会产生弧度过冲,直接形成异常环路、扭曲
- 当前逻辑每帧无条件记录鼠标坐标,鼠标静止时会重复记录相同位置的点,也会干扰曲线插值计算
修复步骤
1. 补全曲线首尾约束锚点
调用beginShape()后先重复传入一次路径第一个点作为起始控制点,遍历完所有路径点后再重复传入一次最后一个点作为结束控制点,给曲线首尾增加硬约束。
以putDrawings()中的绘制逻辑为例,修改后代码如下:
beginShape(); // 重复首点作为起始控制点 curveVertex(drawings[i][0][0], drawings[i][0][1]); for (let j = 0; j < drawings[i].length; j++) { curveVertex(drawings[i][j][0], drawings[i][j][1]); } // 重复尾点作为结束控制点 curveVertex(drawings[i][drawings[i].length-1][0], drawings[i][drawings[i].length-1][1]); endShape();
drawTrail()中的实时轨迹绘制逻辑也要做相同的首尾点重复处理。
2. 过滤无效采样点
不要每帧都记录鼠标坐标,只有当鼠标和上一个记录点的移动距离超过最小阈值(推荐2像素)时,才把当前坐标加入路径,避免重复点、超大间距点干扰曲线计算。
先在全局变量区定义采样阈值:
const MIN_SAMPLE_DIST = 2;
再修改updateDrawings()逻辑:
function updateDrawings() { if (lastPressed && mouseIsPressed) { const currentPath = drawings[drawings.length - 1]; const lastPoint = currentPath[currentPath.length-1]; const lx = lastPoint[0], ly = lastPoint[1]; const moveDist = Math.hypot(mouseX - lx, mouseY - ly); // 移动距离达标才记录新点 if (moveDist > MIN_SAMPLE_DIST) { currentPath.push([mouseX, mouseY]); } } else if (mouseIsPressed) { drawings.push([[mouseX, mouseY]]); } }
updateTrail()中的轨迹点记录逻辑也要增加相同的距离判断。
3. 可选优化
- 大间距自动补点:如果鼠标移动速度极快,帧间位移超过8像素时,在两点之间线性插入中间点,让采样点分布更均匀,从根源避免弧度过冲
- 调整曲线张力:绘制路径前调用
curveTightness(0.3~0.6),数值越大曲线越贴近直连线段,越不容易出现夸张的弧形环路 - 减少冗余状态切换:绘制路径前统一设置一次
noFill()即可,不需要每次绘制完路径都重设fill()、strokeWeight(),可以降低性能消耗
内容的提问来源于stack exchange,提问作者Brandon Li
相关产品推荐
相关产品推荐

