2021年03月27日 - WebVR・Three.js
GLSLでノイズ

「GLSLでジュリア集合」に続き「フラグメントシェーダ ノイズ-wgld.org」を参考に、GLSLでノイズを試しました。
GLSLでノイズ
フォトショップに雲模様フィルタがありますが、ノイズは雲や炎などを表現するさいに使用します。GLSLで自然な仕上がりのノイズ(パーリンノイズのような)を生成するには、線形補間して均衡化した複数の階層(オクターブ)のノイズを合成します。各階層のノイズをどの程度の割合で合成するかはパーシステンスと呼ばれる値を使用し、一般的には0.5を設定します。
● script.jsの読み込み
script.jsは「WebGLでシェーダ(GLSL)入門」と同じものを使用します。
<script src="js/script.js" type="module"></script>
● glsl.js
const vertexShader =`
attribute vec3 position;
void main(void){
gl_Position = vec4(position,1.0);
}
`;
const fragmentShader =`
precision highp float;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
//合成するノイズの階層(オクターブ)数
const int oct = 8;
//ノイズを合成する割合(パーシステンス)
const float per = 0.5;
const float PI = 3.1415926;
//ノイズを均衡化するための線形補間
float interpolate(float a,float b,float x){
float f = (1.0 - cos(x * PI)) * 0.5;
return a * (1.0 - f) + b * f;
}
//乱数を生成
float rnd(vec2 p){
return fract(sin(dot(p,vec2(12.9898,78.233))) * 43758.5453);
}
//補間した乱数を生成
float irnd(vec2 p){
vec2 i = floor(p);
vec2 f = fract(p);
vec4 v = vec4(rnd(vec2(i.x,i.y)),
rnd(vec2(i.x + 1.0,i.y)),
rnd(vec2(i.x,i.y + 1.0)),
rnd(vec2(i.x + 1.0,i.y + 1.0)));
return interpolate(interpolate(v.x,v.y,f.x),interpolate(v.z,v.w,f.x),f.y);
}
//ノイズを生成
float noise(vec2 p){
float t = 0.0;
for(int i = 0; i < oct; i++){
float freq = pow(2.0,float(i));
float amp = pow(per,float(oct - i));
t += irnd(vec2(p.x / freq, p.y / freq)) * amp;
}
return t;
}
//シームレスノイズを生成
float snoise(vec2 p,vec2 q,vec2 r){
return noise(vec2(p.x,p.y)) * q.x * q.y +
noise(vec2(p.x,p.y + r.y)) * q.x * (1.0 - q.y) +
noise(vec2(p.x + r.x,p.y)) * (1.0 - q.x) * q.y +
noise(vec2(p.x + r.x,p.y + r.y)) * (1.0 - q.x) * (1.0 - q.y);
}
void main(void){
//シームレスノイズ
const float map = 700.0;
vec2 t = mod(gl_FragCoord.xy + vec2(time * 10.0),map);
float n = snoise(t,t / map,vec2(map));
gl_FragColor = vec4(vec3(n),1.0);
}
`;
export { vertexShader, fragmentShader };
完成したデモになります。GLSLでノイズを試しました。

