如何在Voronoi图中平滑插值颜色以消除单元格边界?
消除Voronoi图单元格边界并实现颜色平滑插值的方案
你当前的Voronoi图存在可见单元格边界,原因是每个像素的颜色仅由最近的单个控制点决定,即使做了距离插值,也只是向单一方向过渡,单元格间的颜色衔接会产生突变。要实现平滑的跨单元格颜色插值,需要让每个像素的颜色由多个邻近控制点的颜色加权混合而成,而不是只依赖最近点。

修改思路
- 计算当前像素到所有控制点的带噪声扭曲距离
- 基于距离生成平滑衰减的权重(距离越近,权重越高)
- 用所有权重对对应控制点的颜色进行加权平均,得到当前像素的最终颜色
修改后的代码
function drawVoronoiNoise(canvas, cells = 50, noiseScale = 0.06, distortionStrength = 5) { const ctx = canvas.getContext('2d'); const controlPoints = []; // 生成带随机灰度颜色的控制点 for (let i = 0; i < cells; i++) { const x = seededRandom(i) * canvas.width; const y = seededRandom(i + 1) * canvas.height; const grayValue = noise(x / 188.05, y / 188.05) * 255; controlPoints.push({ x, y, color: { r: grayValue, g: grayValue, b: grayValue } }); } // 遍历画布每个像素 for (let x = 0; x < canvas.width; x++) { for (let y = 0; y < canvas.height; y++) { let totalWeight = 0; let finalColor = { r: 0, g: 0, b: 0 }; const epsilon = 0.1; // 避免除以0 for (const cp of controlPoints) { // 带噪声扭曲的距离计算 const noiseX = noise(x * noiseScale, y * noiseScale) * distortionStrength; const noiseY = noise(x * noiseScale + 100, y * noiseScale + 100) * distortionStrength; const distance = Math.hypot(x - cp.x + noiseX, y - cp.y + noiseY); // 使用平滑衰减的权重(这里用距离倒数的平方,衰减更自然) const weight = 1 / (distance * distance + epsilon); totalWeight += weight; // 累加颜色权重 finalColor.r += cp.color.r * weight; finalColor.g += cp.color.g * weight; finalColor.b += cp.color.b * weight; } // 归一化得到最终颜色 finalColor.r = Math.round(finalColor.r / totalWeight); finalColor.g = Math.round(finalColor.g / totalWeight); finalColor.b = Math.round(finalColor.b / totalWeight); ctx.fillStyle = `rgb(${finalColor.r}, ${finalColor.g}, ${finalColor.b})`; ctx.fillRect(x, y, 1, 1); } } }
关键改动说明
- 权重计算:使用
1/(distance² + epsilon)作为权重,距离控制点越近的像素,该控制点对其颜色的影响越大,且权重平滑衰减,避免突变 - 多控制点混合:每个像素的颜色是所有控制点颜色的加权平均,单元格边界附近的像素会同时受到相邻多个控制点的影响,自然消除硬边界
- 灵活调整过渡效果:如果需要更柔和的过渡,可以改用高斯函数
Math.exp(-distance² / (2 * sigma²))作为权重;想要稍锐利的过渡,可改用1/(distance + epsilon)计算权重
内容的提问来源于stack exchange,提问作者Memory1
相关产品推荐
相关产品推荐

