Notice
Recent Posts
Recent Comments
Link
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Archives
Today
Total
관리 메뉴

codingfarm

1. WebGL2 기본 API 정리 본문

카테고리 없음

1. WebGL2 기본 API 정리

scarecrow1992 2026. 4. 7. 21:46

https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html

https://webgl2fundamentals.org/webgl/lessons/resources/webgl-state-diagram.html

 

WebGL2 초기화 및 렌더링 사이클을 위한 기본적인 API 사용방법 및 자주 사용되는 패턴들을 내 나름대로 정리해보았다.

웹/게임을 가리지않고 개발이란 결국 데이터를 읽고, 쓰고, 만들고, 지우는 과정의 반복이라 생각한다.

그렇기에 Webgl2의 주요 리소스들을 CRUD 관점에 맞추어 API를 정리하였다.

  program shader vertex array buffer texture
생성 createProgram createShader createVertexArray createBuffer createTexture
바인 linkProgram attachShader
detachShader
bindVertexArray bindBuffer bindTexture
작업 uniform1i
uniform3fv
uniformMatrix4fv
uniformMatrix4fv
shaderSource
compileShader
vertexAttribPointer bufferData texImage2D
texParameteri
generateMipmap
activeTexture
참조 getAttribLocation
getUniformLocation
       
제거   deleteShader      

gpu 자원과 cpu 자원을 별도의 함수로 순차적으로 호출하고, 작업을 진행하는 방식이 다소 비직관적이었다.

가령 buffer와 attribute를 한데 묶어서 호출하는 방식이 아니라, 전역 상태에 원하는 리소스를 먼저 바인딩하고(bindBuffer), 이에 대한 작업 함수를 호출하는 방식(bufferData)이라 다소 비직관적이게 느껴젔다.

하지만 global 하게 관리되는 webgl 상태가 존재하고, 해당 상태에 설정된 대상에 대해 작업을 수행한다는 발상으로 접근하니 어느정도 이해가 갔다.

결정적으로 두번째 링크에서 매 코드 라인마다 webgl의 상태를 다이어그램으로 가시화해주었기 때문에 코드를 이해하기 한결 간편했다.

 

1. Shader와 Program

정점의 위치를 계산하기 위한 vertex shader와 각 픽셀의 색상을 결정하는 fragment shader의 쌍으로 구성된다.

vertex는 각 정점에 대해 수행되며, 이들로부터 보간된 데이터가 fragment shader로 전달된다.

vertex shader는 GPU에 존재하는 데이터만 읽을 수 있으며,

데이터를 보내는 방법은 아래와 같다.

1) Attribute, Buffer, Vertex Array

vertex shader에서 in 예약어로 정의되는 변수에 대응되는 데이터이다.

각각의 vertex 마다 할당 되어야 하는 데이터들이 전달되며,  vertex 자체의 위치, 법선, uv 좌표, 색상 등의 정보를 전달한다.

  • Buffer: GPU에 올라가는 바이너리 데이터 배열이다. 일반적으로 각 정점에 대한 실제 정보들이 전달되며 주로 위치, 법선, uv 좌표, 색상 등이 전달된다.
  • Attribute: 버퍼에서 데이터를 읽어 오기 위한 일종의 명세이다. 타입, 위치, 이동수치 등의 데이터가 attribute에 보관된다.
  • VAO(Vertex Array Object) : 각각의 attribute가 사용할 버퍼가 무엇인지, 버퍼로부터 데이터를 어떻게 추출할지, location 정보가 어떻게 되는지 등, attribute의 상태가 저장된다.

버퍼는 랜덤 접근이 불가능하며, attribute에서 지정한 크기만큼 vertex shader에 전달된다.

 

사실 webgl 코드에서는 attribute는 별도의 create api가 주어지지 않기에 그 실체가 모호한 기분이며, 이름 그대로 속성(Attribute)처럼 다가온다.

실제로 program에서 attribute info는 gl.linkProgram 호출시점에 shader 코드의 상태에 따라 결정되고, 개발자는 해당 info에 맞추어 shader에 전달하기 위한 데이터를 buffer에 담고, 해석 정보를 vertex array에 구현하면 될 뿐이다.

attribute에 데이터를 전달하는 스켈레톤 코드는 아래와 같다.

const positionLoc = gl.getAttribLocation(prg, 'position');

// vertex positions for a cube
const cubeVertexPositions = new Float32Array([
    1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1,
]);


const cubeVertexArray = gl.createVertexArray();
gl.bindVertexArray(cubeVertexArray);

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubeVertexPositions, gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(
    positionLoc,  // location
    3,            // size (components per iteration)
    gl.FLOAT,     // type of to get from buffer
    false,        // normalize
    0,            // stride (bytes to advance each iteration)
    0,            // offset (bytes from start of buffer)
);

 

