我正在寻找一种算法,可以使用alpha作为凹凸贴图向位图添加斜角效果。

我将如何做这样的事情?我尝试了镜面照明,但只得到高光而不是阴影。

这是我正在谈论的效果(使用Photoshop制作):


>所有这些操作都使用size: 30px(从位图轮廓开始的斜角深度),angle 130altitude 50完成。

从左到右,从上到下:


凿子硬斜角
凿子软斜角
光滑斜角
凿子硬斜角soften: 16px-模糊的斜角?

我正在尝试创建每一个效果,我将如何创建基本斜角?而我需要从斜面中得到每个这些

#1 楼

这可以通过距离变换的卷积来实现。

在蒙版的边缘使用距离变换。然后对该距离变换进行阈值处理,以删除超出某个距离的值。我认为获取阴影的秘诀是将距离转换结果与看起来像这样的内核进行卷积:

[ -1.0  -1.0  -1.0
  -1.0   0.0   0.0
  -1.0   0.0   1.0 ]


这应该使您朝着正确的方向开始:

#include "opencv/cv.h"
#include "opencv/highgui.h"

using namespace cv;
using namespace std;

int main() {
    Mat mask, dist, bevel;
    mask = Mat::zeros(200, 400, CV_8U);
    rectangle(mask, Point(30,30), Point(180,180), Scalar(255), -1);
    circle(mask, Point(30,30), 50, Scalar(0), -1);
    circle(mask, Point(180,180), 50, Scalar(0), -1);
    circle(mask, Point(300,100), 75, Scalar(255), -1);
    imshow("1",mask);




    //find edges and invert image for distance transform
    Canny(mask, dist, 50, 150);
    dist = 255-dist;
    distanceTransform(dist, dist, CV_DIST_L2, CV_DIST_MASK_5);
    threshold(dist, dist, 20, 20, CV_THRESH_TRUNC);
    blur(dist, dist, Size(3,3));
    dist.convertTo(bevel, CV_8U);
    equalizeHist(bevel, bevel);
    imshow("2",bevel);




    //convolve with secret sauce
    float d[] = {-1,-2,-3,
                 -2, 0, 0,
                 -3, 0, 1 };
    Mat kernel(3, 3, CV_32F, d);
    kernel = kernel - mean(kernel)[0];
    filter2D(dist, dist, CV_32F, kernel);

    //normalize filtering result to [-1, 1]
    double maxVal;
    minMaxLoc(dist, NULL, &maxVal);
    dist = 128 * dist / maxVal;

    //convert and display result
    dist.convertTo(bevel, CV_8U, 1, 128);
    bevel = bevel.mul(mask)/255;
    imshow("3", bevel);




    waitKey(0);
}


评论


$ \ begingroup $
看起来很棒!柔化的表面看起来像是模糊的,但是我该如何用它们制作“平滑的斜面”呢?
$ \ endgroup $
– Shedokan
2011年10月29日10:36



$ \ begingroup $
我相信“平滑斜角”会在卷积之前模糊距离蒙版,而“柔化”会在卷积之后模糊结果。
$ \ endgroup $
– Matt M.
2011年10月30日,0:51

#2 楼

Photoshop的Bevel and Emboss可预测地工作:

1)计算临时8位单通道图像中的距离变换


Chisel使用具有倒角度量标准(3x3、5x5或7x7,取决于大小)。如果需要,您可以使用精确的欧几里德距离变换,我更喜欢Meijster的方法,因为它可以进行抗锯齿(“线性时间中计算距离变换的通用算法”,MEIJSTER)。
平滑倒角使用倒角5-7-11距离变换,然后两次应用盒子模糊,以生成凹凸贴图。

2)将凹凸贴图应用于中间距离变换图像。 Blinn的原始技术很合适。

3)要进行软化处理,可以对表面法线进行卷积,也可以使用内核对其进行滤波。

4)使用凹凸贴图表面法线与全局光源组合以计算照明强度,其值为-1到1,其中负值为阴影,正值为高光,绝对值为光源的大小。

5)计算了两个8位单通道临时图像,一个来自高光强度,另一个来自阴影。从那里开始,使用每个蒙版使用颜色,混合模式和不透明度对图层进行着色很简单-一个蒙版用于高光,另一个蒙版用于阴影。

Visual Basic源代码可以在这里找到实现这些功能的方法:

http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=51640&lngWId=1

请访问我的开源LayerEffects项目以了解更多信息:

https://github.com/vinniefalco/LayerEffects.git

我希望这对某人有帮助。

评论


$ \ begingroup $
谢谢,我对您提到的高斯距离变换非常感兴趣,您知道可用的任何代码吗?我无法很好地阅读公式。 :(
$ \ endgroup $
– Shedokan
2012年10月13日21:00

$ \ begingroup $
除了我已经发布的信息之外,我没有找到任何有关GDT的信息。
$ \ endgroup $
– Vinnie Falco
2012年10月13日23:54

$ \ begingroup $
“ 2)将凹凸贴图应用于距离变换图像”是什么意思?距离变换给出距离(每个像素1个数字),而凹凸贴图需要法线(每个像素2个数字)...您确定知道您在说什么吗?
$ \ endgroup $
–伊万·库基(Ivan Kuckir)
15年2月13日在18:03

$ \ begingroup $
@IvanKuckir我应该更加清楚-可以通过将距离变换视为高度图并从相邻的垂直和水平值计算dx / dy来计算表面法线。这两个数字提供了凹凸贴图所需的法线。
$ \ endgroup $
– Vinnie Falco
15年2月16日在19:17