由于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()……”.
刚找到这个版本的GPU 3d噪声,据说它是最快的一个可用的:
#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 = p.x + p.y*57.0 + 113.0*p.z;
return lerp(lerp(lerp( hash(n+0.0), hash(n+1.0),f.x),
lerp( hash(n+57.0), hash(n+58.0),f.x),f.y),
lerp(lerp( hash(n+113.0), hash(n+114.0),f.x),
lerp( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}
#endif
请看下面的例子如何添加白噪声渲染纹理。
解决方案是使用两种纹理:原始白噪声和纯白噪声,就像这个:wiki白噪声
private static final String VERTEX_SHADER =
"uniform mat4 uMVPMatrix;\n" +
"uniform mat4 uMVMatrix;\n" +
"uniform mat4 uSTMatrix;\n" +
"attribute vec4 aPosition;\n" +
"attribute vec4 aTextureCoord;\n" +
"varying vec2 vTextureCoord;\n" +
"varying vec4 vInCamPosition;\n" +
"void main() {\n" +
" vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
"}\n";
private static final String FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D sTextureUnit;\n" +
"uniform sampler2D sNoiseTextureUnit;\n" +
"uniform float uNoseFactor;\n" +
"varying vec2 vTextureCoord;\n" +
"varying vec4 vInCamPosition;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(sTextureUnit, vTextureCoord);\n" +
" vec4 vRandChosenColor = texture2D(sNoiseTextureUnit, fract(vTextureCoord + uNoseFactor));\n" +
" gl_FragColor.r += (0.05 * vRandChosenColor.r);\n" +
" gl_FragColor.g += (0.05 * vRandChosenColor.g);\n" +
" gl_FragColor.b += (0.05 * vRandChosenColor.b);\n" +
"}\n";
共享的片段包含参数uNoiseFactor,该参数在主应用程序每次渲染时都会更新:
float noiseValue = (float)(mRand.nextInt() % 1000)/1000;
int noiseFactorUniformHandle = GLES20.glGetUniformLocation( mProgram, "sNoiseTextureUnit");
GLES20.glUniform1f(noiseFactorUniformHandle, noiseFactor);