Getting started with WebGL

WebGL์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  OpenGL ES 2.0 ๊ธฐ๋ฐ˜ API๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์˜ HTML canvas์— ๋ Œ๋”๋งํ•˜์—ฌ 3D ์›น ์ฝ˜ํ…์ธ  ์ œ์ž‘์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. WebGL ํ”„๋กœ๊ทธ๋žจ์€ ์ปดํ“จํ„ฐ์˜ ๊ทธ๋ž˜ํ”ฝ ์ฒ˜๋ฆฌ ์žฅ์น˜(GPU)์—์„œ ์‹คํ–‰๋˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋‚˜ ํŠน์ˆ˜ ํšจ๊ณผ(์…ฐ์ด๋” ์ฝ”๋“œ)์ฝ”๋“œ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. WebGL ์š”์†Œ๋“ค์€ ๋‹ค๋ฅธ HTML ์š”์†Œ๋“ค๊ณผ ํ˜ผํ•ฉ๋  ์ˆ˜ ์žˆ๊ณ  ํŽ˜์ด์ง€๋‚˜ ํŽ˜์ด์ง€ ๋ฐฐ๊ฒฝ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„๊ณผ ํ•ฉ์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์„œ๋Š” ๊ธฐ๋ณธ WebGL ๊ธฐ๋ณธ ์‚ฌํ•ญ์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” 3D ๊ทธ๋ž˜ํ”ฝ์— ๊ด€๋ จ๋œ ์ˆ˜ํ•™์  ์ดํ•ด๋ฅผ ์ด๋ฏธ ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ„์ฃผํ•˜๊ณ  OpenGL ์ž์ฒด์— ๋Œ€ํ•˜์—ฌ ์„ค๋ช…ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

3D ๋ Œ๋”๋ง ์ค€๋น„

WebGL์„ ์‚ฌ์šฉํ•˜์—ฌ 3D ๋ Œ๋”๋ง์„ ํ•˜๋Š” ๋ฐ ์ฒซ ๋ฒˆ์งธ๋กœ ํ•„์š”ํ•œ ๊ฒƒ์€ ์บ”๋ฒ„์Šค์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ HTML ์ฝ”๋“œ๋Š” canvas๋ฅผ ๋งŒ๋“ค๊ณ  ์‚ฌ์šฉํ•  WebGL ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” onload ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

<body onload="start()">
  <canvas id="glcanvas" width="640" height="480">
    Your browser doesn't appear to support the HTML5 <code>&lt;canvas&gt;</code> element.
  </canvas>
</body>

WebGL ์ปจํ…์ŠคํŠธ ์ค€๋น„

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์—์„œ start() ํ•จ์ˆ˜๋Š” ๋ฌธ์„œ๊ฐ€ ๋‹ค ๋ถˆ๋Ÿฌ์™€์ง€๋ฉด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜์˜ ๊ธฐ๋Šฅ์€ WebGL ์ปจํ…์ŠคํŠธ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์ฝ˜ํ…์ธ  ๋ Œ๋”๋ง์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

var gl; // A global variable for the WebGL context

function start() {
  var canvas = document.getElementById("glcanvas");

  gl = initWebGL(canvas);      // Initialize the GL context

  // Only continue if WebGL is available and working

  if (gl) {
    gl.clearColor(0.0, 0.0, 0.0, 1.0);                      // Set clear color to black, fully opaque
    gl.enable(gl.DEPTH_TEST);                               // Enable depth testing
    gl.depthFunc(gl.LEQUAL);                                // Near things obscure far things
    gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);      // Clear the color as well as the depth buffer.
  }
} 

์ฒซ ๋ฒˆ์งธ ํ•  ์ผ์€ canvas์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์–ป๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. canvas๋ผ๋Š” ๋ณ€์ˆ˜์— ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋‹น์—ฐํžˆ canvas๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ฐธ์กฐํ•  ํ•„์š”๋Š” ์—†๊ณ  ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ง€์—ญ ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด์˜ ํ•„๋“œ ๋ฉค๋ฒ„๋กœ ์ฐธ์กฐํ•ด์•ผ ๋ฉ๋‹ˆ๋‹ค.

