일.canvas 2D 로 사각형 그리기
canvas 2D 로 사각형을 그리는 것은 쉽습니다. 몇 줄의 코드로 쉽게 해결됩니다:
<!-- html -->
<h5>canvas2d</h5>
<canvas id="canvas2d" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
// js
// 요소 참조 획득
var canvas2d = document.getElementById('canvas2d');
// 2D context 획득
var ctx = canvas2d.getContext('2d');
// 채우기 색 설정
ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';
// 사각형 블록 그리기
ctx.fillRect(100, 100, 200, 200);
실제 효과는 200x200px 연보라색 사각형 블록으로, 주위에 너비 100px 의 투명 링이 있습니다. 코드의 관점에서 보면, 400x400px 의 투명한 canvas 중심에 불투명도 0.75 의 200x200px 보라색 사각형 블록이 칠해진 것입니다
ctx.fillRect(100, 100, 200, 200); 에서 canvas 2D 의 좌표계는 화면 좌표계와 같으며, 좌상단이 (0, 0), x 축은 오른쪽이 양수, y 축은 아래가 양수임을 알 수 있습니다
ctx.fillStyle = 'rgba(255, 0, 255, 0.75)'; 에서 rgba() 는 CSS 와 같으며, rgb 값은 0255, a 는 01 로 불투명도를 나타냄을 알 수 있습니다
이.WebGL 로 사각형 그리기
###1.context 획득
canvas2d.getContext('2d') 와 유사하게, WebGL 도 전용 context 를 획득해야 합니다:
var webgl = document.getElementById('webgl');
var gl = webgl.getContext('webgl');
여기서 WebGL 의 context 를 관례적으로 gl 로 명명하는 것은 향후 API 호출 시 OpenGL 호출 방식과 일치하게 하기 위함입니다. 네, 그냥 보기 좋게 하려는 것입니다
###2.canvas 지우기
canvas 2D 가 제공하는 clearRect 메서드와 유사하게, WebGL 에도 지우개 같은 것이 있으며, 더욱 강력하여 지운 후의 색상을 지정할 수 있습니다:
// 지울 canvas 색상 지정
// 파라미터는 rgba, 범위 0.0~1.0
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// canvas 지우기
// gl.COLOR_BUFFER_BIT 색상 버퍼, 기본 지우기 색 rgba(0.0, 0.0, 0.0, 0.0) 투명한 검은색, gl.clearColor 로 지정
// gl.DEPTH_BUFFER_BIT 깊이 버퍼, 기본 깊이 1.0, gl.clearDepth 로 지정
// gl.STENCIL_BUFFER_BIT 스텐실 버퍼, 기본값 0, gl.clearStencil() 로 지정
gl.clear(gl.COLOR_BUFFER_BIT);
이 예에서는 canvas 를 지우는 것이 필수는 아니지만, 이 방법을 반드시 사용할 수 있어야 합니다. 그렇지 않으면 곤란해집니다. canvas 2D 에서 검은색 배경을 설정하려면 이렇게 하기 때문입니다:
// 검은색 배경
ctx.fillStyle = 'rgba(0, 0, 0, 1)';
ctx.fillRect(0, 0, canvas2d.width, canvas2d.height);
같은思路로, canvas 전체를 덮는 검은색 블록을 그리는 것은 WebGL 에서도 물론 가능하지만, 매우 번거롭습니다
###3.사각형 그리기
사각형을 그리기 위해 먼저 8 가지 일을 해야 합니다:
- 셰이더 소스 프로그램 작성
셰이더 언어 (GLSL ES) 를 사용하여 셰이더 소스 프로그램을 작성한 후 문자열 형태로 WebGL 시스템 내부에 전달하여 컴파일 실행합니다:
// 0.셰이더 소스 프로그램
// 정점 셰이더 소스 프로그램
var vsSrc = 'void main() {' +
'gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' + // 좌표 설정
'gl_PointSize = 200.0;' + // 크기 설정
'}';
// 프래그먼트 셰이더 소스 프로그램
var fsSrc = 'void main() {' +
'gl_FragColor = vec4(1.0, 0.0, 1.0, 0.75);' + // 색상 설정
'}';
GLSL ES 의 문법은 C 언어와 비슷합니다. 구체적인 문법 규칙은 이후 노트에서 설명하겠습니다
- 셰이더 객체 생성
말할 것 없습니다. 게임 규칙입니다
// 1.셰이더 객체 생성
var vs = gl.createShader(gl.VERTEX_SHADER);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
// 생성 결과 확인
if (vs === null) {
log('gl.createShader(gl.VERTEX_SHADER) failed');
}
if (fs === null) {
log('gl.createShader(gl.FRAGMENT_SHADER) failed');
}
3. 소스 프로그램 채우기
셰이더 객체가 있으면 셰이더 소스 프로그램을 넣을 수 있습니다
// 2.소스 프로그램 채우기
gl.shaderSource(vs, vsSrc);
gl.shaderSource(fs, fsSrc);
4. 컴파일
소스 코드가 있으면 빨리 컴파일하여 에러가 나는지 확인합니다
// 3.컴파일
gl.compileShader(vs);
gl.compileShader(fs);
// 컴파일 에러 확인
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
log('gl.compileShader(vs) failed');
log(gl.getShaderInfoLog(vs)); // 에러 정보 출력
}
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
log('gl.compileShader(fs) failed');
log(gl.getShaderInfoLog(fs)); // 에러 정보 출력
}
5. 프로그램 객체 생성
셰이더 객체 외에도 프로그램 객체가 필요합니다. js 와 WebGL 내부 간 통신은 주로 이 프로그램 객체를 통해 이루어지므로, 먼저 하나 만듭니다
// 4.프로그램 객체 생성
var prog = gl.createProgram();
// 생성 결과 확인
if (prog === null) {
log('gl.createProgram() failed');
}
주의: 위 4 단계는 모두 정점 XX 와 프래그먼트 XX 가 하나씩이지만, 이 단계에서는 prog 객체는 1 개만 필요합니다
- 프로그램 객체에 셰이더 할당
각 prog 에는 2 개의 셰이더 (1 개의 정점 셰이더, 1 개의 프래그먼트 셰이더) 가 필요하므로, 할당 에러를 확인할 때는 2 와 비교하여 prog 에 2 개의 shader 가 바인딩되었는지 확인합니다
// 5.프로그램 객체에 셰이더 할당
gl.attachShader(prog, vs);
gl.attachShader(prog, fs);
// 할당 에러 확인
if (gl.getProgramParameter(prog, gl.ATTACHED_SHADERS) !== 2) {
log('gl.getProgramParameter(prog, gl.ATTACHED_SHADERS) failed');
}
7. 프로그램 객체 링크
C 언어 프로그램의 compile -> link -> run 과 유사합니다
// 6.프로그램 객체 링크
gl.linkProgram(prog);
// 링크 에러 확인
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
log('gl.linkProgram(prog) failed');
log(gl.getProgramInfoLog(prog));
}
8. 프로그램 객체 사용
에러 확인은 하지 않습니다. 반환 값이 없기 때문입니다
// 7.프로그램 객체 사용
gl.useProgram(prog);
이로써 사각형 하나를 그리기 위한 준비 작업이 완료되었습니다
마지막으로 무언가를 그립니다
// 사각형 그리기 (하나의 점이지만 점의 크기가 약간 큼)
gl.drawArrays(gl.POINTS, 0, 1);
삼.DEMO
위 코드를 포함한 완전한 예제는 여기를 확인하십시오: http://www.ayqy.net/temp/webgl/hoho/index.html
사.WebGL 과 canvas 2D 의 차이
###1.좌표계가 다름
WebGL 에서 canvas 의 중심은 (0, 0), x 축은 오른쪽이 양수, y 축은 위가 양수, z 축은 화면에서射出하여 얼굴을 가리키는 방향이 양수 (오른손 좌표계) 입니다
###2.좌표값이 다름
WebGL 에서 전체 캔버스는 Rect(-1.0, 1.0, 2, 2) 입니다. 즉 canvas 좌상단 좌표는 (-1.0, 1.0), 우상단 좌표는 (1.0, 1.0), 캔버스 크기는 2x2 입니다. canvas 자체가 400x400px 라면, WebGL 에서 좌표값의 단위는 200px 입니다
주의: 좌표값이 아닌 속성, 예를 들어 위 셰이더 소스 프로그램 중의 gl_PointSize 의 경우, 그 단위는 여전히 px 입니다
###3.rgb 값이 다름
프래그먼트 셰이더에는 색상이 사용되었습니다. vec4(r, g, b, a) 로, CSS 의 rgba() 와 달리, WebGL 에서 rgb 값의 범위는 0.0~1.0 이며, 반드시 소수 형태여야 합니다. vec4 생성자는 float 형 파라미터만 받아들이며, int 는암묵적으로 float 로 변환되지 않습니다
###4.색상 중첩 규칙이 다름
DEMO 를 실행하면 canvas 2D 와 Web GL 로 그린 보라색 사각형의 색상이 다름을 알 수 있습니다. canvas 2D 에서는 먼저 검은색 배경을 그린 후 보라색 사각형을 그렸습니다. 보라색 사각형에는 0.25 의 투명도가 있으며, 최종적으로 표시되는 색상은 보라색과 검은색의 중첩입니다.
반면 WebGL 에서는 보라색 사각형의 색상이 검은색과 중첩되지 않았습니다 (body 배경색은 우리가 보라색 사각형에 지정한 색상으로, WebGL 에서 보라 - 검은 중첩이 발생하지 않았음을 분명히 볼 수 있습니다). 보라색 사각형 뒤쪽 (z 좌표가 -0.1) 에 검은색 사각형을 하나 더 그려보았지만, 색상은 여전히 중첩되지 않았습니다. 이는특별히 주의해야 합니다
오.정리
API 사용 단계로 보면 WebGL 은 이토록 번거롭습니다. 사각형 하나를 그리는 데 이토록 많은 코드를 작성해야 합니다. 실제로 우리는 하나의 점 (약간 큰 점) 만 그렸을 뿐이며, 사각형을 그리려면 더욱 번거롭고, 4 개의 정점을 사용하여 2 개의 삼각형 조각을 결정한 후 각각 색을 채워야 합니다
정점 셰이더, 프래그먼트 셰이더란 무엇인가? 어떤 역할이 있는가?조금 더 복잡한 예로 설명해야 합니다. 이후 노트에서 설명하겠습니다
참고 자료
- 『WebGL 프로그래밍 가이드》
아직 댓글이 없습니다