新博客:https://yinl.fun
欢迎关注,同步更新html
Prelin噪声由Ken Perlin在1983年提出,因参与制做迪士尼的动画电影《电子世界争霸战》,但不满于当时那种很是不天然的纹理效果,而提出了Perlin噪声
本篇文章借鉴各路大神的文章总结而来:git
此文章源码在个人我的GitHub上,本文章的仅仅实现了Prelin噪声中的最简单版本。上图先~github
candycat的文章很是好,不过没有Unity的具体实现代码,而则卷大明的文章中只给出了一部分的代码。最后发现了Unity自带2D噪声,因此结合多方文章最终完成了最简单的Prelin噪声。函数
若是你懂GLSL的pixel shaders,那你就能够直接去阅读由iq大神写的:Voronoise。而这里我只是用Unity代码还原冯乐乐博客中利用shaderToy编写的代码动画
在开始正文以前,咱们得知道几个数学小知识。图形学中涉及矩阵计算的东西有太多,在ShaderToy中都有封装,而Unity并无,因此咱们得实现几个图形学函数spa
Floor:向下取整.net
private static Vector2 Floor(Vector2 p) { return new Vector2(Mathf.Floor(p.x), Mathf.Floor(p.y)); }
Fract:取小数部分3d
private static Vector2 Fract(Vector2 p) { return p - Floor(p); }
Sin:正弦函数code
private static Vector2 Sin(Vector2 p) { return new Vector2(Mathf.Sin(p.x), Mathf.Sin(p.y)); }
其实这些函数在Unity中也有实现,不过我这里要实现2D的噪声,因此得处理2D状况下的操做。接下来就是正片了~
首先还原冯乐乐博客中的梯度函数htm
private static Vector2 Hash22(Vector2 p) { p = new Vector2(Vector2.Dot(p, new Vector2(127.1f, 311.7f)), Vector2.Dot(p, new Vector2(269.5f, 183.3f))); return new Vector2(-1, -1) + 2.0f * Fract(Sin(p) * 43758.5453123f); }
而后还原缓和曲线,这里利用新提出的缓和曲线,使其在二阶的状况下也能知足连续性,公式以下:
\(s(t)=6*t^5-15*t^4+10*t^3\)
// 一阶 private static float GetEaseCurves(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } // 二阶 private static Vector2 GetEaseCurves(Vector2 p) { return new Vector2(GetEaseCurves(p.x), GetEaseCurves(p.y)); }
这里将冯乐乐中的-1.0f改成Unity中可计算的Vector(-1, -1)
接下来是生成prelin噪声的主函数了
public static float prelin_noise(Vector2 p) { Vector2 pi = Floor(p); Vector2 pf = p - pi; Vector2 w = GetEaseCurves(pf); float corner1 = Vector2.Dot(Hash22(pi + Vector2.zero), pf - Vector2.zero); float corner2 = Vector2.Dot(Hash22(pi + Vector2.right), pf - Vector2.right); float corner3 = Vector2.Dot(Hash22(pi + Vector2.up), pf - Vector2.up); float corner4 = Vector2.Dot(Hash22(pi + Vector2.one), pf - Vector2.one); return Mathf.Lerp(Mathf.Lerp(corner1, corner2, w.x), Mathf.Lerp(corner3, corner4, w.x), w.y); }
到这里咱们完成了2D Prelin噪声的构建,加下来就是怎么利用噪声生成贴图并转成PNG存储起来~
下面的代码生成了一个噪声的贴图而且返回
private int width = 512; // 贴图宽度 private int height = 512; // 贴图高度 private float xOrg = 0f; // 宽度偏移起点 private float yOrg = 0f; // 高度偏移起点 private float scale = 15f; // 周期 private Texture2D CreateTexture() { Texture2D tex = new Texture2D(width, height); Color[] pix = new Color[width * height]; float y = 0f; while (y < height) { float x = 0f; while (x < width) { float xCoord = xOrg + x / width * scale; float yCoord = yOrg + y / height * scale; float sample = PrelinNoise.prelin_noise(new Vector2(xCoord, yCoord)); pix[(int)y * width + (int)x] = new Color(sample, sample, sample); x++; } y++; } tex.SetPixels(pix); tex.Apply(); return tex; }
下面的函数将贴图转换成PNG图片存储到特定位置
private bool SaveTexture(Texture2D tex, string path) { if (File.Exists(path)) { Debug.LogWarning("已有文件"); return false; } if (tex == null) { Debug.LogWarning("贴图为空"); return false; } // 贴图转换为PNG图片 byte[] texData = tex.EncodeToPNG(); // 若是没有目录则建立目录 int index = path.LastIndexOf('/'); string dir = path.Remove(index); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } // 贴图存储 File.WriteAllBytes(path, texData); return true; }
后续还会陆续更新Sample噪声,分型噪声等利用Unity实现的方式