WebGL: 3D 그래픽의 초보자 가이드

안녕하세요, 미래의 3D 그래픽 마법사 여러분! 이 흥미로운 여정에서 여러분의 가이드로서 WebGL의 세계로 안내해 드리게 되어 기쁩니다. 컴퓨터 그래픽을 몇 년 동안 가르쳐온 사람으로서, WebGL은 웹 브라우저의 마법 지팡이似的 존재입니다. 웹 페이지에서 놀라운 3D 그래픽과 애니메이션을 만들 수 있게 해줍니다. 멋지지 않나요? 시작해 보겠습니다!

WebGL - Home

WebGL은 무엇인가요?

WebGL은 Web Graphics Library의 약자로, JavaScript API를 통해 호환되는 모든 웹 브라우저에서 상호작용식 2D 및 3D 그래픽을 렌더링할 수 있게 해줍니다. 웹 브라우저에 슈퍼파워를 주어 놀라운 시각적 경험을 만들 수 있게 해줍니다!

간략한 역사

WebGL은 2011년 처음 소개되었으며, 이후 웹에서 그래픽을 어떻게 생각하는지 혁명을 일으켰습니다. WebGL 이전에는 브라우저에서 3D 그래픽을 만들기 위해서는 플래시나 자바 애플릿과 같은 플러그인에 의존해야 했습니다. 이제 WebGL을 통해 브라우저 내에서 nativ으로 모든 것을 할 수 있습니다. 자전거에서 스포츠카로 업그레이드한 것 같아요!

준비물

WebGL의 모험을 시작하기 전, 필요한 도구를 확인해 보겠습니다:

  1. 최신 웹 브라우저 (크롬, 파이어폭스, 사파리, 엣지)
  2. 텍스트 에디터 (Visual Studio Code를 추천하지만, 다른 것도 괜찮습니다)
  3. HTML과 JavaScript의 기본 지식 (생疏하다면 걱정하지 마세요, 함께 복습해 나갈게요)

WebGL 시작하기

우리의 첫 WebGL 프로그램을 만들어 보겠습니다! 간단한 "Hello, WebGL!" 예제를 통해 화면에 색칠된 삼각형을 표시해 보겠습니다.

Step 1: HTML 설정

먼저, 캔버스 요소를 포함하는 HTML 파일을 생성해야 합니다. 이 캔버스는 우리의 WebGL 마법이 일어나는 곳입니다.

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Hello, WebGL!</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="glCanvas" width="640" height="480"></canvas>
<script src="webgl-demo.js"></script>
</body>
</html>

이 HTML에서 우리는 ID가 "glCanvas"인 캔버스 요소를 생성하고 크기를 640x480 픽셀로 설정했습니다. 또한, "webgl-demo.js"라는 JavaScript 파일을 링크하여 WebGL 코드를 작성할 예정입니다.

Step 2: WebGL 초기화

이제 "webgl-demo.js" 파일을 생성하고 JavaScript를 작성하여 WebGL을 초기화해 보겠습니다:

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("WebGL을 초기화할 수 없습니다. 브라우저나 기계가 지원하지 않을 수 있습니다.");
return;
}

// 배경색을 검정색으로 설정하고 캔버스를 지운다
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
}

window.onload = main;

이 코드는 다음과 같은 작업을 수행합니다:

  1. 캔버스 요소를 참조합니다.
  2. WebGL 컨텍스트를 캔버스에서 가져려고 시도합니다. 실패하면 오류 메시지를 표시합니다.
  3. 성공하면 배경색을 검정색으로 설정하고 캔버스를 지웁니다.

Step 3: 셰이더 생성

셰이더는 GPU에서 실행되는 특별한 프로그램입니다. GLSL(OpenGL Shading Language)이라는 언어로 작성됩니다. 우리는 두 가지 유형의 셰이더가 필요합니다:顶点 셰이더와 프래그먼트 셰이더.

