由于GPU驱动供应商通常不会费心在GLSL中实现noiseX,我正在寻找一个“图形随机化瑞士军刀”实用函数集,最好是在GPU着色器中优化使用。我更喜欢GLSL,但是任何语言的代码对我来说都可以,我可以把它翻译成GLSL。
具体来说,我希望:
a)伪随机函数- n维,均匀分布于[-1,1]或[0,1]之上,从m维种子(理想情况下是任何值,但我同意将种子限制在,比如说,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维,+-均匀分布,有约束的值集,看起来不错(一些配置外观的选项,比如柏林电平也很有用)。我希望签名是这样的:
float noise (T coord, TT seed);
vec2 noise2 (T coord, TT seed);
// ...
我对随机数生成理论不太感兴趣,所以我最渴望的是一个现成的解决方案,但我也很喜欢这样的回答:“这里有一个非常好的,高效的1D rand(),让我解释一下如何在它的基础上制作一个好的n维rand()……”.
Lygia,一个多语言着色器库
如果你不想复制/粘贴函数到你的着色器,你也可以使用lygia,一个多语言着色器库。它在GLSL和HLSL中都包含了一些生成函数,如cnoise, fbm, noised, pnoise, random, snoise。还有很多其他很棒的功能。要做到这一点:
#上的接力包括“文件”,由Khronos GLSL标准定义,并被大多数引擎和环境(如glslViewer, GLSL -canvas VS Code插件,Unity等)所支持。
例如:cnoise
使用cnoise。GLSL与#包括:
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform float u_time;
#include "lygia/generative/cnoise.glsl"
void main (void) {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec3 color = vec3(cnoise(vec3(st * 5.0, u_time)));
gl_FragColor = vec4(color, 1.0);
}
为了运行这个例子,我使用了glslViewer。
Gustavson的实现使用1D纹理
不,从2005年开始就没有了。只是人们坚持下载旧版本。您提供的链接上的版本仅使用8位2D纹理。
我和阿希玛的Ian McEwan共同开发的新版本没有使用纹理,但是在典型的桌面平台上,纹理带宽很大,运行速度只有它的一半左右。在移动平台上,无纹理版本可能更快,因为纹理通常是一个重要的瓶颈。
我们积极维护的源存储库是:
https://github.com/ashima/webgl-noise
这里是无纹理和使用纹理的噪音版本的集合(只使用2D纹理):
http://www.itn.liu.se/~stegu/simplexnoise/GLSL-noise-vs-noise.zip
如果您有任何具体的问题,请直接给我发电子邮件(我的电子邮件地址可以在经典噪声*中找到)。glsl来源。)
我突然想到,你可以使用一个简单的整数哈希函数,并将结果插入到浮点数的尾数中。IIRC, GLSL规范保证32位无符号整数和IEEE binary32浮点表示,因此它应该是完全可移植的。
我刚才试过了。结果非常好:我尝试的每个输入看起来都像静态的,根本没有可见的模式。相比之下,在相同的输入条件下,流行的sin/fract代码片段在我的GPU上有相当明显的对角线。
一个缺点是它需要GLSL v3.30。虽然它看起来足够快,但我还没有对它的表现进行实证量化。AMD的Shader Analyzer声称HD5870上的vec2版本每个时钟有13.33个像素。与sin/fract片段的每个时钟16像素相比。所以它肯定会慢一点。
这是我的实现。我把它写成了不同的形式这样更容易推导出你自己的函数。
/*
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( v.x ^ hash(v.y) ); }
uint hash( uvec3 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ); }
uint hash( uvec4 v ) { return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w) ); }
// 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 );
}
截图:
我在一个图像编辑程序中检查了截图。有256种颜色,平均值是127,这意味着分布均匀,涵盖了预期的范围。
一定要用这个:
highp float rand(vec2 co)
{
highp float a = 12.9898;
highp float b = 78.233;
highp float c = 43758.5453;
highp float dt= dot(co.xy ,vec2(a,b));
highp float sn= mod(dt,3.14);
return fract(sin(sn) * c);
}
不要用这个:
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
您可以在改进OpenGL ES 2.0的规范一行程序GLSL rand()中找到解释