Editor : http://editor.thebookofshaders.com/
Gradient Noise는 Ken Perlin이 만든 노이즈 알고리즘 입니다.
초기 랜덤함수를 사용한 Noise는 Blocky한 영역이 생기는 문제가 있었습니다.
이러한 Blocky 한 영역을 부드럽게 수정한 Noise 알고리즘이 Gradient Noise 입니다.
Gradient Noise는 우주의 섬광 같기도 하고, 안개 같은 느낌도 주네요
메인 함수에서 if (st.x < Num) 코드 부분을 볼 수 있습니다.
Num을 0.5로 넣게 되면 화면의 절반은 일반 Noise를 나머지는 Gradient Noise 화면을 볼 수 있습니다.
Gradient Noise 구현부는 Noise() 함수를 여러번 호출해서 값을 연산하는 부분이 추가가 되었습니다.
여러 파라메터를 수정해 가거나 random 함수를 수정하면서 effect 효과를 보시기 바랍니다.
노이즈 함수 입니다.
float hash(vec2 p) {
p = 50. * fract(p * 0.3183099 + vec2(0.71, 0.113));
return -1.0 + 2.0 * fract(p.x * p.y * (p.x + p.y));
}
float noise(vec2 st) {
vec2 i = vec2(floor(st));
vec2 f = fract(st);
vec2 u = f * f * (3. - 2. * f);
float ret = mix( mix( hash( i + vec2(0.0, 0.0 ) ),
hash( i + vec2(1.0, 0.0 ) ), u.x),
mix( hash( i + vec2(0.0, 1.0) ),
hash( i + vec2(1.0, 1.0) ), u.x), u.y);
return ret;
}
Hash 함수는 input vec2를 유니크한 값 [0 ~ 1] 범위로 바꾸어 줍니다.
mix(A, B, pct)
Lerp 함수와 거의 동일한데, A 값과 B값 사이를 pct (0~1) 값으로 보간합니다.
mix 하는 부분이 복잡한데, 3번 mix 합니다.
구현부는 다음과 같습니다.
mix(
mix( hash( i + vec2(0.0, 0.0 )), hash( i + vec2(1.0, 0.0 )) , u.x),
mix( hash( i + vec2(0.0, 1.0)), hash( i + vec2(1.0, 1.0)), u.x),
u.y);
mix 함수의 호출 횟수는
빨강색 부분 1번, 초록색 부분 1번,
빨강색 부분 결과, 초록 색 부분 결과, u.y로 1번 해서 총 3번입니다.
hash 함수의 값도 0 ~ 1 범위이기 때문에 최종 결과도 0 ~ 1범위 입니다.
유니크 한 값으로 x, y 방향으로 골고루 퍼뜨려 주는 코드 입니다.
다음은 메인 함수입니다.
st += vec2(u_time / 3., 0);
st *= 8.0;
mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 );
f = 0.5000 * noise( st ); st = m * st;
f += 0.2500 * noise( st ); st = m * st;
f += 0.1250 * noise( st ); st = m * st;
f += 0.0625 * noise( st ); st = m * st;
f = 0.5 + 0.5 * f;
f *= smoothstep(0., 0.005, abs(st.x - 0.6));
color = vec3(f, f, f);
gl_FragColor = vec4(color, 1.0);
좌표 값에 매트릭스 값을 곱하고, 연쇄적으로 노이즈의 input 파라메터로 사용 했습니다.
최종 소스 입니다.
// Author: Simon.Lee
// Title: Gradient Noise by Ken Perlin
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
float hash(vec2 p) {
p = 50. * fract(p * 0.3183099 + vec2(0.71, 0.113));
return -1.0 + 2.0 * fract(p.x * p.y * (p.x + p.y));
}
float random(vec2 st)
{
return fract(sin(dot(st.xy, vec2(12.9898, 78.2333))) * 43758.5453123);
}
float noise(vec2 st) {
vec2 i = vec2(floor(st));
vec2 f = fract(st);
vec2 u = f * f * (3. - 2. * f);
float ret = mix( mix( hash( i + vec2(0.0, 0.0 ) ),
hash( i + vec2(1.0, 0.0 ) ), u.x),
mix( hash( i + vec2(0.0, 1.0) ),
hash( i + vec2(1.0, 1.0) ), u.x), u.y);
return ret;
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
vec3 color = vec3(0.);
float f = 0.;
if (st.x < 0.)
{
st += vec2(u_time / 3., 0);
f = noise(32.0 * st);
}
else
{
st += vec2(u_time / 3., 0);
st *= 8.0;
mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 );
f = 0.5000 * noise( st ); st = m * st;
f += 0.2500 * noise( st ); st = m * st;
f += 0.1250 * noise( st ); st = m * st;
f += 0.0625 * noise( st ); st = m * st;
}
f = 0.5 + 0.5 * f;
f *= smoothstep(0., 0.005, abs(st.x - 0.6));
color = vec3(f, f, f);
gl_FragColor = vec4(color, 1.0);
}
해당 코드는 아래 사이트에서 참조했습니다.
'Shader CG' 카테고리의 다른 글
2.7 Noise - 영혼이 빠져나감 (0) | 2023.08.28 |
---|---|
2.6 나이테 Noise (0) | 2023.08.19 |
2.4 Noise 함수 사용해보기 (0) | 2023.08.12 |
2.3 Noise 미로 만들기 (0) | 2023.08.11 |
2.2 Noise 모자이크 효과 (0) | 2023.08.09 |