본문 바로가기

WebGL

WebGL Fundamentals > Fundamentals : WebGL 초기화

https://webglfundamentals.org/webgl/lessons/webgl-fundamentals.html

 

WebGL Fundamentals

Your first WebGL lesson starting with the fundamentals

webglfundamentals.org

https://github.com/Myoungmin/WebGL_Fundamentals

 

GitHub - Myoungmin/WebGL_Fundamentals: WebGL 학습 프로젝트

WebGL 학습 프로젝트. Contribute to Myoungmin/WebGL_Fundamentals development by creating an account on GitHub.

github.com

 

 

 

 

 

WebGL로 원하는 것을 그리기 위해서는 여러 상태를 설정하고 GPU에서 셰이더를 실행하는 gl.drawArrays나 gl.drawElements를 호출해서 함수 쌍을 실행해야 한다.

모든 데이터는 GPU Shader에 제공되어야 하고, Shader가 데이터를 받을 수 있는 방법에는 4가지가 있다.

1. Attributes and Buffers

BuffersGPU에 업로드하는 바이너리 데이터 배열이다.

 

AttributesBuffers에서 데이터를 가져오고 vertex shader에 제공하는 방법을 지정하는데 사용한다.

어떤 타입의 데이터를 가져올지, 오프셋이 어느 위치에서 시작되는지, 다음 위치로 갈 때 몇 바이트를 이동시킬지 Attributes를 통해 알려준다.

 

Buffers는 랜덤하게 접근할 수 없다.

대신에 vertex shader가 지정한 횟수만큼 실행된다. 

실행될 때마다 지정된 buffer에서 다음 값을 가져와 attribute에 할당 한다.

2. Uniforms

Uniforms은 shader program을 실행하기 전 설정하는 사실상 전역 변수.

3. Textures

Textures는 shader program에서 랜덤하게 접근할 수 있는 데이터 배열이다.

Textures에 넣는 대부분은 이미지 데이터이지만, 색상 이외의 것도 쉽게 담을 수 있다.

4. Varyings

Varyingsvertex shader가 fragment shader에 데이터를 전달하는 방법.

점, 선, 삼각형 등 렌더링되는 것에 따라 vertex shader에 의해 설정된 Varyings의 값은 fragment shader를 실행하는 동안 보간된다.

 

 

 

 

WebGL 초기화

WebGL은 클립 공간의 좌표와 색상, 오직 2가지만을 다룬다.

프로그래머로서 WebGL을 사용하는 프로그래머의 역할은 이 2가지를 작성하는 것이다. 

 

이를 위해 2개의 "shader"를 제공해야 한다. 

클립 공간 좌표를 제공하는 Vertex shader

색상을 제공하는 Fragment shader이다.

 

 

1. shader를 컴파일해서 GPU에 할당해야 하는데 먼저 문자열로 가져와야 한다. 

일반적으로 자바스크립트에서 문자열을 만드는 어떤 방법으로도 GLSL 문자열을 만들 수 있다. 

문자열을 연결할 수도, 

AJAX를 이용해 다운로드할 수도, 

여러 줄의 템플릿 문자열을 사용할 수도 있다. 

예제에서는 자바스크립트 타입이 아닌 스크립트 태그 안에 넣고 있다.

 

<script id="vertex-shader-2d" type="notjs">
 
  // attribute는 buffer로부터 데이터를 받는다.
  attribute vec4 a_position;
 
  // 모든 shader는 main함수를 갖는다.
  void main() {
    // gl_Position는 vertex shader를 세팅하는 특수 변수
    gl_Position = a_position;
  }
 
</script>
 
<script id="fragment-shader-2d" type="notjs">
 
  // fragment shaders 는 default precision이 없어 하나를 골라야한다.
  // mediump is a good default
  precision mediump float;
 
  void main() {
    // gl_FragColor는 fragment shader를 세팅하는 특수 변수
    gl_FragColor = vec4(1, 0, 0.5, 1); // reddish-purple색이 반환되는 vect4
  }
 
</script>

 

사실 대부분의 3D 엔진은 다양한 종류의 템플릿, 문자열 연결 등을 사용하여 즉시 GLSL 셰이더를 생성한다.

이 예제들은 런타임에 GLSL을 생성해야 할 만큼 복잡하지 않아 Static하게 생성하고 있다.

 

 

2. 셰이더를 만들고, GLSL을 업로드한 다음, 셰이더를 컴파일하는 함수가 필요하다.

function createShader(gl, type, source) {
  var shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
 
  var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (success) {
    return shader;
  }
 
  console.log(gl.getShaderInfoLog(shader));
  gl.deleteShader(shader);
}

 

 

3. vertex shader, fragment shader를 생성한다.

var vertexShaderSource = document.querySelector("#vertex-shader-2d").text;
var fragmentShaderSource = document.querySelector("#fragment-shader-2d").text;
 
var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

 

 

4. 두 shader를 program으로 연결해야 한다.

//prgram에 shader 연결하는 함수
function createProgram(gl, vertexShader, fragmentShader) {
  var program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
 
  var success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (success) {
    return program;
  }
 
  console.log(gl.getProgramInfoLog(program));
  gl.deleteProgram(program);
}



//함수 호출하는 부분
var program = createProgram(gl, vertexShader, fragmentShader);

 

 

5. GPU에 GLSL 프로그램을 만들었으니 데이터를 제공한다.

WebGL의 주요 API는 GLSL 프로그램에 데이터를 제공하기 위한 상태 설정에 관한 것이다.

1) 생성된 program의 attribute 위치를 찾는다.

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

 

속성 위치(그리고 유니폼 위치)를 찾는 것은 렌더링할 때가 아니라 초기화하는 동안 해야 한다.

 

2) attribute는 buffer에서 데이터를 가져오기 때문에 buffer를 생성한다.

var positionBuffer = gl.createBuffer();

 

3) 생성한 buffer를 바인드 포인트를 통해 리소스를 참조한다.

gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

 

4) 바인드 포인트를 통해 해당 buffer를 참조해서 데이터를 넣을 수 있다.

리소르를 바인드 포인트에 바인딩하면 모든 함수가 바인드 포인트를 통해 리소스를 참조한다.

 

//자바스크립트 배열인 positions
// 2D 포인트 3개
var positions = [
    0, 0,
    0, 0.5,
  0.7, 0,
];

//gl.bufferData는 데이터를 GPU의 positionBuffer로 복사한다. 
gl.bufferData(
  gl.ARRAY_BUFFER,
//자바스크립트와 다르게 WebGL은 강력한 타입을 가지는 데이터가 필요하므로, 새로운 32비트 부동 소수점 배열을 생성
  new Float32Array(positions),
  gl.STATIC_DRAW
);

 

위에서 ARRAY_BUFFER 바인드 포인트에 할당했기 때문에 위치 버퍼를 사용하고 있다.

 

마지막 매개변수 gl.STATIC_DRAW는 데이터를 어떻게 사용할 것인지 WebGL에 알려준다.

WebGL은 특정 항목들을 최적화하기 위해 해당 힌트를 사용할 수 있는데 gl.STATIC_DRAW는 이 데이터가 많이 바뀌지 않을 것 같다고 WebGL에 알려준다.

 

 

 

 

지금까지 작성한 것은 초기화 코드이다.

여기까지 코드는 페이지를 로드할 때 한 번 실행된다.

 

 

 

 

 

 

 

https://myoungmin.github.io/WebGL_Fundamentals/

 

WebGL_Fundamentals

 

myoungmin.github.io