์บ”๋ฒ„์Šค๊ฐ€ ์žˆ์œผ๋ฉด initWebGL()์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ผ์‹œ์ ์œผ๋กœ ์ •์˜๋˜๊ณ  WebGL ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ปจํ…์ŠคํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ดˆ๊ธฐํ™” ๋˜๋ฉด gl์€ ์ด๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ์˜ˆ์ œ์—์„œ๋Š” ๊ฒ€์€์ƒ‰ ํˆฌ๋ช… ์ƒ‰์ƒ์„ ์„ค์ •ํ•˜๋ฉด ์ปจํ…์ŠคํŠธ๋ฅผ ๊ทธ ์ƒ‰์ƒ์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ ์ปจํ…์ŠคํŠธ๋Š” ์„ค์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ์—์„œ๋Š” ๊นŠ์ด ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐ€๊นŒ์šด ๋ฌผ์ฒด๊ฐ€ ๋ฉ€๋ฆฌ ๋–จ์–ด์ € ์žˆ๋Š” ๋ฌผ์ฒด๋ฅผ ๊ฐ€๋ฆฌ๋Š” ๊ฒƒ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ์—์„œ ์ดˆ๊ธฐํ™”๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ชฉ์ ์€ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๋ ค๋Š” ๊ฒƒ ์ „๋ถ€ ์ž…๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ์‹ค์ œ๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ์–ด๋–ป๊ฒŒ ์‹œ์ž‘ํ•˜๋Š”๊ฐ€ ์•Œ์•„๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

WebGL ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ

initWebGL() ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

function initWebGL(canvas) {
  gl = null;

  try {
    // Try to grab the standard context. If it fails, fallback to experimental.
    gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
  }
  catch(e) {}

  // If we don't have a GL context, give up now
  if (!gl) {
    alert("Unable to initialize WebGL. Your browser may not support it.");
    gl = null;
  }

  return gl;
}

์บ”๋ฒ„์Šค์—์„œ WebGL ์ปจํ…์ŠคํŠธ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด canvas๋กœ "webgl"์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์š”์ฒญํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ์— ์‹คํŒจํ•œ๋‹ค๋ฉด "experimental-webgl"์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์‹œ๋„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด๋งˆ์ €๋„ ์‹คํŒจํ•œ๋‹ค๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ์‚ฌ์šฉ ์ค‘์ธ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ WebGL์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒฝ๊ณ ๋ฅผ ์ถœ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒŒ ์ „๋ถ€์ž…๋‹ˆ๋‹ค. ์ด ์‹œ์ ์—์„œ gl์€ null(WebGL ์ปจํ…์ŠคํŠธ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ)์ด๊ฑฐ๋‚˜ ๋ Œ๋”๋งํ•  WebGL ์ปจํ…์ŠคํŠธ๋ฅผ ์ฐธ์กฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Note: experimental-webgl์ด๋ผ๋Š” ์ด๋ฆ„์€ ์‚ฌ์–‘ ๊ฐœ๋ฐœ ์‹œ ์‚ฌ์šฉ๋˜๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์ผ์‹œ์ ์ธ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. webgl์€ ์‚ฌ์–‘์ด ํ™•์ •๋˜๋ฉด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ ์ด ์ฝ”๋“œ๋Š” WebGL ์ปจํ…์ŠคํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐ ์ถฉ๋ถ„ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๊ฒ€์ • ๋ฐ•์Šค ํ˜•ํƒœ์˜ ๋นˆ ๊ณต๊ฐ„์ด ํ˜•์„ฑ๋˜๋ฉฐ, ์—ฌ๊ธฐ์— ์ฝ˜ํ…์ธ ๋ฅผ ์ƒ์„ฑํ•  ๊ธฐ๋ณธ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ WebGL์„ ํ˜ธํ™˜ํ•œ๋‹ค๋ฉด ์‹คํ–‰๋  ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

WebGL ์ปจํ…์ŠคํŠธ ํฌ๊ธฐ ์กฐ์ •

