我的专栏目录:
小IVan:专题概述及目录![图标](https://i-blog.csdnimg.cn/blog_migrate/d6ea8e09530a242b2ee5802be9b6a242.png)
本篇概述:
程序化纹理有着很多好处,第一可以方便修改,当我们的生成逻辑写好后,想要调整的话就是调调参数的事情。第二就是思路清晰,这张图是怎么来的,逻辑非常清晰,而不是传统的图像绘制,画到哪儿想到哪儿,思维是游走的,离散的。第三我们可以实时生成,可以让纹理和玩家产生互动等等。
现在主流的是用Substance来生成,但是其实引擎也能做,引擎本来就是用来操作这些素材的地方。想看引擎和Substance的对接的话可能你要失望了,对于目前的Substance而言,我个人极力反对目前版本的Substance和引擎直接结合。本章将在引擎里实现各种程序化纹理,不管是离线烘焙也好,还是实时生成也罢。
程序化纹理篇的大概规划是,先把程序化生成需要的节点我们自己全部开发一次,然后把这些工具节点撸好以后在开始用这些工具做纯程序化的纹理(在引擎中)。我们的核心目的是把材质编辑器拓展成引擎内置的“Substance”,像Substance一样能有几何生成,图像转换等功能。当然拓展材质编辑器有很多种办法,不止改引擎一个。
在开始本篇之前最好能熟练使用Substance软件。欢迎各路大神斧正错误。
Substance有很多噪波生成器,下面将从最基础的噪波开始,把Substance有的或者没有的噪波生成节点全部在Unreal种实现。使用噪波的组合,我们能做出很多效果。
要生成一个噪声,我们一般需要三步,第一步是构造随机发生器,第二步是插值,第三步是叠加。
噪声从生成方式上可以分为几种:
(1)white noise
(2)perlin noise
(3)value noise
(4)worley noise
【1】Fast Noise(White Noise)
效果:
![v2-51e046a6b761b3b20b8b58ce28ca3ff0_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/3c8d58c3624f1c677b65e03923cec422.jpeg)
公式代码:
float RandFast( uint2 PixelPos, float Magic = 3571.0 )
{
float2 Random2 = ( 1.0 / 4320.0 ) * PixelPos + float2( 0.25, 0.0 );
float Random = frac( dot( Random2 * Random2, Magic ) );
Random = frac( Random * Random * (2 * Magic) );
return Random;
}
材质:
![v2-fbe7579ecc83e5fcec6af23bc6c3f052_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/e78d4eefd3ababa7e3fd22bd7285fd8a.jpeg)
其实为啥这个算法是这样呢,并没有为啥,就是拟合得好所以就这样了。我把这些常用的函数封装到材质函数节点里,以后做程序化纹理的时候就能直接用了。
![v2-3cf7e9e4b4faa839dc2c09e9069a2067_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/c6730b60e99d5408b0ee13e1835ec1c2.png)
![v2-3ee20596f1daa66279fc48d53daf110a_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/8b95a93df73bef3b6d651e54101a45e5.jpeg)
后面的很多介绍里的很多这种公用逻辑都会这样做,做完这些只会我们就能建立一个自己的工具库,就像Substance那样。这时有人就要说了,我们不是有noise节点么,为啥还要自己写呢?其实我们应该更多靠自己,我们需要知道原理之后才能根据需求来改进它和精进它,而不是一直拿来主义。
这一步就是只做了构造随机发生器这一步。
【2】Random With Scale(White Noise)
这种是对上面的改进,加入缩放因素,可以让我们做出棋盘格之类的纹理
效果:
![v2-51e20fa1b1647d4e5d509cca96d772ca_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/a946f0de9b3c33493e300812d3c26cd8.jpeg)
代码:
float2 Random(float2 uv)
{
float Magic = 3571;
float2 PixelPos = uv * 512;
float2 Random2 = ( 1.0 / 4320.0 ) * PixelPos + float2( 0.25, 0.0 );
float Random = frac( dot( Random2 * Random2, Magic ) );
Random = frac( Random * Random * (2 * Magic) );
return Random;
}
float main(float2 uv)
{
return Random(floor(uv * 50));
}
材质:
![v2-3b376f44ae4f903a52b05887501685e7_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/36a81467eb2e1d4c8337756a3026dfe2.jpeg)
![v2-9100bb7e94fa10d4303c3508013ac600_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/fab5ce82a1642c14f390762aa3dfecc1.jpeg)
【3】Perlin Noise
想要生成柏林噪声,需要做以下几步:
(1)定义晶格,每个晶格的顶点有一个“伪随机”的梯度向量(其实就是个向量啦)。对于二维的Perlin噪声来说,晶格结构就是一个平面网格,三维的就是一个立方体网格。
(2)输入一个点(二维的话就是二维坐标,三维就是三维坐标,n维的就是n个坐标),我们找到和它相邻的那些晶格顶点(二维下有4个,三维下有8个,n维下有 个),计算该点到各个晶格顶点的距离向量,再分别与顶点上的梯度向量做点乘,得到
个点乘结果。
(3)使用缓和曲线来计算它们的权重和。
以二维为例主要代码如下(解释看注释)
//随机数
float2 hash22(float2 p)
{
p = float2( dot(p,float2(127.1,311.7)),
dot(p,float2(269.5,183.3)));
return -1.0 + 2.0 * frac(sin(p) * 43758.5453123);
}
//构造perlin noise,输入一个点
float perlin_noise(float 2p)
{
//生成第二步:构建晶格
float2 pi = floor(p);
float2 pf = p - pi;
float2 w = pf * pf * (3.0 - 2.0 * pf);
//生成第三步:使用缓和曲线
return lerp(lerp(dot(hash22(pi + float2(0.0, 0.0)), pf - float2(0.0, 0.0)),
dot(hash22(pi + float2(1.0, 0.0)), pf - float2(1.0, 0.0)), w.x),
lerp(dot(hash22(pi + float2(0.0, 1.0)), pf - float2(0.0, 1.0)),
dot(hash22(pi + float2(1.0, 1.0)), pf - float2(1.0, 1.0)), w.x),
w.y);
}
把单一的perlin noise进行叠加即可出现很多有趣的效果。下面几个是多层叠加的柏林噪波
效果:
Noise itself