WebGL - 그래픽 파이프라인

안녕하세요, 야심찬 프로그래머 여러분! 오늘 우리는 WebGL 그래픽 파이프라인을 통해 흥미로운 여정을 떠납니다. 프로그래밍에 처음이라면 걱정하지 마세요 - 나는 당신의 친절한 안내자가 될 것이며, 단계별로 함께 나아갈 것입니다. 이 튜토리얼의 끝을 맞아서, 여러분은 WebGL이 코드를 어떻게 스크린에 훌륭한 시각적으로 변환하는지 확실하게 이해하게 될 것입니다.

WebGL - Graphics Pipeline

자바스크립트: 시작점

WebGL의 깊이로 뛰어들기 전에, 익숙한 것으로부터 시작해 보겠습니다 - 자바스크립트. WebGL은 자바스크립트를 통해 접근되므로, 우리의 모험의 완벽한 출발점입니다.

첫 번째 WebGL 프로그램

간단한 예제로 시작해 보겠습니다:

// 캔버스 요소 가져오기
const canvas = document.getElementById('myCanvas');

// WebGL 컨텍스트 가져오기
const gl = canvas.getContext('webgl');

// 배경색 설정
gl.clearColor(0.0, 0.0, 0.0, 1.0);

// 캔버스 지우기
gl.clear(gl.COLOR_BUFFER_BIT);

이 코드 조각에서 우리는 몇 가지 일을 합니다:

  1. HTML 캔버스 요소에 대한 참조를 가져옵니다.
  2. WebGL 렌더링 컨텍스트를 얻습니다.
  3. 배경색을 설정합니다 (이 경우, 검정색).
  4. 지정된 색상으로 캔버스를 지웁니다.

이것이 많이 보이지 않을 수 있지만, 축하합니다! 여러분은 첫 번째 WebGL 프로그램을 만들었습니다. 마치 거대한 캔버스를 준비하는 것과 같습니다.

베릭스 셰이더: 세상을 형성하는 것

이제 캔버스가 준비되었으므로, 베릭스 셰이더에 대해 이야기해 보겠습니다. 베릭스 셰이더는 3D 세상의 조각가라고 생각해 보세요. 그들은 오브젝트의 원시 데이터 - 베릭스 -을 다룹니다.

간단한 베릭스 셰이더

기본 베릭스 셰이더의 예제를 보겠습니다:

attribute vec4 a_position;

void main() {
gl_Position = a_position;
}

이 셰이더는 간단하지만 매우 중요한 일을 합니다 - 각 베릭스의 위치를 gl_Position에 할당합니다. 마치 3D 오브젝트의 각 점에게 "여기로 가라"고 말하는 것과 같습니다.

원시 어셈블리: 점을 연결하는 것

베릭스 셰이더가 그 일을 마친 후, WebGL은 원시 어셈블리 단계로 넘어갑니다. 이 단계는 마치 점을 연결하는 퍼즐과 같습니다 - 개별 베릭스를 연결하여 형태를 형성합니다.

예를 들어, 삼각형을 그리는 경우, 원시 어셈블리는 세 개의 베릭스를 가져와서 그들이 단일 삼각형을 형성한다고 이해합니다.

래스터라이제이션: 어디서나 픽셀

이제 래스터라이제이션의 마법이 시작됩니다. 이 단계는 3D 형태를 2D 픽셀로 변환합니다. 마치 3D 조각을 상세한 사진으로 만드는 것과 같습니다.

프래그먼트 셰이더: 세상을 칠하는 것

프래그먼트 셰이더는 진정한 예술이 일어나는 곳입니다. 베릭스 셰이더가 오브젝트의 구조를 다루었다면, 프래그먼트 셰이더는 그것을 칠합니다.

간단한 프래그먼트 셰이더

적색으로 칠하는 기본 프래그먼트 셰이더를 보겠습니다:

precision mediump float;

void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

이 셰이더는 gl_FragColor를 적색 벡터로 설정합니다 (전체 적색, 녹색과 파란색 없음, 전체 불투명도). 마치 전체 3D 세상을 적색 페인트로 덮는 것과 같습니다.

