围绕多边形绘制渐变斜面

Draw gradient bevel around polygon

基本上我需要为给定的多边形创建衰减纹理。例如这是我的图像

我需要创建的是这个,但是从白色到黑色的斜角渐变,将绿色部分视为渐变。

我得到了所有顶点的坐标和斜面的厚度。我正在使用 HTML5 2d canvas 进行渲染。基本上最明显的解决方案是计算每个像素到多边形的距离,如果它在厚度参数内,则计算颜色并为像素着色。但这是繁重的计算,而且会很慢,即使对于满足我需要的尽可能小的纹理也是如此。那么我可以用 canvas 来实现这个目标吗?

只需以不同的笔画宽度绘制多边形的轮廓,并根据宽度的每一步改变颜色。

该片段展示了一种实现方法。使用线连接 "miter" 和 "round"

绘制 2 个多边形

 "use strict";

const canvas = document.createElement("canvas"); 
canvas.height = innerHeight;
canvas.width = innerWidth;
canvas.style.position = "absolute"; 
canvas.style.top = canvas.style.left = "0px";
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);

// poly to draw
var poly = [0.1,0.2,0.4,0.5,0.2,0.8];
var poly1 = [0.6,0.1,0.9,0.5,0.8,0.9];

// convert rgb style colour to array
function rgb2Array(rgb){
    var arr1 = rgb.split("(")[1].split(")")[0].split(",");
    var arr = [];
    while(arr1.length > 0){
        arr.push(Number(arr1.shift()));
    }
    return arr;
}
// convert array to rgb colour
function array2rgb(arr){
    return "rgb("+Math.floor(arr[0])+","+Math.floor(arr[1])+","+Math.floor(arr[2])+")"
}

// lerps array from to. Amount is from 0 @ from 1 @ to. res = is the resulting array
function lerpArr(from,to,amount,res){
    var i = 0;
    if(res === undefined){
        res = [];
    }
    while(i < from.length){
        res[i] = (to[i]-from[i]) * amount + from[i];    
        i++;
    }
    return res;
}

// draw gradient outline
// poly is the polygon verts
// width is the outline width
// fillStyle is the polygon fill style
// rgb1 is the outer colour
// rgb2 is the inner colour of the outline gradient
function drawGradientOutline(poly,width,fillStyle,rgb1,rgb2){
    ctx.beginPath();
    var i = 0;
    var w = canvas.width;
    var h = canvas.height;
    ctx.moveTo(poly[i++] * w,poly[i++] * h);
    while(i < poly.length){
        ctx.lineTo(poly[i++] * w,poly[i++] * h);
    }
    ctx.closePath();
    var col1 = rgb2Array(rgb1);
    var col2 = rgb2Array(rgb2);
    
    i = width * 2;
    var col = [];
    while(i > 0){
        ctx.lineWidth = i;
        ctx.strokeStyle = array2rgb(lerpArr(col1,col2,1- i / (width * 2),col));
        ctx.stroke();
        i -= 1;
    }
    ctx.fillStyle = fillStyle;
    ctx.fill();
}
ctx.clearRect(0,0,canvas.width,canvas.height)
ctx.lineJoin = "miter";
drawGradientOutline(poly,20,"black","rgb(255,0,0)","rgb(255,255,0)")
ctx.lineJoin = "round";
drawGradientOutline(poly1,20,"black","rgb(255,0,0)","rgb(255,255,0)")