https://webglfundamentals.org/webgl/lessons/webgl-how-it-works.html
https://github.com/Myoungmin/WebGL_Fundamentals
◈ 이번 실습에서 복습할 포인트
- Varying을 사용하는 방법.
- 2개 이상의 속성을 사용하고, 데이터를 vertex shader에서 fragment shader로 전달하는 방법.
이미지 처리를 하려면 텍스처 좌표를 전달하기 위해, 이 예시와 마찬가지로 추가적인 attribute를 사용해야 한다
Varying
vertex shader는 GLSL로 작성하는 함수이다.
이 함수는 각 vertex마다 한 번씩 호출된다.
몇 가지 계산한 다음 현재 vertex의 클립 공간 값으로 특수 변수 gl_Position을 설정한다.
GPU는 이 값을 가져와서 내부에 저장한다.
TRIANGLES를 그린다고 가정하면,
정점 3개를 생성할 때마다 GPU는 이걸 이용해 삼각형을 만든다.
어떤 픽셀이 삼각형의 점 3개에 해당하는지 확인한 다음,
삼각형을 픽셀로 그리는 과정인 래스터화한다.
이렇게 생성된 픽셀은 픽셀마다 fragment shader를 호출하여 어떤 색상으로 만들지 결정한다.
fragment shader는 특수 변수 gl_FragColor를 해당 픽셀에 원하는 색상으로 설정해야 한다.
vertex shader에서 fragment shader로 더 많은 정보를 전달하려면 전달하려는 각 값에 "varying"을 정의하는 방법이 있다.
◈ 더 많은 정보를 전달하기 위해 vertex shader와 fragment shader에 varying을 선언한다.
1. fragment shader로 데이터를 전달하기 위해 vertex shader에 varying을 선언한다.
varying vec4 v_color;
//...
void main() {
// 위치에 행렬 곱하기
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
// 클립 공간에서 색상 공간으로 변환
// 클립 공간 -1.0에서 +1.0까지에서 색상 공간 0.0에서 1.0까지로 변환하는 식
v_color = gl_Position * 0.5 + 0.5;
}
2. fragment shader에 동일한 varying을 선언한다.
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
위 설정에서 우리는 vertex 3개만을 계산했다.
위 shader를 사용하면 vertex shader는 3번만 호출되므로 3개의 색상만을 계산하지만 삼각형은 여러 색상으로 표출된다.
이게 varying이라고 불리는 이유다.
WebGL은 각 정점을 계산한 3개의 값을 가져오고,
삼각형을 래스터화할 때 계산된 vertex들 사이를 보간한다.
각 픽셀마다 해당 픽셀에 대해 보간된 값으로 fragment를 호출한다.
shader의 아래 식을 통해 색상 공간으로 변환하고 우리가 선언한 varying에 작성된다.
// 클립 공간에서 색상 공간으로 변환
// 클립 공간 -1.0에서 +1.0까지에서 색상 공간 0.0에서 1.0까지로 변환하는 식
v_color = gl_Position * 0.5 + 0.5;
v_color에 vertex를 통해 작성된 3개의 값들은 보간되어 각 픽셀에 대한 fragment shader로 전달된다.
각 픽셀로 보간된 값들에 의해 색상이 결정되므로 삼각형이 여러 색상으로 표출된다.
이러한 과정 때문에 삼각형을 이동하면 픽셀 위치가 바뀌기 때문에 varying에 의해 삼각형 색상이 바뀐다.
◈ 더 많은 데이터를 vertex shader에 전달하여 fragment shader에 전달할 수 있다.
vertex shader에 attribute를 추가하고, 이를 통해 넘겨 받은 데이터를 varying에 입력하여 fragment shader에 전달한다.
attribute vec2 a_position;
attribute vec4 a_color;
...
varying vec4 v_color;
void main() {
...
// 속성에서 베링으로 색상 복사
v_color = a_color;
}
자바스크립트에서 색상 데이터를 생성하고 추가한 attribute에 이 색상 데이터를 전달한다.
// 정점 데이터가 필요한 곳 탐색
var positionLocation = gl.getAttribLocation(program, "a_position");
var colorLocation = gl.getAttribLocation(program, "a_color");
...
// 색상을 위한 버퍼 생성
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
// 색상 설정
setColors(gl);
...
// 사각형을 만드는 두 삼각형의 색상으로 버퍼 채우기
function setColors(gl) {
// 모든 정점을 다른 색상으로 만들기
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
Math.random(), Math.random(), Math.random(), 1,
Math.random(), Math.random(), Math.random(), 1,
Math.random(), Math.random(), Math.random(), 1,
Math.random(), Math.random(), Math.random(), 1,
Math.random(), Math.random(), Math.random(), 1,
Math.random(), Math.random(), Math.random(), 1
]),
gl.STATIC_DRAW
);
}
Rendering할 때 생성한 buffer에서 색상 데이터를 attribute로 어떻게 가져올지 설정한다.
gl.enableVertexAttribArray(colorLocation);
// 색상 버퍼 할당
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
// colorBuffer(ARRAY_BUFFER)의 데이터를 가져오는 방법을 색상 속성에 지시
var size = 4; // 반복마다 4개의 컴포넌트
var type = gl.FLOAT; // 데이터는 32비트 부동 소수점
var normalize = false; // 데이터 정규화 안 함
var stride = 0; // 0 = 다음 위치를 가져오기 위해 반복마다 size * sizeof(type) 만큼 앞으로 이동
var offset = 0; // 버퍼의 처음부터 시작
gl.vertexAttribPointer(colorLocation, size, type, normalize, stride, offset);
https://myoungmin.github.io/WebGL_Fundamentals/