프래그먼트 연산: 최종 터치

프래그먼트 셰이더 후, WebGL은 프래그먼트에 다양한 연산을 수행합니다. 이는 깊이 테스트(어느 오브젝트가 다른 오브젝트 앞에 있는지 결정), 투명도 처리(투명한 오브젝트가 어떻게 상호작용하는지) 등을 포함합니다.

프레임 버퍼: 대단한 결말

마지막으로, 프레임 버퍼에 도달합니다. 이는 렌더링된 이미지가 화면에 표시되기 전에 저장되는 곳입니다. 마치 무대 뒤쪽에서 최종 터치를 가하는 것과 같습니다.

모든 것을 함께 모음

이제 각 단계를 거쳐가 보았으므로, 모든 것을 함께 모아보겠습니다. 완전한 WebGL 프로그램을 보겠습니다:

// 베릭스 셰이더 소스 코드
const vsSource = `
attribute vec4 aVertexPosition;

void main() {
gl_Position = aVertexPosition;
}
`;

// 프래그먼트 셰이더 소스 코드
const fsSource = `
precision mediump float;

void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

// 셰이더 초기화
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vsSource);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fsSource);
gl.compileShader(fragmentShader);

// 셰이더 프로그램 생성
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

// 프로그램 사용
gl.useProgram(shaderProgram);

// 버퍼 생성 및 데이터 전송
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
1.0,  1.0,
-1.0,  1.0,
1.0, -1.0,
-1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

// 베릭스 데이터를 베릭스 포지션 속성으로 끌어올리는 방법 지정
const numComponents = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.vertexAttribPointer(
gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
numComponents,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(gl.getAttribLocation(shaderProgram, 'aVertexPosition'));

// 시ーン 그리기
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

이 프로그램은 검정 배경에 간단한 적색 사각형을 그립니다. 이를 분해해 보겠습니다:

  1. 우리는 베릭스와 프래그먼트 셰이더를 정의합니다.
  2. 셰이더를 컴파일하고 프로그램에 연결합니다.
  3. 버퍼를 생성하고 데이터를 전송합니다.
  4. 베릭스 데이터를 베릭스 포지션 속성으로 끌어올리는 방법을 지정합니다.
  5. 캔버스를 지우고 시ーン을 그립니다.

각 단계는 우리가 논의한 그래픽 파이프라인의 단계에 해당합니다. 마치 생산 라인을 지켜보는 것처럼, 원시 데이터(베릭스 데이터)가 완성된 제품(화면에 표시되는 픽셀)으로 변환됩니다.

메서드 표

이 튜토리얼에서 사용한 주요 WebGL 메서드 표입니다:

메서드 설명
gl.createShader() 셰이더 오브젝트 생성
gl.shaderSource() 셰이더의 소스 코드 설정
gl.compileShader() 셰이더 컴파일
gl.createProgram() 프로그램 오브젝트 생성
gl.attachShader() 셰이더 프로그램에 연결
gl.linkProgram() 프로그램 링크
gl.useProgram() 현재 렌더링 상태로 프로그램 설정
gl.createBuffer() 버퍼 오브젝트 생성
gl.bindBuffer() 버퍼 오브젝트를 대상에 바인드
gl.bufferData() 버퍼 오브젝트의 데이터 저장소 생성 및 초기화
gl.vertexAttribPointer() 베릭스 데이터 레이아웃 지정
gl.enableVertexAttribArray() 베릭스 속성 배열 활성화
gl.clearColor() 색상 버퍼 지우기 시 사용할 색상 설정
gl.clear() 버퍼 지우기
gl.drawArrays() 배열 데이터를 사용하여 원시 그리기

이제 WebGL 그래픽 파이프라인을 통해 여러분의 여정이 끝났습니다. 기억하시라, 어떤 기술도 연습이 필요합니다. 하지만 각 코드 줄을 작성할 때마다, 웹 브라우저에서 훌륭한 3D 그래픽을 만드는 데 한 걸음 더 다가갑니다. 계속 실험하고, 배우고, 가장 중요한 것은 즐겁게 만들어 보세요!

Credits: Image by storyset