정점과 프래그먼트
셰이더 프로그램은 정점(vertex) 셰이더와 프래그먼트(fragment) 셰이더로 구성된다. 정점 셰이더는 정점의 기하학적 속성을 정의하고, 프래그먼트 셰이더는 그 색상을 정의한다. 이 글에서는 정점 셰이더와 프래그먼트 셰이더를 작성하는 방법과 사용하는 방법을 다룬다.
정점 셰이더
정점 셰이더에서는 main() 함수 안에 정점의 위치 gl_Position을 정의해야 한다. gl_Position은 예약된 변수이므로 그 이름을 임의로 바꿀 수 없다. 정점 셰이더의 간단한 예제는 다음과 같다.
precision mediump float;
attribute vec2 a_position;
uniform float u_time;
varying vec2 v_position;
void main() {
vec2 zeroToOne = a_position;
v_position = a_position;
// Convert from [0,1] to [-1,+1]
vec2 clipSpace = zeroToOne * 2.0 - 1.0;
clipSpace.y *= -1.;
gl_Position = vec4(clipSpace, 0., 1.);
}
precision mediump float는 float의 정밀도를 중간 수준으로 설정한다. 필요하다면 lowp나 highp를 선택할 수 있다. 낮은 정밀도는 계산 부하가 적지만 표현 범위가 좁고, 높은 정밀도는 그 반대다. lowp, mediump, highp는 각각 최소 9, 16, 32비트로 수를 표현한다. 그 크기는 시스템에 따라 다르다. 1
attribute vec2 a_position은 외부에서 정의되는 속성 변수를 선언한다. 위 예제에서 a_position은 캔버스 내 픽셀의 정규화된 위치를 나타내며, 따라서 [0, 1] 범위의 부동소수점 수로 표현된다. WebGL의 클립 공간(clipspace) 은 -1에서 1까지의 범위를 가지므로, clipspace를 출력할 때 [0, 1]에서 [-1, 1]로 변환하는 것을 반드시 잊지 말아야 한다.
uniform 변수 u_time은 페이지가 시작된 후 경과한 시간을 초 단위로 나타내기 위한 것이다. 속성 값은 픽셀마다 다른 반면, uniform 값은 모든 픽셀에 대해 동일하다는 점에 유의한다.
마지막으로 varying은 정점 셰이더에서 프래그먼트 셰이더로 데이터 값을 보내기 위한 데이터 타입이다. 위에서 정점 셰이더는 a_position의 값을 v_position에 복사하는데, 이는 기본적으로 프래그먼트 셰이더가 속성 변수를 사용할 수 없기 때문이다.
프래그먼트 셰이더
프래그먼트 셰이더는 픽셀의 색상 gl_FragColor를 기술한다. 이 예약 변수의 타입은 red, green, blue, alpha로 구성된 vec4이다.
precision mediump float;
varying vec2 v_position;
uniform float u_time;
void main() {
gl_FragColor = vec4(1., 0., 1., 1.);
}
테스트 방법
효율적인 학습을 위해 GLSL 코드를 온라인 2이나 여기에서 편집하고 테스트할 수 있다. 아래에서는 정점 셰이더와 프래그먼트 셰이더 코드를 테스트할 수 있는 라이브 예제를 제공한다. 제공되는 속성 변수와 uniform 변수는 a_position, u_time, u_resolution, u_mousePosition이다. a_position은 캔버스 UV 맵에서 픽셀의 정규화된 위치를, u_time은 페이지가 로드된 후 경과한 시간을, u_resolution은 캔버스의 픽셀 크기를, u_mousePosition은 캔버스를 기준으로 한 마우스의 위치를 나타낸다. 아래 코드를 수정하면 결과가 실시간으로 변한다.
Touch or hover your mouse here