//顶点 셰이더 프로그램
const vsSource = `
attribute vec4 aVertexPosition;

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

// 프래그먼트 셰이더 프로그램
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

顶点 셰이더는 우리의顶点을 위치시키고, 프래그먼트 셰이더는 우리의 픽셀을 색칠합니다 (이 경우 빨간색).

Step 4: 셰이더 프로그램 초기화

이제 셰이더를 컴파일하고 링크하여 셰이더 프로그램을 초기화해야 합니다:

function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('셰이더 프로그램을 초기화할 수 없습니다: ' + gl.getProgramInfoLog(shaderProgram));
return null;
}

return shaderProgram;
}

function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('셰이더 컴파일 중 오류가 발생했습니다: ' + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}

return shader;
}

이 코드는 셰이더를 컴파일하고 링크하여 프로그램을 생성하고, 오류를 검사합니다.

Step 5: 삼각형 데이터 생성

이제 삼각형의 데이터를 만들어 보겠습니다:

function initBuffers(gl) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

const positions = [
-1.0,  1.0,
1.0,  1.0,
-1.0, -1.0,
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

return {
position: positionBuffer,
};
}

이 코드는 버퍼를 생성하고 삼각형의顶点 위치 데이터를 초기화합니다.

Step 6: 시ーン 그리기

마지막으로, 모든 것을 합쳐 삼각형을 그리겠습니다:

function drawScene(gl, programInfo, buffers) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.useProgram(programInfo.program);

gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
2,        // 각 반복마다 2개의 컴포넌트
gl.FLOAT, // 데이터는 32비트 플로트
false,    // 정규화하지 않음
0,        // 스트라이드 (0 = 자동)
0         // 버퍼 내의 오프셋
);

gl.drawArrays(gl.TRIANGLES, 0, 3);
}

이 함수는 캔버스를 지우고 셰이더 프로그램을 설정하고, 버퍼 데이터를 연결한 후 삼각형을 그립니다.

모든 것을 합치기

이제 main 함수를 업데이트하여 모든 조각을 사용하도록 하겠습니다:

function main() {
const canvas = document.getElementById("glCanvas");
const gl = canvas.getContext("webgl");

if (!gl) {
alert("WebGL을 초기화할 수 없습니다. 브라우저나 기계가 지원하지 않을 수 있습니다.");
return;
}

const shaderProgram = initShaderProgram(gl, vsSource, fsSource);

const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
},
};

const buffers = initBuffers(gl);

drawScene(gl, programInfo, buffers);
}

window.onload = main;

이제 HTML 파일을 브라우저에서 열면 검정 배경에 빨간색 삼각형이 표시되어야 합니다. 축하합니다! 첫 WebGL 프로그램을 완성했습니다!

일반 WebGL 메서드

다음은 사용한 일반 WebGL 메서드와 그 목적에 대한 표입니다:

메서드 목적
gl.createBuffer() 새 버퍼 객체 생성
gl.bindBuffer() 버퍼 객체를 타겟에 바인드
gl.bufferData() 버퍼 객체의 데이터 스토어를 초기화 및 생성
gl.createShader() 셰이더 객체 생성
gl.shaderSource() 셰이더 객체의 소스 코드 설정
gl.compileShader() 셰이더 객체 컴파일
gl.createProgram() 프로그램 객체 생성
gl.attachShader() 셰이더 객체를 프로그램 객체에 첨부
gl.linkProgram() 프로그램 객체 링크
gl.useProgram() 현재 렌더링 상태의 지정 프로그램 설정
gl.getAttribLocation() 어트리뷰트 변수의 위치 반환
gl.enableVertexAttribArray() 顶点 어트리뷰트 배열 활성화
gl.vertexAttribPointer() 顶点 어트리뷰트 데이터 레이아웃 지정
gl.drawArrays() 배열 데이터로 프리미티브 렌더링

결론

와우, 오늘 많은 내용을 다루었네요! WebGL이 무엇인지 배웠고, 개발 환경을 설정하고 첫 WebGL 프로그램을 만들었습니다. WebGL을 배우는 것은 자전거 타는 것과 같아요 -처음에는 흔들릴 수 있지만, 연습을 하면 얼마 지나지 않아 빠르게 달릴 수 있을 거예요!

미래의 강의에서는 더 복잡한 형태를 탐구하고 상호작용성을 추가하며, 3D 그래픽으로 깊이 더 들어갈 거예요. WebGL의 세계는 방대하고 흥미롭습니다. 함께 더 많은 것을 탐험해 나가자. 다음 시간에 다시 만나요! 행복한 코딩을!

Credits: Image by storyset