GLSL的随机/噪声函数

由于GPU驱动程序供应商通常noiseX在GLSL中实现noiseX ,所以我正在寻找一种“graphics随机瑞士军刀”实用程序function集,最好在GPU着色器中进行优化。 我更喜欢GLSL,但是编写任何语言都可以,我可以把它自己翻译成GLSL。

具体来说,我希望:

a) 伪随机函数 – 从M维种子计算得到的N维,在[-1,1]或超过[0,1]上的均匀分布(理想情况下是任何值,但是我可以用种子限制为了统一的结果分布,比如0..1)。 就像是:

 float random (T seed); vec2 random2 (T seed); vec3 random3 (T seed); vec4 random4 (T seed); // T being either float, vec2, vec3, vec4 - ideally. 

b) 连续的噪音,如柏林噪音 – 再次,N维,+ – 均匀分布,具有一套有限的价值观,而且看起来不错(有些选项可以configuration外观像柏林的水平也可能是有用的)。 我希望签名像:

 float noise (T coord, TT seed); vec2 noise2 (T coord, TT seed); // ... 

我对随机数生成理论并不是很了解,所以我非常热切地想要一个预先制定的解决scheme ,但是我也很感谢“这里有一个非常好的,高效的1D rand()”的答案,让我解释一下你如何在它上面制作一个好的N维rand()…“

对于非常简单的伪随机查找的东西,我使用这个在Internet上find的oneliner:

 float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } 

你也可以使用你喜欢的任何PRNG来产生一个噪点纹理,然后以正常的方式上传这个纹理,并在你的着色器中取样; 如果你愿意的话,我可以在后面find代码示例。

此外,请查阅Stefan Gustavson的文件 ,了解Perlin和Simplex噪声的GLSL实现。

Gustavson的实现使用了一维纹理

不,不是,自2005年以来没有。只是人们坚持下载旧版本。 您提供的链接上的版本只使用8位2D纹理。

Ashima和Ian的Ian McEwan的新版本并没有使用纹理,而是在具有大量纹理带宽的典型桌面平台上以大约一半的速度运行。 在移动平台上,无纹理版本可能会更快,因为纹理往往是一个重要的瓶颈。

我们积极维护的源代码库是:

https://github.com/ashima/webgl-noise

无纹理和纹理使用版本的噪音的集合在这里(只使用2D纹理):

~stegu/simplexnoise/GLSL-noise-vs-noise.zip

如果您有任何具体问题,请随时通过电子邮件直接发送(我的电子邮件地址可以在classicnoise*.glsl源文件中find)。

我发现你可以使用一个简单的整数散列函数,并将结果插入浮点数的尾数。 IIRC GLSL规范保证32位无符号整数和IEEE binary32浮点表示,所以它应该是完全可移植的。

我刚刚给了这个尝试。 结果是非常好的:它看起来完全像我试过的每个input都是静态的,根本没有可见的模式。 相比之下,在给定相同input的情况下,stream行的sin / fract片断在我的GPU上具有相当明显的对angular线。

一个缺点是它需要GLSL v3.30。 虽然看起来不够快,但我还没有经验地量化其performance。 AMD的Shader Analyzer宣称HD5870的vec2版本每时钟13.33像素。 sin / fract片段的每个时钟对应16个像素。 所以肯定会慢一点。

这是我的实现。 我把它留在了这个想法的各种排列中,以便更容易从中获得你自己的function。

 /* static.frag by Spatial 05 July 2013 */ #version 330 core uniform float time; out vec4 fragment; // A single iteration of Bob Jenkins' One-At-A-Time hashing algorithm. uint hash( uint x ) { x += ( x << 10u ); x ^= ( x >> 6u ); x += ( x << 3u ); x ^= ( x >> 11u ); x += ( x << 15u ); return x; } // Compound versions of the hashing algorithm I whipped together. uint hash( uvec2 v ) { return hash( vx ^ hash(vy) ); } uint hash( uvec3 v ) { return hash( vx ^ hash(vy) ^ hash(vz) ); } uint hash( uvec4 v ) { return hash( vx ^ hash(vy) ^ hash(vz) ^ hash(vw) ); } // Construct a float with half-open range [0:1] using low 23 bits. // All zeroes yields 0.0, all ones yields the next smallest representable value below 1.0. float floatConstruct( uint m ) { const uint ieeeMantissa = 0x007FFFFFu; // binary32 mantissa bitmask const uint ieeeOne = 0x3F800000u; // 1.0 in IEEE binary32 m &= ieeeMantissa; // Keep only mantissa bits (fractional part) m |= ieeeOne; // Add fractional part to 1.0 float f = uintBitsToFloat( m ); // Range [1:2] return f - 1.0; // Range [0:1] } // Pseudo-random value in half-open range [0:1]. float random( float x ) { return floatConstruct(hash(floatBitsToUint(x))); } float random( vec2 v ) { return floatConstruct(hash(floatBitsToUint(v))); } float random( vec3 v ) { return floatConstruct(hash(floatBitsToUint(v))); } float random( vec4 v ) { return floatConstruct(hash(floatBitsToUint(v))); } void main() { vec3 inputs = vec3( gl_FragCoord.xy, time ); // Spatial and temporal inputs float rand = random( inputs ); // Random per-pixel value vec3 luma = vec3( rand ); // Expand to RGB fragment = vec4( luma, 1.0 ); } 

截图:

随机(vec3)在static.frag中的输出

我在图像编辑程序中检查了截图。 有256种颜色,平均值为127,这意味着分布是统一的,涵盖了预期的范围。

McEwan和@StefanGustavson 在这里描述的很像Perlin噪声,但是“不需要任何设置,即不需要纹理和统一数组,只需将它添加到着色器源代码中,然后在任意位置调用它”。

这非常方便,尤其是考虑到Gustavson早期的实现(与@dep相关)使用了GLSL ES (WebGL的着色器语言) 不支持的1D纹理。

黄金噪音

 // Gold Noise ©2017 dcerisano@standard3d.com // - based on the golden ratio, PI, and the square root of two // - faster one-line fractal noise generator function // - improved random distribution // - works with all chipsets (including low precision) // - gpu-optimized floating point operations (faster than integer) // - does not contain any slow division or unsupported bitwise operations // Use mediump or highp for improved random distribution. // This line can be removed for low precision chipsets and older GL versions. // precision highp float; // precision mediump float; precision lowp float; // Irrationals with precision shifting // float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio float PI = 3.14159265358979323846264 * 00000.1; // PI float SRT = 1.41421356237309504880169 * 10000.0; // Square Root of Two // Gold Noise function // float gold_noise(in vec2 coordinate, in float seed) { return fract(sin(dot(coordinate*seed, vec2(PHI, PI)))*SRT); } 

立即在浏览器中查看Gold Noise!

截至2017年9月9日,该函数已经改进了@appas'answer中当前函数的随机分布:

在这里输入图像描述

@appas函数也是不完整的,因为没有提供种子(uv不是种子 – 每帧都是一样的),并且不适用于低精度芯片组。 黄金噪音默认情况下以较低的精度运行(快得多)。

刚刚发现这个版本的3d噪声的GPU,alledgedly它是最快的一个可用:

 #ifndef __noise_hlsl_ #define __noise_hlsl_ // hash based 3d value noise // function taken from https://www.shadertoy.com/view/XslGRr // Created by inigo quilez - iq/2013 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. // ported from GLSL to HLSL float hash( float n ) { return frac(sin(n)*43758.5453); } float noise( float3 x ) { // The noise function returns a value in the range -1.0f -> 1.0f float3 p = floor(x); float3 f = frac(x); f = f*f*(3.0-2.0*f); float n = px + py*57.0 + 113.0*pz; return lerp(lerp(lerp( hash(n+0.0), hash(n+1.0),fx), lerp( hash(n+57.0), hash(n+58.0),fx),fy), lerp(lerp( hash(n+113.0), hash(n+114.0),fx), lerp( hash(n+170.0), hash(n+171.0),fx),fy),fz); } #endif 

1d Perlin的直线锯齿形版本,实质上是随机的lfo之字形。

  half rn(float xx){ half x0=floor(xx); half x1=x0+1; half v0 = frac(sin (x0*.014686)*31718.927+x0); half v1 = frac(sin (x1*.014686)*31718.927+x1); return (v0*(1-frac(xx))+v1*(frac(xx)))*2-1*sin(xx); }