hcwanz 发表于 2023-12-23 15:25:07

[着色.源码]方形噪声与散列(哈希)

本帖最后由 hcwanz 于 2023-12-23 15:39 编辑

本篇源码用于我之前的像素画板,详情见:
像素画板模块 - 火山平台俱乐部 - 火山软件开发平台 - Powered by Discuz! (voldp.com)

前文讲了噪声算法模拟自然随机的特性,
现在我们先讲一下噪声随机的另一个特性--散列性(hash、哈希)。

散列实际就是,固定的把一段有序的数列,转换为无序的数列。
想用文字讲明白需要费好些口舌,但如果用代码就好很多了。

数组 输入={0,1,2,3};
数组 输出;
输出=散列方法(输入);
调试输出(输出);//{5,45,1,465}
输出=散列方法(输入);
调试输出(输出);//{5,45,1,465}
.....
输出=散列方法(输入);
调试输出(输出);//{5,45,1,465}

像火山的取文本哈希值,就是通过散列算法,可以把一吉的文本转换为一个长整数,进行比较。
在运行速度下降不多的情况下,节省了大量空间。

说回噪声,我们本篇分享的源码是最初始的方形噪声,虽然效率和随机性,比之现代的单形噪声逊色不少,但原理简单,极为适合入门学习。
方形噪声的作者是Ken Perlin,所以英文名为:Perlin noise

前文说过着色器程序与普通程序不同,我们需要同时对所有的像素点进行计算,而非是拿着画笔依次绘制。
因此着色器的目标是,计算出一个像素点应该是什么颜色。

首先把下面的文字想象成是一组像素点:
口口口口口口口口口口
口口口口口口口口口口
口口口口口口口口口口
口口口口口口口口口口
口口口口口口口口口口
口口口口口口口口口口
那么我们要如何计算,以得到可复现的结果呢?
作者的思路是,先把大组划分为数个方形的像素点组,
十一一十一一十一一十
丨口口丨口口丨口口丨
丨口口丨口口丨口口丨
十一一十一一十一一十
丨口口丨口口丨口口丨
丨口口丨口口丨口口丨
然后对于每个顶点,根据坐标进行散列计算。
这样,每个方形组,都有了四个独一无二的随机值。

之后根据每个点的所处位置,对随机值按距离进行百分比权重平衡。
于是每个点,都有了自己独有的随机值。

但最终的结果,还是秩序大于随机。或者说非常的突兀。

因为点的距离依然是一个十分有序的等距数列,为此我们需要对点距进行一定的计算才能把它当作权重使用。
但这种计算不是上面的散列计算,因为我们已经有随机数了,现在我们需要的是让随机不要显得突兀。

作者使用的是Hermine曲线(不需要记这个稀奇古怪的名字,公式比名字还简单)
代码为:
变量 位置;
变量 权重值=位置*位置*(3.0-2.0*位置)
//权重值=线阶(0.0,1.0,位置)//和上面的基本一样
下为计算过后与未计算的不同:(蓝为原本)

如此,我们就完成了对于方形噪声的学习

现在我们画出的方形噪声并不具备什么实际价值、也没什么美感,
但未来进一步的学习中大家就能发现它身上的数学之美。
                                                                                                                                                                                                            下一篇是方形噪声的进步版--单形噪声,因为比较抽象,学着比较绕,所以可能会等几天。
再之后是一个实用的源码:Shader - Shadertoy BETA
再完了我会回归基础对着色器的诸多内置方法搞一系列的教程。
(为什么不先讲基础?因为我上半年就是断在那个源码那里,所以这次要先搞明白,了结自己的夙愿。)


hcwanz 发表于 2023-12-23 15:26:44

源码:(还是建议用vim,以获得较好的体验)

#版 450
同 粗二 外屏幕;
同 粗二 外鼠位;
同 逻二 外鼠按;
同 粗数 外时间;

