WebGL 기초( 2 - 삼각형 그리기 준비 )

WebGL 기초( 2 - 삼각형 그리기 준비 )

이번에는 코드를 보며 아래와 같이 삼각형을 만들어보기로 합니다.

1 - 셰이더 작성

먼저 앞장에서 작업한 버텍스 셰이더와 프래그먼트 셰이더를 작성합니다.

2 - WebGL 렌더링 컨텍스트 생성하기

WebGL 렌더링 컨텍스트는 canvas로부터 얻어올 수 있습니다.

canvas는 ‘2D’와 ‘webgl’이라는 두개의 캔버스 context가 있습니다.
canvas는 둘 중 어떤 컨텍스트를 사용하든 상관하지 않지만
원하는 API를 노출하는 적절한 객체를 제공해주려면
canvas에게 명시적으로 알려줘야 합니다.

context를 가져오려면 canvas의 getContext 메소드를 호출하면됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<div class='wrap'>
<canvas id="my-canvas" width="400" height="300">
해당 브라우저는 html5 canvas element를 지원하지 않습니다.
</canvas>
</div>
<script>
var gl = null,
canvas = null;
canvas = document.getElementById('my-canvas');
try{
gl = canvas.getContext('webgl') ||
canvas.getContext('experimental-webgl');
} catch (e){
}
</script>
</body>

*getContext
-첫번째 파라미터 : context이름
-두번째 파라미터 : 선택인자

3 - 셰이더 컴파일 및 링크 -> 프로그램 생성

지금까지 작성한 셰이더를 GPU에서 동작하도록 단계별로 진행합니다.

1단계
정점 셰이더와 프래그먼트 셰이더의 문자열을 가져옵니다.

1
2
var vertexShaderSource = document.getElementById("2d-vertex-shader").text;
var fragmentShaderSource = document.getElementById("2d-fragment-shader").text;

2단계
셰이더 생성 및 컴파일을 합니다.

1
2
3
4
5
6
7
8
9
// 셰이더 컴파일
var vertextShader = makeShader(vertexShaderSource, gl.VERTEX_SHADER),
fragmentShader = makeShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
function makeShader(src, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
return shader;
}

3단계
2개의 셰이더를 1개의 프로그램에 연결하기

1
2
3
4
5
6
7
8
// 프로그램 생성
// 프로그램은 vertexShader,fragmentShader 두쌍을 합쳐서 프로그램이라고 합니다.
glProgram = gl.createProgram();

// 프로그램에 셰이더 첨부 및 연결
gl.attachShader(glProgram, vertexShader);
gl.attachShader(glProgram, fragmentShader);
gl.linkProgram(glProgram);

여기까지가 하나의 GLSL프로그램을 만드는 과정입니다.

4 - 셰이더에서 참조할 데이터 넣기

이제부터 WebGL API를 사용하여 앞에서 만든 GLSL프로그램에서 참조할 데이터를 넣어줄 것입니다.

앞에서 만든 GLSL프로그램에서 aVertexPosition 애트리뷰트를 사용하였는데,
이 애트리뷰트에서 소비할 데이터를 제공할 버퍼를 만들어 줍니다.

1
2
var triangleVerticeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVerticeBuffer);


bindBuffer( target, mybuffer )


WebGL은 내부에 버퍼를 여러개 생성하고 관리할 수 있습니다.
그래서 어떤 버퍼를 사용하고 있는지 일려주어야 하는데, 어떤 버퍼를 사용하고 있다고 가리키는 것을
바인드 포인트(bind point)라고 합니다.
그렇기 때문에 bindBuffer 함수를 실행하면 바인드 포인트는 triangleVerticeBuffer를 가리키게 되고,
이후에 제공되는 데이터는 이 바인드 포인트가 가리키는 버퍼에 입력되게 됩니다.

bindBuffer의 첫번째 인자로는 상수 값
ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER 이 들어가는데
ARRAY_BUFFER는 타깃 버퍼가 위치 및 색상같은 정점 어트리뷰트에 사용될때,
ELEMENT_ARRAY_BUFFER는 타깃 버퍼가 정점 인덱스를 포함할 때 사용합니다.

그후 bufferData를 통해 GPU에 데이터를 올리게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var triangleVertices = [
// 왼쪽 삼각형
-0.5, 0.5, 0.0,
0.0, 0.0, 0.0,
-0.5, -0.5, 0.0,

// 오른쪽 삼각형
0.5, 0.5, 0.0,
0.0, 0.0, 0.0,
0.5, -0.5, 0.0
];
// 공간 좌표 (x,y,z)이고 값은 캔버스 크기로부터 -1~1 까지 표현된다.
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);

WebGL은 강력한 형의 값을 요구하기 때문에
데이터를 32비트 부동 소수점 형식의 값의 배열로 만들기 위해 Float32Array를 사용해 줍니다.
이때 앞에서 정의 한 triangleVerticeBuffer를 인자로 넘기지 않는 이유는
이미 바인드 포인트가 triangleVerticeBuffer를 가리키고 있기때문 입니다.


bufferData( target, data, usage )


bufferData 호출에서 세번째 파라미터 usage(용법)는 3가지가 존재하는데,
최적화와 관련된 상수라고 합니다.(파악안됨..)

  • STATIC_DRAW
    데이터를 한번만 설정하고 애플리케이션이 여러번 사용하는 동안 다시 변경하지 않습니다.

  • DYNAMIC_DRAW
    애플리케이션에서 데이터를 여러번 사용하지만 매번 내용을 재설정합니다.

  • STREAM_DRAW
    데이터를 변경하지 않습니다.

5 - 애트리뷰트 참고하기

마지막으로 앞서 만든 GLSL 프로그램에서 애트리뷰트로 aVertexPosition이 사용되는데,
WebGL API를 통하여 프로그램에 정의된 애트리뷰트의 위치를 얻어옵니다.

1
var positionAttributeLocation = gl.getAttribLocation(program, "aVertexPosition");

getAttribLocation()함수를 이용해 프로그램의 a_position 애트리뷰트의 위치를 참조했습니다.

셰이더 컴파일 및 링크, 데이터를 버퍼에 제공, 애트리뷰트의 위치를 참조까지 완료하면
삼각형을 그리기 위한 준비가 완료됩니다.

이 과정은 초기화 과정으로 전체 코드 동작중 한번만 실행하도록 해야한다고 합니다.

다음 장에서는 WebGL 기초 마지막으로
삼각형을 그려보도록 하겠습니다.


Comments: