개발/Shader / / 2023. 2. 24. 18:31

GLSL - qualifier, shape squre, shape circle

반응형

Qualifier

vec3 hsb2rgb( in vec3 c ){
    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
                             6.0)-3.0)-1.0,
                     0.0,
                     1.0 );
    rgb = rgb*rgb*(3.0-2.0*rgb);
    return c.z * mix( vec3(1.0), rgb, c.y);
}

앞서 본 함수의 매개변수에는 왠 in이라는 키워드가 있다. 이러한 키워드를 qualifier라고 하는데, 여기서 in은 없는거나 마찬가지이다.

in은 매개변수로 값을 전달할 때 깊은 복사로 전달되어 함수 안에서는 지역변수 메모리가 따로 생성되어 함수를 호출할 때 레퍼런스가 전달되지 않는다. 하지만 out은 얕은 복사로 전달되어 변수의 레퍼런스를 전달한다. out 말고도 inout이라는 키워드도 있는데, out과 inout의 차이는 명확하다.

 

void plus(out vec3 val){
    val += 1.0;
}

void plus2 (inout vec3 val){
    val += 1.0;
}

위와 같은 함수들이 있다고 하자, 여기서 out으로 선언된 함수는 매개변수 val의 값으로 어떤 값이 들어가도 내부적으로 default 값이 존재하여 외부에서 매개변수 val의 레퍼런스는 넘겨주지만 값은 넘겨줄 수 없다. 하지만 inout으로 선언된 함수는 매개변수 val의 값까지도 넘겨줄 수 있다.

unity C#에서도 비슷한 qualifier가 존재하는데 inout이 ref라는 키워드로 비슷한 용도로 사용된다.

 

Shape

https://thebookofshaders.com/07/

 

The Book of Shaders

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

thebookofshaders.com

 

Squre

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

vec3 rect(vec2 coord, vec2 loc, vec2 size){
    vec2 sw = loc-size/2.;
    vec2 ne = loc+size/2.;
    vec2 pct = step(sw, coord); 
    pct -= step(ne, coord);
    
    return vec3(pct.x * pct.y);
}

void main(){
    vec2 coord = gl_FragCoord.xy/u_resolution;
    
    vec3 col = rect(coord, vec2(.5), vec2(.5));
    
    gl_FragColor = vec4(col, 1.);
}

사각형을 그리는 코드이다.

방법은 이렇게 각 모서리의 좌표마다 특징을 구해서 해당 좌표 범위 안쪽을 구분할 수 있는 구분자를 찾아내는 방식이다.

코드를 보면 loc은 중심점, size는 사각형의 가로 세로 크기를 의미한다. 

sw라는 변수는 south west라는 의미로 그림에서 사각형 왼쪽 밑 모서리 좌표를, ne는 north east라는 의미로 그림에서 사각형 오른쪽 위 모서리 좌표를 의미한다. 

 

step함수로 각 coord 좌표값을 sw값을 기준으로 0,1을 나눈다. 위 그림과 같이 좌표가 나올 것이다.

 

이번에는 step함수로 coord 좌표값을 ne값 기준으로 0,1을 나누면 위 그림과 같이 좌표가 나온다. 

 

    vec2 pct = step(sw, coord); 
    pct -= step(ne, coord);
    
    return vec3(pct.x * pct.y);

sw값 기준으로 step한 값에서 ne값 기준으로 step한 값을 빼면 중앙 사각형에 해당하는 좌표값만 1,1이 나오고 나머지는 좌표 중 하나가 0인 형태가 된다. 둘 중 하나가 0이면 return하는 vec3값이 0이 되도록 코드가 짜여있으므로, 1,1인 구간만 vec3값이 1이 되고 나머지는 vec3(0)이 되므로 이를 이용해서 사각형을 그릴 수 있게 된다.

 

Circle

// Author @patriciogv - 2015
// http://patriciogonzalezvivo.com

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

void main(){
	vec2 st = gl_FragCoord.xy/u_resolution;
    float pct = 0.0;

    // a. The DISTANCE from the pixel to the center
    pct = distance(st,vec2(0.5));

    // b. The LENGTH of the vector
    //    from the pixel to the center
    // vec2 toCenter = vec2(0.5)-st;
    // pct = length(toCenter);

    // c. The SQUARE ROOT of the vector
    //    from the pixel to the center
    // vec2 tC = vec2(0.5)-st;
    // pct = sqrt(tC.x*tC.x+tC.y*tC.y);

    vec3 color = vec3(pct);

	gl_FragColor = vec4( color, 1.0 );
}

위 코드에서 원을 그리는 방법에 대해서 a,b,c 세 가지로 표현하는데, 이중 하나를 알아보도록 한다.

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

vec3 circle(vec2 coord, vec2 loc, float r){
    float d;
    d = length(coord - loc);
    
    d = smoothstep(r, r+0.01, d);
    
    return vec3(d);
}

void main(){
    vec2 coord = gl_FragCoord.xy/u_resolution;
    
    vec3 col = circle(coord, vec2(.5), .3);
    
    gl_FragColor = vec4(col, 1.);
}

circle이라는 함수 안에서 coord좌표 위치에서 loc변수 0.5 만큼을 모든 좌표에서 뺀 거리를 반환하여 그리면

이렇게 (0.5, 0.5)좌표로부터 흩뿌리는 듯한 모양이 나온다. 중심은 정확히 차(distance)가 0이 나오고 나머지는 멀어질 수록 점점 절댓값이 0에서 멀어지기 때문이다. 

이러한 상황에서 원을 그리기 위해 반지름 r을 설정하고, distance가 특정 값보다 작으면 0으로 떨어지게 만들면 r 만큼의 반지름을 가진 검은 원을 그릴 수 있다.

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유