본문으로 이동
메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.
Web Graphics Library, WebGL; 웹지엘
플러그인 없이 웹 브라우저에서 GPU 가속 2D·3D 그래픽을 그리는 OpenGL ES 기반 자바스크립트 API

WebGL(Web Graphics Library)은 HTML <canvas> 요소 위에 GPU 가속 그래픽을 그리는 자바스크립트 API다. 비영리 표준 단체 크로노스 그룹(Khronos Group)이 관리하며, 모바일·임베디드용 그래픽 API인 OpenGL ES를 거의 그대로 웹에 옮긴 형태다. WebGL 1.0은 OpenGL ES 2.0, WebGL 2.0은 OpenGL ES 3.0에 대응한다.[1]

WebGL 이전에는 웹에서 3D를 그리려면 Flash의 Stage3D, Java 애플릿, Unity Web Player 같은 플러그인이 필요했다. WebGL은 브라우저에 내장되어 설치 없이 동작하고, 캔버스가 일반 DOM 요소라 HTML·CSS와 섞어 배치할 수 있다. 3D 모델 뷰어, 지도, 데이터 시각화, 브라우저 게임, CAD, 가상 현실(WebXR)의 렌더링 기반으로 쓰인다.

WebGL은 W3C나 WHATWG가 아니라 크로노스 그룹의 명세다. HTML5 표준에 들어 있지 않지만 모든 주요 브라우저가 구현하므로 사실상 웹 표준처럼 취급된다.

버전 기반 명세 컨텍스트 이름 셰이더 언어
WebGL 1.0 OpenGL ES 2.0 2011년 3월 3일(GDC에서 발표) "webgl"(초기 "experimental-webgl") GLSL ES 1.00
WebGL 2.0 OpenGL ES 3.0 2017년 1월 "webgl2" GLSL ES 3.00(#version 300 es)

WebGL 2.0에서 기본 기능이 된 것은 3D 텍스처와 텍스처 배열, 인스턴스 렌더링, 다중 렌더 타깃(MRT), 트랜스폼 피드백, 유니폼 버퍼 객체(UBO), 정수 텍스처와 정수 연산, 오클루전 쿼리, 비정규화 좌표 샘플러 객체, 2의 거듭제곱이 아닌 텍스처의 완전한 지원 등이다. WebGL 1에서는 확장(ANGLE_instanced_arrays, WEBGL_draw_buffers, OES_vertex_array_object 등)으로만 쓸 수 있던 것들이다.[2] 컴퓨트 셰이더는 WebGL 2에도 없다. OpenGL ES 3.1의 컴퓨트 셰이더를 넣으려던 "WebGL 2.0 Compute" 작업도 있었지만, WebGPU에 자리를 넘기고 중단된 것으로 알려져 있다.

렌더링 파이프라인

편집 원본 편집

OpenGL ES 2.0처럼 WebGL에는 OpenGL 1.x의 고정 기능 파이프라인(glBegin, 조명·행렬 스택 등)이 없다. 정점 변환, 조명, 색칠은 모두 개발자가 셰이더로 짜야 한다.

  1. 자바스크립트가 정점 좌표, 법선, 텍스처 좌표 같은 데이터를 Float32Array 등 형식화 배열에 담아 GPU 버퍼(gl.createBuffer(), gl.bufferData())로 올린다.
  2. 정점 셰이더(vertex shader)가 정점마다 한 번 실행되어 화면 좌표(gl_Position)를 계산한다. 보통 모델·뷰·투영 행렬을 곱한다.
  3. GPU가 정점을 삼각형으로 조립하고 잘라 내기(clipping)와 래스터화를 거쳐 픽셀 후보(프래그먼트)를 만든다.
  4. 프래그먼트 셰이더(fragment shader)가 픽셀마다 실행되어 색을 계산한다. 텍스처 샘플링, 조명 계산이 여기서 일어난다.
  5. 깊이 검사, 스텐실 검사, 블렌딩을 거쳐 프레임버퍼(캔버스 또는 오프스크린 텍스처)에 기록된다.

자바스크립트는 상태 설정과 그리기 명령(gl.drawArrays(), gl.drawElements())만 내리고, 무거운 계산은 GPU가 병렬로 처리한다.

셰이더는 C와 비슷한 OpenGL ES 셰이딩 언어(GLSL ES, ESSL)로 쓰고, 문자열로 WebGL API에 넘기면 브라우저가 컴파일해 GPU 코드로 바꾼다. 다음은 삼각형 하나를 그리는 최소 예다.

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');           // WebGL 2 컨텍스트

const vsSource = `#version 300 es
in vec2 aPos;
void main() { gl_Position = vec4(aPos, 0.0, 1.0); }`;

const fsSource = `#version 300 es
precision mediump float;
out vec4 outColor;
void main() { outColor = vec4(1.0, 0.4, 0.1, 1.0); }`;

function compile(type, src) {
  const s = gl.createShader(type);
  gl.shaderSource(s, src);
  gl.compileShader(s);
  if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(s));
  return s;
}
const prog = gl.createProgram();
gl.attachShader(prog, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(prog);
gl.useProgram(prog);

const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.8, -0.8, -0.8, 0.8, -0.8]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(prog, 'aPos');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);

삼각형 하나에 이만큼의 코드가 필요할 정도로 API가 저수준이라, 실무에서는 대개 아래 라이브러리를 쓴다.

브라우저 구현과 ANGLE

편집 원본 편집

브라우저는 WebGL 호출을 그대로 GPU 드라이버에 넘기지 않는다. 인자를 검증하고, 셰이더 소스를 파싱해 위험한 구문을 걸러 낸 뒤 플랫폼 API로 번역한다. Chrome과 Firefox는 Google의 오픈 소스 계층 ANGLE(Almost Native Graphics Layer Engine)을 써서 Windows에서는 Direct3D 11로, 최근에는 macOS에서 Metal, 일부 플랫폼에서 Vulkan으로 번역한다. Windows의 OpenGL 드라이버 품질이 고르지 않았던 것이 ANGLE을 쓰게 된 이유다. Chrome에서는 GPU 명령을 별도 GPU 프로세스가 실행해, 드라이버가 죽어도 브라우저 전체가 죽지 않게 한다.

GPU는 여러 프로그램이 공유하므로 드라이버 리셋이나 다른 프로그램 때문에 컨텍스트를 잃을 수 있다. WebGL 앱은 webglcontextlost, webglcontextrestored 이벤트를 받아 자원을 다시 만들어야 한다.

라이브러리와 도구

편집 원본 편집
이름 성격
Three.js 가장 널리 쓰이는 범용 3D 라이브러리. 장면 그래프, 카메라, 재질, 조명, glTF 로더를 제공한다. WebGL 1.0 발표 당시 이미 존재하던 미들웨어로 크로노스 보도 자료에도 이름이 나온다[1]
Babylon.js Microsoft 개발자들이 시작한 3D 게임·렌더링 엔진. 물리, 편집기, WebXR, WebGPU 백엔드 지원
PlayCanvas 웹 기반 편집기를 가진 오픈 소스 게임 엔진
PixiJS WebGL 기반 2D 렌더러. WebGL이 없으면 Canvas 2D로 대체
A-Frame HTML 태그로 VR 장면을 기술하는 프레임워크(Three.js 기반)
deck.gl, Mapbox GL JS, MapLibre GL, CesiumJS 대용량 지도·지리 데이터 시각화
regl, twgl.js WebGL 호출을 얇게 감싸 상태 관리를 쉽게 하는 저수준 도우미
Unity, Unreal Engine 4 게임 엔진의 웹 빌드 대상. Unity의 "WebGL" 빌드는 C# 코드를 WebAssembly로, 그래픽을 WebGL로 출력한다

3D 모델 교환 형식 glTF는 원래 "WebGL Transmission Format"으로 시작한 크로노스 표준으로, 웹 3D 자산의 사실상 표준이다. Sketchfab 같은 서비스는 업로드한 모델을 WebGL 뷰어로 보여 준다.

