2013-05-08 106 views
1

我想写一个算法(在C#中),将两个或更多不相关的高度图缝合在一起,因此地图之间没有可见的接缝。基本上我想模仿这个网页上找到的功能: http://www.bundysoft.com/wiki/doku.php?id=tutorials:l3dt:stitching_heightmaps如何缝合多个高度图以去除接缝?

(你可以只看图片得到的,我说的是什么要点)

我也希望能够采取一个单一的高度图,并改变它,以便它可以平铺,以创建一个无尽的世界(所有这些都用于Unity3d)。但是,如果我可以将多个高度图拼接在一起,我应该可以轻松修改算法以在单个高度图上执行操作,所以我不担心这部分。

任何类型的指导将不胜感激,因为我已经搜索和搜索解决方案没有成功。只是在正确的方向简单微调将不胜感激!我了解许多图像处理技术可以应用于高度贴图,但一直无法找到能够产生我期待的结果的图像处理算法。例如,image stitching似乎只适用于具有重叠视野的图像,对于不相关的高度图不是这种情况。

会在某种程度上使用FFT低通滤波器工作,还是只能用于生成单个tileable高度图?

由于该算法将在Unit3d中使用,因此任何C#代码都必须局限于.Net 3.5,因为我相信这是Unity使用的最新版本。 感谢您的帮助!

回答

1

好吧,似乎我是在正确的轨道上与我以前的尝试解决这个问题。我最初尝试将高度贴拼接在一起涉及到heightmap上每个点的以下步骤:

1)找到高度图上的一个点与其相对点之间的平均值。相反的点只是在x轴(如果缝合水平边缘)或z轴(用于垂直边缘)上反射的第一个点。

newHeight = oldHeight + (average - oldHeight)*((maxDistance-distance)/maxDistance); 

其中距离是从在高度图到最近的水平或垂直边缘的点的距离(取决于哪个边缘要:

2)使用下面的公式找到该点的新的高度缝合)。根据此公式调整距离小于maxDistance的点(这是一个影响地形多少的可调整值)。

这是旧的公式,虽然它在大多数地形上都产生了非常好的结果,但它在变化的高度图点区域和未改变的高度图点区域之间的区域中创建了明显的线条。我几乎立即意识到发生了这种情况,因为与未改变的区域相比,改变区域的坡度太陡,因此在两者之间形成了明显的对比。不幸的是,我以错误的方式解决了这个问题,寻找解决方案来解决如何模糊或平滑对比区域以消除线条。

在平滑技术取得很小的成功之后,我决定尝试减小变化区域的斜率,希望能够更好地与未改变区域的斜率相融合。我很高兴地报告,这大大改进了我的拼接算法,去掉了上面报告的99%的线条。

从旧式的主要元凶是这一部分:

(maxDistance-distance)/maxDistance 

将其线性地基于点到最近的边缘之间的距离产生0和1之间的值。随着高度图点与边缘之间的距离增加,高度图点将利用越来越少的平均值(如上所定义的),并且越来越多地移向它们的原始值。这种线性插值是导致斜率太大的原因,但幸运的是我在Unity API的Mathf类中找到了一种内置方法,允许二次(我相信三次)插值。这是SmoothStep Method。使用这种方法(我相信类似的方法可以在Xna框架找到here),在确定高度图值时使用多少平均值的变化在中等距离变得非常严重,但是严重程度减轻了指数级地,距离越接近maxDistance,产生一个不太严重的斜率,与未改变区域的斜率更好地融合。新的论坛看起来像这样:

//Using Mathf - Unity only? 
float weight = Mathf.SmoothStep(1f, 0f, distance/maxDistance); 

//Using XNA 
float weight = MathHelper.SmoothStep(1f, 0f, distance/maxDistance); 

//If you can't use either of the two methods above 
float input = distance/maxDistance; 
float weight = 1f + (-1f)*(3f*(float)Math.Pow(input, 2f) - 2f*(float)Math.Pow(input, 3f)); 

//Then calculate the new height using this weight 
newHeight = oldHeight + (average - oldHeight)*weight; 

可能有更好的插值方法,产生更好的拼接。如果我找到这样的方法,我肯定会更新这个问题,所以其他想要进行高度贴图拼接的人都可以找到他们需要的信息。用线性插值方式在正确的轨道上获得荣誉ruthwound的荣誉!

0

你发布的图像中做了什么看起来很像我简单的线性插值。 所以基本上:你拍两张图像(左,右)并定义拼接区域。对于线性插值,可以将左图像的最左像素(拼接区域中)和右图像的最右像素(也在拼接区域中)。然后用填充值填充它们之间的空格。

拿这个例子 - 我使用的是单线这里要说明的想法:

Left = [11,11,11,10,10,10,10] 
Right= [01,01,01,01,02,02,02] 

比方说我们的重叠是4个像素宽:

Left = [11,11,11,10,10,10,10] 
Right=   [01,01,01,01,02,02,02] 
       ^^^^ overlap/stitiching region. 

左侧的左值图像将为10 右图像的最右边值为1. 现在我们在2和10之间线性插值,我们的新拼接区域如下所示

stitch = [10, 07, 04, 01] 

我们结束了以下缝合线:

line = [11,11,11,10,07,04,01,02,02,02] 

如果应用此两个完整的图像,你应该得到类似于您发布之前什么结果。

+0

好的,我明白你在说什么,但是你会如何将它应用于高度图?在您的示例中,生成的缝合线的长度为10,但合并后,最初的左和右线条的长度为14.我需要生成与原始左/右线条长度相同的新左/右线条,左边的最右边的值与右边的最左边的值匹配(如果它们不是相同的值,那么heightmaps之间会有差距)。 – 2013-05-08 16:18:05

+0

感谢您的帮助,插值绝对在正确的轨道上。我添加了一个答案,迄今为止产生了最好的结果。将自己的答案标记为问题的答案是否可以,或者通常是否被忽视? – 2013-05-09 03:18:21