앞서 쉐이더 코드를 보면 position 은 vec4로 선언되었고, attribute info 도 분명 FLOAT_VEC4 타입인데, 정작 vertex array에는 size 3으로 설정되었다. 행렬 계산을 위해선, 배열로부터 translate의 영향을 받기 위해 마지막 원소가 자동으로 1로 채워져야 할것같은데, 해당 부분은 정확한 확인이 필요할것같다.

 

2) Uniform

모든 셰이더 프로그램이 동시 참조하는 전역변수이다.

가령 "각각의 vertex에 대한 좌표" 정보는 vertex마다 다른 정보이므로 attribute로 전달되어야 하지만, "모델의 transform matrix"는 모든 vertex가 동시에 참조해도 충분하므로 Uniform으로 전달하면된다.

uniform 은 데이터가 이진데이터와 비이진데이터로 크게 2가지로 나뉜다,

 

2-1) binary uniform

이진 배열의 형태로 표현 가능한 데이터. 주로 transform matrix, light intensity, light dir 등의 정보가 전달된다.

다이어그램 상으로는 program 내에 직접 보관되는것으로 보이며,

비교적 간단한 절차로 설정할 수 있다.

const modelViewLoc = gl.getUniformLocation(prg, 'modelView');
gl.uniformMatrix4fv(modelViewLoc, false, modelView);

다이어그램 상으로는 localtion이 안보이지만, getUniformLocation 함수로 봐선 실제 location 자체는 존재하는것으로 고려된다.

절차가 간단한 만큼, 매 렌더링 마다 달라질 수 있는 데이터를 전달하는데에도 적합해보인다.

(transform 데이터 등)

 

2-2) non-birary uniform (Texture)

이진 배열 형태로 표현 불가능한 데이터들이며, 주로 diffuse, ao, normal 등의 텍스처 정보들이 전달된다.

이러한 특수성 때문에 리소스 자체는 webgl에 의해 직접 관리되며, program에서는 location으로 간접 참조하는 방식으로 접근하는것으로 보인다.

그렇기에 전체적으로 아래와 같이 다소 복잡한 절차를 따른다.

  1. 텍스처 생성
  2. webgl에 bind
  3. uniform 로케이션 맵
// 1. 텍스처 생성
const checkerTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, checkerTexture);
gl.texImage2D(
    gl.TEXTURE_2D,
    0,                // mip level
    gl.LUMINANCE,     // internal format
    4,                // width
    4,                // height
    0,                // border
    gl.LUMINANCE,     // format
    gl.UNSIGNED_BYTE, // type
    new Uint8Array([  // data
      192, 128, 192, 128,
      128, 192, 128, 192,
      192, 128, 192, 128,
      128, 192, 128, 192,
    ]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

// 2. webgl 등록
const diffuseLoc = gl.getUniformLocation(prg, 'diffuse');
let texUnit = 6;
gl.activeTexture(gl.TEXTURE0 + texUnit);
gl.bindTexture(gl.TEXTURE_2D, checkerTexture);

// 3. uniform location 맵핑
gl.uniform1i(diffuseLoc, texUnit);

 

webgl2fundamentals 문서에서는 각각 uniform과 texture라는 별도의 방법으로 안내해주긴 하지만,

shader 코드상에서는 uniform으로 전달되고, 코드상에서도 간접적으로나마 참조되기 때문에 하나의 범주로 묶어 정리하였다.

 

3) varying

한마디로, vertex shader(out)에서 fragment shader(in)로 보내는 값이다.

해당 데이터는 해당 픽셀이 속한 폴리곤을 구성하는 3개의 vertex로부터 보간되어 내려보내진다.

WebGL 1.0 에서는 varying 을 사용하지만, 최신 OpenGL/ WebGL2.0 에서는 in/out 키워드로 대체되었다.

사용법은 그냥 직관적으로 shader내에서 사용하면된다.

대신 vertex/fragment 양측 쉐이더에서 동일한 이름과 형식을 사용해야한다.

// 버텍스 셰이더
varying vec3 vColor; // 프래그먼트로 전달할 변수
attribute vec3 aColor;

void main() {
    vColor = aColor; // 속성값을 varying에 할당
    gl_Position = ...;
}

// 프래그먼트 셰이더
varying vec3 vColor; // 버텍스에서 보간된 값을 받음

void main() {
    gl_FragColor = vec4(vColor, 1.0); // 보간된 색상 적용
}

 

 

 

Comments