사용 사례로는 Google 지도의 3D 보기, Google Earth 웹판, Figma의 캔버스 렌더러, CAD 서비스 Onshape와 Autodesk의 웹판 도구, 인체 해부 모델 Zygote Body, NASA의 화성 탐사선 시뮬레이션 Experience Curiosity, Chrome Experiments의 데모(유체 시뮬레이션, 레이 트레이싱) 등이 있다.

WebGPU는 W3C GPU for the Web 작업 그룹이 만든 후속 API다. OpenGL 계열 대신 Direct3D 12, Metal, Vulkan 같은 현대 저수준 그래픽 API의 구조를 따른다. Chrome 113(2023년)이 처음 출시했고, 2025년 Firefox 141(Windows)과 Safari 26이 뒤따르면서 주요 브라우저 모두가 지원하게 되었다.[3]

항목 WebGL WebGPU
모델 OpenGL ES 2.0/3.0 Direct3D 12, Metal, Vulkan 스타일
표준화 크로노스 그룹 W3C
상태 관리 전역 상태 기계(바인딩을 바꿔 가며 그림) 파이프라인·바인드 그룹 객체를 미리 만들어 검증
명령 제출 호출 즉시 명령 버퍼에 기록 후 큐에 제출
셰이더 언어 GLSL ES WGSL
컴퓨트 셰이더 없음 있음(GPGPU, 머신러닝 추론)
워커·멀티스레드 OffscreenCanvas로 워커에서 렌더링 가능 설계 단계부터 워커 친화적
CPU 부하 그리기 호출마다 검증 비용 검증을 앞당겨 호출당 비용이 낮음
지원 범위 거의 모든 브라우저·기기 최신 브라우저·기기

WebGL은 사실상 기능 확장이 끝난 상태이고, 새 기능은 WebGPU로 간다. 다만 지원 범위가 넓어 한동안은 WebGL이 기본 대체 경로로 남는다. Three.js, Babylon.js 같은 라이브러리는 두 백엔드를 모두 지원한다. WebGPU가 가능해진 뒤로 브라우저 안 대형 언어 모델 추론(WebLLM 등)처럼 GPGPU 용도가 크게 늘었다.

초기 보안 논란

편집 원본 편집

WebGL은 웹 페이지의 코드를 GPU 드라이버까지 전달하므로, 도입 초기부터 공격 표면이 커진다는 우려가 있었다. 2011년 보안 회사 Context Information Security가 두 차례 보고서("WebGL: A New Dimension for Browser Exploitation" 등)에서 다음 문제를 지적했다.

  • 서비스 거부: 끝나지 않는 셰이더나 거대한 그리기 호출로 GPU를 멈추게 해 시스템 전체를 먹통으로 만들 수 있다.
  • 교차 출처 이미지 탈취: 다른 출처의 이미지를 텍스처로 쓰고 셰이더 실행 시간 차이로 픽셀 값을 추론할 수 있다.
  • 드라이버 취약점: 드라이버의 메모리 오류가 원격에서 노출된다.

같은 해 6월 16일 Microsoft 보안 대응 센터(MSRC)는 "WebGL Considered Harmful" 글에서 하드웨어 기능을 웹에 지나치게 직접 노출하고, 보안 패치 책임이 GPU 제조사 같은 제3자에게 많이 넘어간다는 이유로 당시로서는 Microsoft의 보안 개발 수명 주기 기준을 통과하기 어렵다고 밝혔다.[4] 그러나 Microsoft도 2013년 Internet Explorer 11에서 WebGL을 지원했다.

브라우저와 크로노스는 대응책을 명세와 구현에 넣었다. 교차 출처 이미지와 동영상은 CORS 허용(img.crossOrigin = "anonymous"와 서버의 Access-Control-Allow-Origin)이 있어야 텍스처로 쓸 수 있게 했고, 셰이더 검증기, 버퍼 범위 검사, 초기화하지 않은 메모리를 0으로 채우기, GPU 리셋 감지(ARB_robustness)와 컨텍스트 손실 이벤트, 문제가 많은 드라이버를 막는 블랙리스트를 도입했다.

