程序化无缝噪点纹理生成器






4.98/5 (39投票s)
一些程序化位图创建算法的演示和测试。
更新
我在您可以在以下位置找到的工具中使用了本文的基础: https://sites.google.com/site/noiselab15/
引言
在一些涉及运行时行星生成的工作中,我遇到了程序化无缝纹理生成。在运行时创建行星,管理无缝纹理至关重要。无缝纹理可用作灰度高度图和/或地形纹理和/或大气效果。
在网上搜索时,我发现了一些众所周知的技术,例如 Perlin 噪点(http://en.wikipedia.org/wiki/Perlin_noise)或分形噪点。
因此,我决定整理一个 C#“沙盒”小型项目,以实验一些纹理生成算法、测试性能等。特别是,我使用网络资源(稍后会提供参考)实现了一个 Perlin 噪点生成器,然后我创建了一些递归算法,在我看来,这些算法可以与 Perlin 达到令人满意的效果,而且性能成本较低。 在这里,我将分享一些内容。
背景
我通过研究以下网络资源实现了 Perlin 噪点:http://www.sepcot.com/blog/2006/08/PDN-PerlinNoise2d 和 http://freespace.virgin.net/hugo.elias/models/m_perlin.htm 。我不会解释 Perlin 噪点,第一个原因是我的理解程度不足以比以上链接解释得更好。
在继续之前,还有另一件(这次很简单)有用的事情是了解什么是灰度图像以及它在定义高度图方面有多有用。同时,了解如何使用图像的 alpha 通道也很有用,例如为预设的天空添加云。
基本思想是在图像的一个随机子区域上绘制一个浅灰色矩形 (我们称之为“方框”),覆盖该子区域。之后,我们在第一个方框的中心附近计算 n 个随机点,然后缩小方框大小(例如减半),并对 n 个小方框重复此操作。每次绘制一个方框时,我们都会将其灰度增量添加到现有像素中。
在下面的序列中,我们从 2 次递归调用开始,到 20 次递归调用结束。对于最后一个图像,我们重复 7 次,并将灰度增量减小,以便较大的方框消失。
最终,创建的纹理是无缝且完美可平铺的
使用代码
Contoli 噪点的核心递归方法非常简单
//
// CONTOLI NOISE
private void printQuad(float [,] Values, int wid, int hei,int x, int y, int boxSize, int deepness, int delta) {
if (deepness > 0 && boxSize>=1)
{
for (int i = -boxSize/2; i < boxSize/2; i++)
{
for (int j = -boxSize / 2; j < boxSize / 2; j++)
{
/*seamless management start*/
int pixX = (x + i) % wid;
int pixY = (y + j) % hei;
if (pixX < 0)
pixX = wid + pixX;
if (pixY < 0)
pixY = wid + pixY;
/*seamless management end*/
Values[pixX, pixY] = Values[pixX, pixY] + delta; // add value
Iterations++;
}
int xx = r.Next(x, x + boxSize);
int yy = r.Next(y, y + boxSize);
printQuad(Values, wid, hei, xx, yy, boxSize / 2, --deepness, delta);
}
}
}
//
其中:
Values
是表示图像像素的二维浮点数组
wid
和 hei 是图像的尺寸
x
和 y 是方框的中心点坐标
boxSize
是矩形的大小
deepness
是当前的递归深度
delta
是添加到现有值上的灰度值。(它代表高度增量)
停止递归:
if (deepness > 0 && boxSize>=1)
如果我们递归太深或方框大小达到零,我们将停止递归。
调用它:
r = getrRandom(); //r is public Random class accessed by all methods for (int nr = 0; nr < N_Repetitions; nr++) { //get a random point int x = r.Next(0, wid - 1); int y = r.Next(0, hei - 1); printQuad(Values, wid, hei, x, y, box_size, Godeep, d); } updBitmap(Values, tmp, grayScale.Checked); pictureBox1.Image = tmp; pictureBox1.Refresh();
updBitmap
将 Values 数组转换为灰度位图。
getRandom
初始化 printQuad
内部使用的随机数生成器。
N_Repetitions
不言自明。
应用程序
Contoli 噪点方法
Quad:最简单的,已经讨论过;
Circ:绘制圆形而不是矩形,我们可以在保持递归深度较低的情况下获得更好的效果;
Func;绘制一个 2 变量函数而不是矩形。当前函数是 Torus(http://en.wikipedia.org/wiki/Torus)。
Quad(左)与 Circ(右):
Torus 示例:1 次递归深度 vs 33 次递归深度。
一般说明:增加“递归”值时,最好减小“颜色增量”值。
使用 printFunc
代码。
//TORUS f func = (x1,y1) => (float)Math.Sqrt((0.4f * 0.4f - Math.Pow((0.6f - Math.Sqrt(x1 * x1 + y1 * y1)), 2)));//TORUS printFunc(Values, wid, hei, x, y, box_size, Godeep, d,func); useValueArray = true; break;
printFunc
接受一个函数 f
委托。如果您不喜欢 Torus,可以根据需要重新定义它。
抛物面示例
f func = (x1,y1) => 1f + (float) ((x1*x1)/1f + (y1*y1)/1f) * -1f; //PARABOLOID
在“距离算法”部分,我展示了一系列算法,用于使用基于距离一组随机点的技术在位图上生成效果。这仍在进行中。
Voronoi 图
在 Voronoi 部分,我们可以尝试一些基于 Voronoi 思想的程序化空间镶嵌实现的。基本思想是:1) 在平面上取一组随机点 S;2) S 中的每个点“s”定义平面上的一个区域“r”,其中区域“r”中的每个点都离点“s”最近(解释起来比理解难);3) 使用一些随机颜色(灰度)为每个区域(或区域边界)着色;4) 添加一些编码以使所有内容“无缝”
示例
代码
private void Voronoi(float[,] Values, int wid, int hei, int[,] points)
{
for (int i = 0; i < wid; i++)
{
for (int j = 0; j < hei; j++)
{
float minDist = Math.Min(wid,hei);
int minV = 0;
for (int p = 0; p < points.GetLength(0); p++) {
int pX = points[p, 0];
int pY = points[p, 1];
int pV = points[p, 2]; //0..255
Double Dist1X = Math.Abs((i - pX));
Double Dist1Y = Math.Abs((j - pY));
Double Dist2X = wid - Dist1X;
Double Dist2Y = hei - Dist1Y;
/*to grant seamless I take the min between distX and wid-distX
| |
| | ----------- = Dist1X
|...i-----------X.......| .......... = Dist2X
| |
*/
Dist1X = Math.Min(Dist1X, Dist2X);
/*to grant seamless I take the min between distY and hei-distY*/
Dist1Y = Math.Min(Dist1Y, Dist2Y);
float dist = (float)Math.Sqrt(Math.Pow(Dist1X, 2) + Math.Pow(Dist1Y, 2));
if (dist < minDist) {
minDist = dist;
minV = pV;
}
}
Values[i, j] = minV;
Iterations++;
}
}
}
3D 噪点
进入 3D。我添加了一个 Contoli 噪点和 Voronoi 噪点的 3D 实现。要测试它,只需点击“开始 3D 噪点”,等待一段时间(取决于参数),然后欣赏。
一些解释,在这种情况下,第三个维度是时间,所以我们得到一个“动画”噪点。如果比较 printQuad3D
和 printQuad
,您会发现第三个维度的管理。显而易见,第三个维度也是无缝的,并且允许动画循环播放而没有切断。
动画演示链接
Quad 3D 噪点
https://www.youtube.com/watch?v=cVnhmmPVSf8
Circ 3D 噪点:
https://www.youtube.com/watch?v=cFVYq_cS5C4
https://www.youtube.com/watch?v=7qPrKBut6qY
Voronoi 动画
https://www.youtube.com/watch?v=GnR6dLPxvNc
https://www.youtube.com/watch?v=uihClJuwqz8
https://www.youtube.com/watch?v=TpkrNQe4guQ
https://www.youtube.com/watch?v=CfpY8saDa9U
历史
First version.
2014 年 11 月 9 日:添加了 VORONOI 部分。
2014 年 11 月 12 日:添加了 3D 噪点部分。
2014 年 11 月 14 日:添加了 3D 噪点演示 YouTube 链接