我想在(非矩形)形状上创建斜角效果(在canvas
元素中)。搜索了几乎整个互联网:到目前为止没有运气。寻找建议。在我耗尽所有现有可能性之前,我不想自己实施斜面效果。目标浏览器是Chrome。
这是没有应用斜角的图像,以及具有我正在寻找的效果的图像。这是在Photoshop中完成的:
编辑: 我和马克的建议纠缠在一起。 阴影偏移方法的两个问题是:
1)
必须绘制一个边框,我不想要它。
2)
边框的粗细决定了阴影的强度。
我不希望边框可见,所以我需要一种尽可能小的边框,然后切出边框的方法。截至目前,这涉及许多不同的步骤:
1)
首先,我创建一个具有透明填充颜色,边框和轻微阴影(带有(0,0)偏移)和模糊为1的形状。然后我将形状绘制到自身上增加阴影的不透明度。
2)
然后,我创建一个带有透明填充颜色,边框和阴影的形状,如markE所述。我将lineWidth设置为一个非常小的数字 - 例如0.5。我将(1)中的形状应用到此形状上(通过globalCompositeOperation = 'destination-out'
),然后将形状绘制在自身上3次,以增加阴影的不透明度。
3)
然后我绘制正常的形状,没有边框。我将(2)应用到正常形状上,并再次使用globalCompositeOperation = 'destination-out'
从(1)切割出与形状边界的内容。
结果如下:
答案 0 :(得分:6)
首先问题是 - 斜角效应是如何起作用的?
你可能会说斜面效果也是你的平面2d图像的三维效果,它确实存在(好吧,就像物体点亮的方式一样)。
基本上,着色计算就像在一些实际的3d对象上完成一样,但由于你只有2d图像,你还需要一些称为 - 法线贴图。
法线贴图是2d图像,它代替图像中的颜色,在RGB通道中编码了表面法线信息。因此,图像中的每个像素都有RGB分量,R通道用于x方向的表面法线,G用于y方向的法线,B用于法线的z轴分量。
详细了解法线贴图here。
另一种选择是使用凹凸贴图。这是一个图像,而不是像素的颜色或关于法线的信息,保存有关像素“高度”的信息。
详细了解凹凸贴图here。
无论是凹凸贴图还是法线贴图,结果都非常相似。凹凸贴图在图像中只有一个通道(灰度图像),因此它们更容易制作,并且往往更“逼真”,但它取决于您的效果。
以下是方形图像上斜角效果的凹凸贴图示例。
问题是图像通常具有不均匀的形状(如您的示例),那么如何为这些图像创建凹凸贴图?
解决方案是创建一个称为“Eucledian Distance Matrix”的东西。
EDM广泛用于Photoshop中,它们可以保存信息中某些像素远离图像的数量(图层上最近的彩色像素)。 EDM用于抚摸对象和斜角效果。 (有很多资源可用于生成EDM)
例如,在第2行和第2列中只有像素着色的4x4图片的EDM示例如下所示。
1 1 1 2
1 0 1 2
1 1 1 2
2 2 2 3
使用EDM,您可以获取信息在图像“内部”有多少像素,然后根据该信息生成凹凸贴图。
if (isInside(x,y))
if ( dist = innerDistanceAt(x,y) < bevelWidth )
bumpMap[x][y] = dist/bevelWidth;
else
bumpMap[x][y] = 1.0;
这段代码只是一个伪代码示例,但您应该明白这一点。
所以我们现在制作凹凸贴图,是时候计算光照(做阴影)。
有很多可以使用的着色模型 - list。这里有更多的视觉差异 - link。
我将从Lambert模型开始。你可以找到很多关于它的资源。
通常,您需要曲面法线(或凹凸贴图,然后可以从中计算曲面法线(使用微分))和光矢量。根据该信息和漫反射颜色(在这种情况下,图像中的像素颜色),您可以计算该像素的亮度,然后输出着色像素。
我没有发布很多工作代码,因为笔画效果和斜角效果非常复杂,但你应该明白这个想法。这就是他们在照片编辑软件中真正起作用的方式,正如你所看到的,它并不那么容易。
如果您有任何问题,请随时提出。
关于斜角效果的随机链接 - here。
答案 1 :(得分:2)
您可以使用插入阴影创建边框效果。
这个过程很简单:
以下是示例代码和演示:http://jsfiddle.net/m1erickson/4kvLn/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: white; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var points=[];
points.push({x:130,y:130});
points.push({x:200,y:130});
points.push({x:250,y:165});
points.push({x:200,y:200});
points.push({x:130,y:200});
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/landscape2.jpg";
function start(){
definePath();
ctx.save();
ctx.strokeStyle="#000";
ctx.clip();
ctx.drawImage(img,10,0);
ctx.shadowColor = '#000';
for(var i=0;i<3;i++){
for(var j=0;j<3;j++){
ctx.shadowBlur=4+i;
ctx.lineWidth=0.50;
ctx.stroke();
}
}
ctx.restore();
}
function definePath(){
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++){
var pt=points[i];
ctx.lineTo(pt.x,pt.y);
}
ctx.quadraticCurveTo(80,165,130,130);
ctx.closePath();
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>