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でノイズを試してみました。