본문 바로가기
Shader CG

2.5 Gradient Noise

by SimonLee 2023. 8. 17.

Editor : http://editor.thebookofshaders.com/

 

** The Book of Shaders Editor **

 

editor.thebookofshaders.com

 

Gradient Noise는 Ken Perlin이 만든 노이즈 알고리즘 입니다.

초기 랜덤함수를 사용한 Noise는 Blocky한 영역이 생기는 문제가 있었습니다.

이러한 Blocky 한 영역을 부드럽게 수정한 Noise 알고리즘이 Gradient Noise 입니다.

 

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);
}

 

 

해당 코드는 아래 사이트에서 참조했습니다.

https://thebookofshaders.com/

 

The Book of Shaders

Gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.

thebookofshaders.com

'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