GPU 핑거프린팅

편집 원본 편집

WebGL은 브라우저 핑거프린팅의 주요 재료다.

  • WEBGL_debug_renderer_info 확장의 UNMASKED_VENDOR_WEBGL, UNMASKED_RENDERER_WEBGL 값으로 GPU 제조사와 모델명(예: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 ...)")을 읽을 수 있다.[5]
  • 지원 확장 목록, 최대 텍스처 크기 같은 한계값, 셰이더 정밀도가 기기마다 다르다.
  • 같은 장면을 그려도 GPU·드라이버에 따라 픽셀 값이 미세하게 달라, 렌더링 결과의 해시가 식별자가 된다(캔버스 핑거프린팅의 WebGL판).


대응으로 Firefox의 privacy.resistFingerprinting, Tor 브라우저, Brave 등은 렌더러 문자열을 일반화하거나 값을 흔든다. Firefox는 about:config의 webgl.disabled를 true로 바꿔 WebGL을 완전히 끌 수 있고, Chrome은 명령줄 옵션이나 정책으로 끌 수 있다.

  • 2006년: Mozilla의 블라디미르 부키체비치(Vladimir Vukićević)가 <canvas>에 OpenGL 컨텍스트를 붙이는 "Canvas 3D" 시제품을 만든 것으로 알려져 있다. WebGL은 이 작업에서 출발했다.[6]
  • 2007년 말: Mozilla와 Opera가 각자 3D 캔버스를 구현했다.
  • 2009년 초: 크로노스 그룹이 Apple, Google, Mozilla, Opera 등과 함께 WebGL 작업 그룹을 만들었다.
  • 2011년 3월 3일: GDC에서 WebGL 1.0 최종 명세가 발표되었다. Firefox 4 베타, Chrome 9, Opera 미리 보기판, Safari 나이틀리 빌드에 구현이 들어가 있었다. 같은 발표에서 OpenCL을 웹에 옮기는 WebCL 작업 그룹도 소개되었다(WebCL은 브라우저에 채택되지 않았다).[1]
  • 2011년 2~3월: Chrome 9, Firefox 4 정식판이 WebGL을 기본 활성화했다.
  • 2012년 11월: Autodesk가 Fusion 등 클라우드 도구를 WebGL 클라이언트로 제공한다고 발표했다.
  • 2013년: Internet Explorer 11이 WebGL을 지원했다(초기에는 적합성 시험 일부 미통과).
  • 2014년: iOS 8과 Safari 8이 WebGL을 기본 활성화했다. 크로노스에 따르면 이해 9월 WebGL 1.0이 전체 브라우저의 80%에서 쓸 수 있게 되었다.[2]
  • 2017년 1월: WebGL 2.0 명세가 완성되고 Firefox 51, Chrome 56이 처음 출시했다.
  • 2021년 9월: Safari 15가 macOS와 iOS 모두에서 WebGL 2.0을 기본 지원했다.
  • 2022년 2월 9일: 크로노스가 WebGL 2.0이 모든 주요 브라우저에서 지원된다고 발표했다.[2]
  • 2023년 이후: 후속 API WebGPU가 브라우저에 출시되기 시작했다.

현재 Chrome, Edge, Firefox, Safari, Opera, Samsung Internet 등 주요 브라우저는 데스크톱과 모바일 모두 WebGL 1.0과 2.0을 지원한다. Firefox 계열 포크인 Pale Moon도 지원한다. 예외는 서버에서 페이지를 미리 렌더링하는 Opera Mini이고, Internet Explorer 11은 WebGL 1.0을 부분적으로만 지원했다. 브라우저가 지원해도 GPU나 드라이버가 차단 목록에 있거나 원격 데스크톱·가상 머신처럼 GPU가 없는 환경이면 소프트웨어 렌더러(SwiftShader 등)로 느리게 동작하거나 아예 쓸 수 없다. 사용 가능 여부는 canvas.getContext('webgl2')가 null을 돌려주는지로 확인한다.