//二维随机
/*此方法为简单的散列算法,里面的方法、数字只要足够复杂即可,没有特殊意义。*/
粗数 随机(粗二 位置){
    返 取小(正弦(点积(位置.横纵,
                                    粗二(12.6739,47.432)))
                        * 74389.439728);
}
//二维方形噪声
//来自:https://www.shadertoy.com/view/4dS3Wd
粗数 噪声(粗二 位置){
    粗二 位整=退整(位置);
    粗二 位小=取小(位置);
/*取得二维中,当前点所在像素组的四个顶点影响值*/
    粗数 点一=随机(位整+粗二(0,0));
    粗数 点二=随机(位整+粗二(1,0));
    粗数 点三=随机(位整+粗二(0,1));
    粗数 点四=随机(位整+粗二(1,1));
/*对横纵两个坐标的小数部分进行计算,
*得出当前像素组内独一无二的两个本坐标的权重值。*/
    粗二 权=位小*位小*(3.0-2.0*位小);
    //权=线阶(0,1,位小);
/*计算公式类似线阶()
*读者可以取消下一行的注释,看看不进行这一计算会怎样*/
    //权=位小;

/*根据权重混合4个顶点值*/
/*混合方法原理:
    返回=点一 * (1-权.横) + 点二 * 权.横 */
    返混合(混合(点一,点二,权.横),
             混合(点三,点四,权.横),
             权.纵);
}
无 主(){
    粗二 位置=像位置.横纵/外屏幕.横纵;
/*缩放坐标系,对于某些噪声方法有奇效
*读者可以试试修改5.0,看看有什么变化*/
    粗二 点=粗二(位置*10.0);
/*使用噪声方法*/
    粗数 噪=噪声(点);

    像颜色 =粗四(粗三(噪),1.0);
}

hcwanz 发表于 2023-12-23 15:51:23

本帖最后由 hcwanz 于 2023-12-23 16:30 编辑

发现了一个方形噪声的简单进阶版,在原本的思路下,改了顶点随机值计算方式,得到了很巨大的提升




hcwanz 发表于 2023-12-23 16:08:05

#版 450
同 粗二 外屏幕;
同 粗二 外鼠位;
同 逻二 外鼠按;
同 粗数 外时间;

/*依旧是一个散列算法,与之前源码不同的是返回一个粗二值*/
粗二 随机(粗二 位置){
    位置=粗二(点积(位置,粗二(123.2,341.3)),
            点积(位置,粗二(269.2,133.5)));
    返 -1.0+2.0*取小(正弦(位置)*16354.1354654);
}
粗数 噪声(粗二 位置){
    粗二 位整=退整(位置);
    粗二 位小=取小(位置);
/*与之前掩码不同就在于此,
*这里的参数二好像具备方向上的概念,不再是单纯的变量*/
    粗数 点一=点积(随机(位整+粗二(0,0)),位小-粗二(0,0));
    粗数 点二=点积(随机(位整+粗二(1,0)),位小-粗二(1,0));
    粗数 点三=点积(随机(位整+粗二(0,1)),位小-粗二(0,1));
    粗数 点四=点积(随机(位整+粗二(1,1)),位小-粗二(1,1));

    粗二 权=位小*位小*(3.0-2.0*位小);

    返混合(混合(点一,点二,权.横),
             混合(点三,点四,权.横),
             权.纵);
}
无 主(){
    粗二 位置 = 像位置.横纵/外屏幕.横纵;
    位置.横 *= 外屏幕.横/外屏幕.纵;//使得画的图案一定是正方形
/*缩放坐标系,对于某些噪声方法有奇效
*读者可以试试修改5.0,看看有什么变化*/
    粗二 点=粗二(位置*10.0);
/*使用噪声方法*/
    粗数 噪=噪声(点)*0.5+0.5;

    像颜色 =粗四(粗三(噪),1.0);
}

hcwanz 发表于 2023-12-23 17:07:32

本帖最后由 hcwanz 于 2023-12-23 17:11 编辑

搞懂了,初版的方形噪声,其顶点影响值对于组内的每个像素点都是相同的。
所以他绘制出的图像非常方,因为这一个方里的变化量是一样,不同的仅仅是点的权重。

而改进版,则在计算顶点影响值时,加入了当前点与对应影响顶点的方向。
所以哪怕在方内部,每个点的变化量都是不同的,因此绘制出的图像就不显的方了。

老道 发表于 2023-12-24 10:57:14

咋没人赞!这么无私的奉献
页: [1]
查看完整版本: [着色.源码]方形噪声与散列(哈希)