목차

WebGLFundamentals.org

Fix, Fork, Contribute

WebGL 알파

WebGL이 백버퍼(ie, 캔버스)에서 알파를 처리하는 방법에 문제를 겪는 일부 OpenGL 개발자들을 발견해서, 알파와 관련하여 WebGL과 OpenGL의 차이점을 살펴보는 것도 좋을 것이라 생각했습니다.

OpenGL과 WebGL의 가장 큰 차이점으로 OpenGL은 어떤 것과도 합성되지 않거나, 실제로 OS 윈도우 매니저에 의해 어떤 것도 합성되지 않은, 백버퍼에 렌더링하므로 알파가 무언인지는 중요하지 않습니다.

WebGL은 브라우저에 의해 웹 페이지와 합성되고 기본값으로 투명도가 있는 .png <img> 태그와 2D 캔버스 태그와 동일한 pre-multiplied 알파를 사용합니다.

WebGL은 이걸 좀 더 OpenGL처럼 만들기 위한 여러 방법을 가지고 있습니다.

#1) WebGL에 non-premultiplied 알파와 합성을 원한다고 알림

gl = canvas.getContext("webgl", {
  premultipliedAlpha: false  // non-premultiplied 알파 요청
});

기본값은 true입니다.

물론 결과는 캔버스 아래에 있는 배경색(캔버스의 배경색, 캔버스 컨테이너의 배경색, 페이지의 배경색, 캔버스가 z-index > 0일 경우 캔버스 뒤에 있는 항목, 등등...)으로 페이지 위에 합성되는데, 말인즉슨 색상 CSS가 웹 페이지의 해당 영역을 정의합니다.

알파 문제가 있는지 찾는 정말 좋은 방법은 캔버스의 배경을 빨강같은 밝은 색상으로 설정하는 겁니다. 무슨 일이 일어나고 있는지 바로 보실 수 있습니다.

<canvas style="background: red;"><canvas>

또한 알파 문제를 숨겨주는 검은색으로 설정할 수도 있습니다.

#2) 백버퍼에서 알파를 원하지 않는다고 WebGL에 알림

gl = canvas.getContext("webgl", { alpha: false }};

백버퍼는 RGB만 있기 때문에 이는 좀 더 OpenGL처럼 작동하게 만들어 줍니다. 좋은 브라우저는 알파가 없다는 것을 알 수 있고 WebGL이 합성하는 방식을 최적화할 수 있기 때문에 아마 이게 최고의 선택일 겁니다. 물론 이는 실제로 백버퍼에 알파가 없다는 걸 의미하므로 어떤 목적으로 백버퍼에서 알파를 사용하고 있다면 동작하지 않을 수 있습니다. 제가 아는 소수의 앱만이 백버퍼에서 알파를 사용합니다. 주장하건대 저는 이게 기본값이었어야 한다고 생각합니다.

#3) 렌더링의 마지막에 알파 지우기

..
renderScene();
..
// 백버퍼의 알파를 1.0으로 설정
gl.clearColor(1, 1, 1, 1);
gl.colorMask(false, false, false, true);
gl.clear(gl.COLOR_BUFFER_BIT);

지우기는 일반적으로 매우 빠르지만 대부분의 하드웨어에는 특별한 경우가 있습니다. 대부분의 데모에서 이를 수행했습니다. 제가 똑똑했다면 위의 #2 방법으로 바꿨을 겁니다. 이 글을 올린 후에 바로 작업할 것 같습니다. 대부분의 WebGL 라이브러리는 이 방법을 기본값으로 해야할 것처럼 보입니다. 실제로 합성 효과에 알파를 사용하는 소수의 개발들은 이를 요청할 수 있습니다. 나머지는 최고의 성능과 최소한의 놀라움을 얻을 겁니다.

#4) 알파를 한 번 지우고 더 이상 렌더링하지 않기

// 초기화할 때, 백버퍼 지우기
gl.clearColor(1,1,1,1);
gl.clear(gl.COLOR_BUFFER_BIT);

// 알파 렌더링 끄기
gl.colorMask(true, true, true, false);

물론 자신만의 프레임 버퍼로 렌더링한다면 알파 렌더링을 다시 켰다가 캔버스 렌더링으로 전환할 때 다시 꺼야할 수 있습니다.

#5) 이미지 처리

알파가 있는 이미지를 WebGL로 로딩하는 경우 저의 기본값입니다. WebGL은 미리 곱하지 않은 색상 값인 PNG 파일 그대로의 값을 제공할 겁니다. pre-multiplied는 손실인 반면 이건 무손실이기 때문에 일반적으로 OpenGL 프로그램에 사용됩니다.

1, 0.5, 0.5, 0  // RGBA

r, g, b가 0이 되는 걸 의미하는 a = 0이기 때문에 un-premultiplied는 가능한 값인 반면 pre-multiplied는 불가능한 값입니다.

원한다면 WebGL이 알파를 미리 곱하도록 할 수 있습니다. 이렇게 UNPACK_PREMULTIPLY_ALPHA_WEBGL를 true로 설정하여 이를 수행하는데

gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);

기본값은 un-premultiplied 입니다.

대부분의 Canvas 2D 구현은 pre-multiplied 알파로 작동한다는 점에 유의하세요. 이는 WebGL로 전송하고 UNPACK_PREMULTIPLY_ALPHA_WEBGL이 false일 때 WebGL이 다시 un-premultipiled로 전환할 것임을 의미합니다.

#6) pre-multiplied 알파와 함께 작동하는 혼합 방정식 사용

제가 작성하거나 작업한 거의 모든 OpenGL 앱들이 사용 중인데

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

non-premultiplied 알파 텍스처에서 작동합니다.

실제로 pre-multiplied 알파 텍스처로 작업하려면,

gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

이게 제가 알고 있는 방법입니다. 더 많은 걸 알고 있다면 아래에 알려주세요.

이슈/버그는? Github에 이슈를 만들어주세요.
코드 블록은 <pre><code>여기에 코드 입력</code></pre>를 사용해주세요
comments powered by Disqus