์ด์ œ ์ƒˆ๋กœ์šด WebGL ์ปจํ…์ŠคํŠธ๋Š” ์ƒˆ๋กœ์šด ์ปจํ…์ŠคํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  CSS ์—†์ด ์บ”๋ฒ„์Šค ์š”์†Œ์˜ height์™€ width๋กœ ๋ทฐํฌํŠธ์˜ ํ•ด์ƒ๋„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์บ”๋ฒ„์Šค ์š”์†Œ์˜ ์Šคํƒ€์ผ ํŽธ์ง‘ํ•˜๋ฉด ์ถœ๋ ฅ๋˜๋Š” ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝ๋  ๊ฒƒ์ด์ง€๋งŒ ๋ Œ๋”๋ง ํ•ด์ƒ๋„๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋œ ํ›„ ์บ”๋ฒ„์Šค ์š”์†Œ์˜ width์™€ height ์†์„ฑ์„ ํŽธ์ง‘ํ•˜๋ฉด ๊ทธ๋ ค์ง€๋Š” ํ”ฝ์…€ ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. WebGL ๋ Œ๋”์˜ ํ•ด์ƒ๋„๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์บ”๋ฒ„์Šค ๋ฌธ์„œ ์ „์ฒด ์ฐฝ ํฌ๊ธฐ๋ฅผ ์กฐ์ •ํ•˜๊ฑฐ๋‚˜ ์•ฑ์—์„œ ๊ทธ๋ž˜ํ”ฝ ์„ค์ •์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธธ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. WebGL ์ปจํ…์ŠคํŠธ viewport() ํ•จ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝํ•  ์ˆ˜์žˆ๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ Œ๋”๋ง๋œ WebGL ์ปจํ…์ŠคํŠธ์˜ ํ•ด์ƒ๋„๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ์œ„์— ๋‚˜์˜ค๋Š” gl๊ณผ canvas ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๋ฉ๋‹ˆ๋‹ค.

gl.viewport(0, 0, canvas.width, canvas.height);

์บ”๋ฒ„์Šค๋Š” CSS ์Šคํƒ€์ผ๊ณผ ๋‹ค๋ฅธ ํ•ด์ƒ๋„๋กœ ๋ Œ๋”๋ง๋˜์–ด์งˆ ๋•Œ ํ™”๋ฉด์—์„œ ์ฐจ์ง€ํ•˜๋Š” ํฌ๊ธฐ๋ฅผ ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. CSS๋กœ ํฌ๊ธฐ๋ฅผ ์กฐ์ •ํ•˜๋ฉด ๋‚ฎ์€ ํ•ด์ƒ๋„์—์„œ ๋ Œ๋”๋งํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด์„ ํ™•๋Œ€ํ•  ๋•Œ ์ž์›์„ ์ ˆ์•ฝํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ถ•์†Œ๋Š” ์Šˆํผ์ƒ˜ํ”Œ ์•ˆํ‹ฐ์—์ผ๋ฆฌ์–ด์‹ฑ(SSAA) ํšจ๊ณผ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. (๋งŽ์€ ์„ฑ๋Šฅ ๋น„์šฉ์ด ๋ฐœ์ƒํ•˜๊ณ  ์ž‘์€ ๊ฒฐ๊ณผ์ด๊ธฐ๋Š” ํ•˜์ง€๋งŒ) ์•„๋ž˜์— ์ฐธ๊ณ  ์‚ฌํ•ญ์„ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค.

  • WebGL์— ๋Œ€ํ•œ ์†Œ๊ฐœ - DEV.OPERA์— ์žˆ๋Š” Luz Caballero๊ฐ€ ์ž‘์„ฑํ•œ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ๋Š” WebGL์ด ๋ฌด์—‡์ธ์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™๋˜๋Š”์ง€, ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ ๊ฐœ๋…์— ๋Œ€ํ•˜์—ฌ ์„ค๋ช…ํ•˜๊ณ  ๋ช‡ ๊ฐ€์ง€ WebGL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•˜์—ฌ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.
  • ํ˜„๋Œ€ OpenGL์— ๋Œ€ํ•œ ์†Œ๊ฐœ - Joe Groff๊ฐ€ ์ž‘์„ฑํ•œ OpenGL์— ๋Œ€ํ•œ ์ข‹์€ ๋ฌธ์„œ ์‹œ๋ฆฌ์ฆˆ์ž…๋‹ˆ๋‹ค. ์กฐ๋Š” ๋ช…ํ™•ํ•˜๊ฒŒ ์—ญ์‚ฌ๋ฅผ ๊ฐ€์ง€๊ณ  OpenGL์˜ ์ค‘์š”ํ•œ ๊ทธ๋ž˜ํ”ฝ ํŒŒ์ดํ”„๋ผ์ธ ๊ฐœ๋…์— ๋Œ€ํ•ด ์†Œ๊ฐœํ•˜๊ณ  ๋ช‡ ๊ฐ€์ง€ ๋ฐ๋ชจ๋ฅผ ํ†ตํ•ด OpenGL์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™๋˜๋Š”์ง€ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์˜ˆ์ œ๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ OpenGL์— ๋Œ€ํ•œ ๊ฐœ๋…์ด ์•ˆ ์žกํ˜€ ์žˆ๋‹ค๋ฉด ์‹œ์ž‘ํ•˜๊ธฐ ์ข‹์€ ์žฅ์†Œ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.