WebGL - 캐브 소환
안녕하세요, 미래의 WebGL 마법사 여러분! 오늘 우리는 3D 그래픽의 세계로 흥미로운 여정을 떠납니다. 이 튜토리얼의 끝까지 따라오시면, WebGL을 사용하여 회전하는 캐브를 만들 수 있게 될 것입니다. 멋지지 않나요? 시작해보겠습니다!
기본 개념 이해
캐브를 DJ처럼 돌리기 전에, 몇 가지 기본 개념을 이해해보겠습니다.
WebGL이란?
WebGL (Web Graphics Library)는 브라우저에서 3D 그래픽을 렌더링할 수 있도록 해주는 JavaScript API입니다. 브라우저에 3D 안경을 씌우는 것과 같습니다!
왜 캐브인가요?
"왜 캐브로 시작하나요?"라는 의문이 드실 수 있습니다. 그러나 캐브는 3D 그래픽의 "Hello World"입니다. 이해하기 쉬우면서도 중요한 개념을 가르쳐줄 만큼 복잡합니다. 그리고, 누가 캐브를 좋아하지 않을까요?
WebGL 환경 설정
HTML 캔버스
먼저, 캐브가 공연할 무대가 필요합니다. WebGL에서 이 무대를 캔버스라고 합니다. 설정해보겠습니다:
<canvas id="glcanvas" width="640" height="480">
Your browser doesn't support HTML5 canvas
</canvas>
이렇게 하면 640x480 픽셀의 캔버스를 만듭니다. 보이지 않는다면 걱정하지 마세요 - 지금은 보이지 않는 춤의 무대입니다.
WebGL 초기화
이제 WebGL을 준비해보겠습니다:
var canvas = document.getElementById('glcanvas');
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('WebGL not supported, falling back on experimental-webgl');
gl = canvas.getContext('experimental-webgl');
}
if (!gl) {
alert('Your browser does not support WebGL');
}
이 코드는 우리의 WebGL 컨텍스트를 가져옵니다. 브라우저가 WebGL을 지원하지 않으면, VHS 플레이어에서 DVD를 재생하려는 것과 같이 작동하지 않습니다!
3D 캐브 생성
꼭짓점 정의
캐브는 8개의 꼭짓점(頂点)을 가지고 있습니다. WebGL에 이 꼭짓점이 어디 있는지 알려줘야 합니다:
var vertices = [
// 앞면
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// 뒷면
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// 윗면
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// 아랫면
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// 오른쪽면
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// 왼쪽면
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0
];
각 세트의 세 개의 숫자는 캐브의 꼭짓점을 3D 공간에서 나타냅니다. WebGL에 캐브의 지도를 주는 것과 같습니다!
버퍼 생성
이제 이 데이터를 GPU로 보내야 합니다:
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
이것은 캐브를 가방(버퍼)에 싸서 GPU로 보내는 것과 같습니다.
셰이더 - WebGL의 마법사
顶点 셰이더
顶点 셰이더는顶点의 위치를 설정합니다:
var vertexShaderSource = `
attribute vec3 aVertexPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
}
`;
이 셰이더는 각顶点에 우리의 변환 행렬을 적용합니다. 마법사가顶点을 이동시키는 것과 같습니다!
프래그먼트 셰이더
프래그먼트 셰이더는 캐브를 칠합니다:
var fragmentShaderSource = `
void main(void) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
이 간단한 셰이더는 모든 것을 흰색으로 칠합니다. 캐브를 칠하는 것과 같습니다!
셰이더 컴파일 및 링크
이제 셰이더를 컴파일하고 프로그램에 링크합니다:
function getShader(gl, source, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var vertexShader = getShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
var fragmentShader = getShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
}
gl.useProgram(shaderProgram);
이것은 마법사(셰이더)를 가르치고 무대에 올리는 것과 같습니다!
캐브 회전
회전 설정
캐브를 회전시키기 위해 시간이 지남에 따라 회전 각도를 업데이트해야 합니다:
var cubeRotation = 0.0;
function render(now) {
now *= 0.001; // convert to seconds
const deltaTime = now - then;
then = now;
cubeRotation += deltaTime;
drawScene();
requestAnimationFrame(render);
}
이 함수는 반복적으로 호출되어 캐브의 회전을 갱신합니다.
그리기 함수
이제 모든 것을 합쳐서 회전하는 캐브를 그리겠습니다:
function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
const modelViewMatrix = mat4.create();
mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]);
mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotation, [0, 1, 1]);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), false, projectionMatrix);
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), false, modelViewMatrix);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 36);
}
이 함수는 캔버스를 지우고 시점을 설정하고 회전을 적용한 후 캐브를 그립니다.
결론
그렇습니다, 여러분! 우리는 WebGL을 사용하여 회전하는 3D 캐브를 만들었습니다. WebGL을 마스터하는 것은 저그링하는 것과 같습니다 - 연습이 필요하지만, 한 번 익혀지면 놀라운 것을 할 수 있습니다!
여기 우리가 사용한 주요 메서드를 요약한 표입니다:
메서드 | 설명 |
---|---|
gl.createBuffer() |
새로운 버퍼 객체 생성 |
gl.bindBuffer() |
버퍼 객체를 대상에 바인드 |
gl.bufferData() |
버퍼 객체의 데이터 저장소 생성 및 초기화 |
gl.createShader() |
셰이더 객체 생성 |
gl.shaderSource() |
셰이더 객체의 소스 코드 설정 |
gl.compileShader() |
셰이더 객체 컴파일 |
gl.createProgram() |
프로그램 객체 생성 |
gl.attachShader() |
셰이더 객체를 프로그램 객체에 첨부 |
gl.linkProgram() |
프로그램 객체 링크 |
gl.useProgram() |
지정된 프로그램을 현재 렌더링 상태로 설정 |
gl.clear() |
버퍼를 기본값으로 지우기 |
gl.uniformMatrix4fv() |
일관된 4x4 행렬을 일관된.uniform 변수에 지정 |
gl.drawArrays() |
배열 데이터에서 프리미티브 렌더링 |
계속 연습하고, 계속 코딩하면 곧 브라우저에서 놀라운 3D 그래픽을 만들 수 있을 것입니다. 행복한 코딩을 기원합니다!
Credits: Image by storyset