这是一个示范:
var ctx = document.getElementById("test").getContext("2d");
ctx.shadowColor = "black";
ctx.fillStyle = "white";
ctx.shadowBlur = 10;
ctx.fillRect(10, 10, 10, 10);
ctx.shadowBlur = 50;
ctx.fillRect(70, 10, 10, 10);
ctx.fillRect(70, 70, 70, 70);

<canvas id="test" width="200" height="200"></canvas>
&#13;
如果我设置shadowBlur=10
然后绘制一个小的10x10正方形,我会得到一个漂亮,强烈的阴影。如果我设置shadowBlur=50
并绘制一个70x70大的正方形,则相同。但如果我设置shadowBlur=50
然后绘制一个小的10x10正方形,我会得到一个非常微弱,几乎看不见的阴影。
相反,我会期待一个小的中心广场和周围的大阴影。
显然我误解了阴影模糊是如何工作的,所以 - 它是如何工作的,以及如何在一个小物体周围得到一个大的暗影?
答案 0 :(得分:3)
shadowBlur
使用高斯模糊在内部产生阴影。对象被绘制为单独的位图,如阴影颜色中的模板,然后使用半径模糊。在此步骤之后,它不使用原始形状。结果是合成的(作为旁注:以前在如何合成阴影方面存在分歧,因此Firefox和Chrome / Opera以不同的方式呈现它们 - 我认为它们现在已经在source-over
落在两个阵营中了)
如果物体非常小且模糊半径非常大,则物体周围的空余空间会使平均值变薄,留下更暗淡的阴影。
使用内置方法获得更明显阴影的唯一方法是使用更小的半径。你也可以使用径向渐变“作弊”,或绘制一个更大的物体,阴影应用于离屏画布,但相对于阴影本身偏移,因此对象不会重叠,然后仅绘制阴影(使用剪切参数)在绘制主要对象之前,使用drawImage()
)以所需大小返回主画布。
在较新版本的浏览器中,您还可以使用CSS过滤器在上下文中使用新的filter
属性手动生成高斯模糊阴影。它确实需要一些额外的合成步骤,并且很可能是大多数场景下的屏幕外画布,但是你可以使用这种方法在多个步骤中过度渲染阴影,从小到大可变半径,以某种性能为代价产生更明显的阴影。 / p>
filter
:这允许更复杂的形状,如内置阴影,但可以更好地控制最终结果。在这种情况下,“衰减”可以通过在循环内使用具有初始归一化半径值的缓动函数来控制。
// note: requires filter support on context
var ctx = c.getContext("2d");
var iterations = 16, radius = 50,
step = radius / iterations;
for(var i = 1; i < iterations; i++) {
ctx.filter = "blur(" + (step * i) + "px)";
ctx.fillRect(100, 50, 10, 10);
}
ctx.filter = "none";
ctx.fillStyle = "#fff";
ctx.fillRect(100, 50, 10, 10);
<canvas id=c></canvas>
gradient
+ filter
的示例:这是一个更加跨浏览器友好的解决方案,好像不支持过滤器,至少渐变接近可接受的阴影。唯一的缺点是它在复杂的形状方面更受限制。
此外,对渐变使用可变中心点可以模拟衰减,光照大小,光照类型等。
基于@Kaiido的评论示例/ mod -
// note: requires filter support on context
var ctx = c.getContext("2d");
var grad = ctx.createRadialGradient(105,55,50,105,55,0);
grad.addColorStop(0,"transparent");
grad.addColorStop(0.33,"rgba(0,0,0,0.5)"); // extra point to control "fall-off"
grad.addColorStop(1,"black");
ctx.fillStyle = grad;
ctx.filter = "blur(10px)";
ctx.fillRect(0, 0, 300, 150);
ctx.filter = "none";
ctx.fillStyle = "#fff";
ctx.fillRect(100, 50, 10, 10);
<canvas id=c></canvas>