본문 바로가기
셰이더 (Shader)/The Book of Shaders (완)

[GLSL] 6 - Colors

by Minkyu Lee 2023. 4. 18.

벡터 내부의 데이터에 C언어의 구조체처럼 접근한다.

vec3 red = vec3(1.0,0.0,0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;

 

색상을 x, y, z 표기법으로 정의하면 혼란스러울 수 있다.

그래서 다른 접근법도 있다.

s,t,p는 일반적으로 텍스처의 공간 좌표에 사용된다.

vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;

 

 

GLSL 벡터의 또 다른 특징은 프로퍼티를 원하는 순서대로 결합할 수 있다.

값을 쉽게 캐스팅하고 혼합한다.

이 기능을 스위즐이라고 한다.

vec3 yellow, magenta, green;

// Making Yellow
yellow.rg = vec2(1.0);  // Assigning 1. to red and green channels
yellow[2] = 0.0;        // Assigning 0. to blue channel

// Making Magenta
magenta = yellow.rbg;   // Assign the channels with green and blue swapped

// Making Green
green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels

 

Mixing color

두 값을 백분율로 혼합할 수 있는 함수 mix()가 있다.

백분율 범위는 0.0에서 1.0 사이의 값이다.

색이 시간에 따라 계속 변한다.

// ... 생략
vec3 colorA = vec3(0.149,0.141,0.912);
vec3 colorB = vec3(1.000,0.833,0.224);

void main() {
    vec3 color = vec3(0.0);
    float pct = abs(sin(u_time));
    color = mix(colorA, colorB, pct);
    gl_FragColor = vec4(color,1.0);
}

Playing with gradients

벡터값을 이용해 mix할 수도 있다.

// ... 생략
vec3 colorA = vec3(0.149,0.141,0.912);
vec3 colorB = vec3(1.000,0.833,0.224);

float plot (vec2 st, float pct){
  return  smoothstep( pct-0.01, pct, st.y) -
          smoothstep( pct, pct+0.01, st.y);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    vec3 pct;
    pct.r = smoothstep(0.0,1.0, st.x);
    pct.g = sin(st.x*PI);
    pct.b = pow(st.x,0.5);

    color = mix(colorA, colorB, pct);

    // Plot transition lines for each channel
    color = mix(color,vec3(1.0,0.0,0.0),plot(st,pct.r));
    color = mix(color,vec3(0.0,1.0,0.0),plot(st,pct.g));
    color = mix(color,vec3(0.0,0.0,1.0),plot(st,pct.b));

    gl_FragColor = vec4(color,1.0);
}

HSB

RGB가 아닌 다른 색공간도 있다.

HSB는 Hue, Saturation, Brightness(또는 Value)의 약자이다.

직관적인 색공간이다.

// ... 생략
vec3 rgb2hsb( in vec3 c ){
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz),
                 vec4(c.gb, K.xy),
                 step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r),
                 vec4(c.r, p.yzx),
                 step(p.x, c.r));
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
                d / (q.x + e),
                q.x);
}

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

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);
    color = hsb2rgb(vec3(st.x,1.0,st.y));

    gl_FragColor = vec4(color,1.0);
}

HSB in polar coordinates (극좌표계)

// 극좌표계란?

극좌표계는 평면 위의 위치를 각도와 거리를 써서 나타내는 2차원 좌표계이다

두 점 사이의 관계가 각이나 거리로 쉽게 표현되는 경우 유용하다

https://ko.wikipedia.org/wiki/%EA%B7%B9%EC%A2%8C%ED%91%9C%EA%B3%84

 

// 코드 설명

HSB는 원래 극좌표로 표현하도록 설계되었다.

HSB 함수를 극좌표로 매핑하려면 중심점에서 픽셀 좌표까지의 각도와 거리를 구해야한다.

 

각도와 길이를 구한 후, 해당 값을 0.0에서 1.0 사이의 범위로 정규화한다.

27번째 줄에서 atan(y,x)는 -PI와 PI(-3.14~3.14) 사이의 라디안 단위 각도를 반환한다.

이 값을 TWO_PI로 나누어 -0.5에서 0.5 사이의 값을 구한다.

간단한 덧셈을 통해 원하는 범위인 0.0에서 1.0으로 변경한다.

 

반경은 최대 0.5를 반환하므로, (뷰포트의 중심으로부터의 거리를 계산하기 때문에)

최대 1.0을 얻으려면 이 범위를 두 배(2를 곱하여)로 늘려야 한다.

 

요약하자면 ㅇ범위를 0.0에서 1.0으로 변환하고 매핑하는 것이 전부이다.

// ... 생략

#define TWO_PI 6.28318530718

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);

    vec2 toCenter = vec2(0.5)-st;
    float angle = atan(toCenter.y,toCenter.x);
    float radius = length(toCenter)*2.0;

    color = hsb2rgb(vec3((angle/TWO_PI)+0.5,radius,1.0));

    gl_FragColor = vec4(color,1.0);
}

Note about functions and arguments

매개변수 전에 위치한 in이라는 키워드를 보자.

이는 읽기 전용인지를 지정하는 qualifier(수식어)이다. 

out이나 inout도 있다.

inout은 전달된 변수를 수정할 수 있는 방식인 레퍼런스로 전달하는 것과 유사한 개념이다.

댓글