hcwanz 发表于 2023-12-27 14:29:11

[着色.源码]单形噪声(simplex noise)

本帖最后由 hcwanz 于 2023-12-27 14:34 编辑

    前文讲的方形噪声,其原理就是先划分出以不同(相邻方形有两个不同的顶点)随机值随机的区域;再根据每个点坐标,平滑每个点的随机值(改进版则同时对每个随机值进行再处理,以得到每个点都不同的随机值)。
    这里面存在一个重要的性能浪费,方形并不是顶点最少的形状,二维方面这不算大问题,因为比之最少的三角形,我们仅多计算一个随机值;但到了三维时代,这个问题就尤为严重了,立方体需要八个顶点,也就是我们要计算八个随机值,而四面体,则仅有四个顶点。也就是说,在三维计算上,方形会多做一半的运算。
    因此就有了单形噪声,他更为抽象复杂,所以这一次的学习不会向上次那般顺利。
    我找了三个实现源码,都是优化完的结果,很难看出实现思路,而且三兄弟完全不一样。
    这三优化的有多彻底呢?有一些猜不出意义的数字,还不能改,推测是一些计算的结果,作者直接算好了填进去的;
    那么有多不一样呢?这些数字值不一样、出现的位置也不一样。
    换言之他们完全是基于不同的代码优化而来。(崩溃啊)

    还是谈谈原理和实现思路吧。
    我们的屏幕、窗口、计算、乃至相应的数学,都是基于直角坐标系构建的,所以直角构成的方形,依然有很重要的地位。
    我们还是需要通过方形获取坐标数据,然后把方形划分为两个等腰直角三角形。这一过程相当简单,如下图所示,在斜线的上的点,其横纵坐标相等。而横>纵的,就在右三角,横<纵的,就在左三角。

    现在我们得到了点所在的等腰三角形,但等腰三角形根本不能进行统一的计算。为此我们需要把它转换为可以进行统一运算的全等三角形。(如上图)
    我们贴心的作者已经在代码里帮我们把这一切优化到面目全非了,所以想深入了解这一方面的人,可以百度单形噪声。别问我,没有代码纯看公式真搞不懂。
    还有一点要讲的是,计算三角形三个点时,以左下角的顶点为相对基准点;其上的中间点,由判断处于那个三角形的时候计算得到的;最后一个点必然是基准点加(1,1)。
    剩下的也没啥好讲的了,都难在代码里,我直接附代码图和代码吧。


hcwanz 发表于 2023-12-27 14:30:04

// 原作者的所有噪声作品:
// https://www.shadertoy.com/playlist/fXlXzf&from=0&num=12
#版 450
同 粗二 外屏幕;
同 粗二 外鼠位;
同 逻二 外鼠按;
同 粗数 外时间;
/*这只是一个平平无奇的散列方法,你可以用更好的代替*/
粗二 哈希( 粗二 位置 ){
    位置 = 粗二( 点积(位置,粗二(127.1,311.7)), 点积(位置,粗二(269.5,183.3)) );
    返 -1.0 + 2.0*取小(正弦(位置)*43758.5453123);
}

粗数 噪声(粗二 位置 ){
/*我说的,极致优化部分,只需要知道跟这两相关的都是为了转换的*/
    常 粗数 到钝 = 0.366025404; // (根(3)-1)/2;
    常 粗数 到直 = 0.211324865; // (3-根(3))/6;
//原点:所在三角形的基准顶点。
    粗二 原点 = 退整(位置 + 点积(位置,粗二(到钝)));
//点原:转回直角系后,所在三角形原点的坐标
    粗二 点原 = 位置 - 原点 + 点积(原点,粗二(到直));
//所在:为了判断当前三角形在左还是右
//独点:当前位置所在三角形独有的顶点的相对于原点的坐标
///被注释掉的是原码,我觉得下面的更好理解
///    粗数 所在 = 跃阶(点原.纵,点原.横);
///    粗二 独点 = 粗二(所在,1.0-所在);
    粗二 独点 =(0.0==跃阶(点原.纵,点原.横)?粗二(0,1)
                                          :粗二(1,0));
//独点是三角独有点,(1,1)是三角共有点
    粗二 点独 = 点原 - 独点 + 到直;
///    点独 = 点原 - 独点 + 点积(独点,到直)
    粗二 点共 = 点原 - 1.0 + 2.0*到直;
///    点共 = 点原 - 1.0 + 点积(粗二(1),到直)

//0.5是全等三角形的一个顶点到对边最短的距离吧。
//此计算下的三角形最长边为1,用0.5可以把顶点对所有点的影响权重框定在中
    粗三 距权 = 较大(0.5-粗三(点积(点原,点原),
                              点积(点独,点独),
                              点积(点共,点共)),0.0);
//上面的是衰减方法,如果不用的话,我们会得到一堆三角形
//参数一的这几个点,应该是对应点的距离权重(点积)
//参数二的则是计算对应点的随机数
    粗三 噪 = 距权*距权*距权*距权;

      噪 *= 粗三(点积(点原,哈希(原点+0.0)),
                   点积(点独,哈希(原点+独点)),
                   点积(点共,哈希(原点+1.0)));
    返 点积(噪, 粗三(70.0));
}
无 主(){
    粗二 位置 = 像位置.横纵 / 外屏幕.横纵;
/*前半为了使画出的图像为正方形,后为了使图像动态移动*/
    粗二 坐标 = 位置*粗二(外屏幕.横/外屏幕.纵,1.0) + 外时间*0.25;

    粗数 结果 = 0.0;

    若( 位置.横<0.6 ){
      // 左图:单个值噪声
      结果 = 噪声( 16.0*坐标 );
   }则{
      // 右图:分形噪声(基于四个值噪声)//本身就可开一门的东西,以后可能讲吧
      坐标 *= 5.0;
      阵二 m = 阵二( 1.6,1.2, -1.2,1.6 );
      结果= 0.5000*噪声( 坐标 ); 坐标 = m*坐标;
      结果 += 0.2500*噪声( 坐标 ); 坐标 = m*坐标;
      结果 += 0.1250*噪声( 坐标 ); 坐标 = m*坐标;
      结果 += 0.0625*噪声( 坐标 );
    }

    结果 = 结果*0.5 + 0.5;//为了把值限制在[-0.5,0.5]

    结果 *= 线阶( 0.0, 0.005, 取正(位置.横-0.6));//这里是为了画黑线

    像颜色 = 粗四( 结果, 结果, 结果, 1.0 );
}

hcwanz 发表于 2023-12-27 14:38:22

今天这个有点潦草,不过大家不用担心。
下一个帖子,我们还要学习另一种思路的更为复杂的单形噪声。

火绒 发表于 2023-12-27 22:54:46

厉害,希望能继续更新
页: [1]
查看完整版本: [着色.源码]单形噪声(simplex noise)